am 8ecc24b7: (-s ours) resolved conflicts for merge of d3cb3af5 to gingerbread-plus-aosp

* commit '8ecc24b7732428f2424b954d95cd9377fbdf80e3':
  Blacklist two additional DigiNotar intermediate CAs
diff --git a/Android.mk b/Android.mk
index d67dd89..9d162fb 100644
--- a/Android.mk
+++ b/Android.mk
@@ -24,6 +24,7 @@
 LOCAL_JAVACFLAGS := -encoding UTF-8
 LOCAL_JAVA_LIBRARIES := core
 LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
 include $(BUILD_JAVA_LIBRARY)
 
 # This is used to generate a list of what is unused so it can be removed when bouncycastle is updated.
@@ -76,5 +77,6 @@
     LOCAL_NO_STANDARD_LIBRARIES := true
     LOCAL_BUILD_HOST_DEX := true
     LOCAL_MODULE_TAGS := optional
+    LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
     include $(BUILD_HOST_JAVA_LIBRARY)
 endif
diff --git a/bouncycastle.config b/bouncycastle.config
index 42ca610..d615ad2 100644
--- a/bouncycastle.config
+++ b/bouncycastle.config
@@ -13,7 +13,6 @@
 org/bouncycastle/asn1/mozilla \
 org/bouncycastle/asn1/ntt \
 org/bouncycastle/asn1/ocsp \
-org/bouncycastle/asn1/sec \
 org/bouncycastle/asn1/smime \
 org/bouncycastle/asn1/test \
 org/bouncycastle/asn1/tsp \
@@ -30,10 +29,8 @@
 org/bouncycastle/crypto/tls/ \
 org/bouncycastle/i18n/ \
 org/bouncycastle/jce/examples \
-org/bouncycastle/jce/provider/asymmetric/ \
 org/bouncycastle/jce/provider/test \
 org/bouncycastle/mail \
-org/bouncycastle/math \
 org/bouncycastle/mozilla \
 org/bouncycastle/ocsp \
 org/bouncycastle/openpgp \
@@ -114,7 +111,6 @@
 org/bouncycastle/asn1/misc/CAST5CBCParameters.java \
 org/bouncycastle/asn1/misc/IDEACBCPar.java \
 org/bouncycastle/asn1/misc/package.html \
-org/bouncycastle/asn1/nist/NISTNamedCurves.java \
 org/bouncycastle/asn1/nist/package.html \
 org/bouncycastle/asn1/oiw/ElGamalParameter.java \
 org/bouncycastle/asn1/oiw/package.html \
@@ -123,6 +119,7 @@
 org/bouncycastle/asn1/pkcs/RC2CBCParameter.java \
 org/bouncycastle/asn1/pkcs/SignerInfo.java \
 org/bouncycastle/asn1/pkcs/package.html \
+org/bouncycastle/asn1/sec/package.html \
 org/bouncycastle/asn1/teletrust/TeleTrusTNamedCurves.java \
 org/bouncycastle/asn1/teletrust/package.html \
 org/bouncycastle/asn1/util/DERDump.java \
@@ -152,20 +149,10 @@
 org/bouncycastle/asn1/x509/package.html \
 org/bouncycastle/asn1/x9/KeySpecificInfo.java \
 org/bouncycastle/asn1/x9/OtherInfo.java \
-org/bouncycastle/asn1/x9/X962NamedCurves.java \
-org/bouncycastle/asn1/x9/X962Parameters.java \
-org/bouncycastle/asn1/x9/X9Curve.java \
-org/bouncycastle/asn1/x9/X9ECParameters.java \
-org/bouncycastle/asn1/x9/X9ECParametersHolder.java \
-org/bouncycastle/asn1/x9/X9ECPoint.java \
-org/bouncycastle/asn1/x9/X9FieldElement.java \
-org/bouncycastle/asn1/x9/X9FieldID.java \
-org/bouncycastle/asn1/x9/X9IntegerConverter.java \
 org/bouncycastle/asn1/x9/package.html \
 org/bouncycastle/crypto/BufferedAsymmetricBlockCipher.java \
 org/bouncycastle/crypto/MaxBytesExceededException.java \
 org/bouncycastle/crypto/agreement/DHAgreement.java \
-org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java \
 org/bouncycastle/crypto/agreement/ECDHCBasicAgreement.java \
 org/bouncycastle/crypto/agreement/ECMQVBasicAgreement.java \
 org/bouncycastle/crypto/agreement/package.html \
@@ -220,7 +207,6 @@
 org/bouncycastle/crypto/engines/package.html \
 org/bouncycastle/crypto/generators/BaseKDFBytesGenerator.java \
 org/bouncycastle/crypto/generators/DHKeyPairGenerator.java \
-org/bouncycastle/crypto/generators/ECKeyPairGenerator.java \
 org/bouncycastle/crypto/generators/ElGamalKeyPairGenerator.java \
 org/bouncycastle/crypto/generators/ElGamalParametersGenerator.java \
 org/bouncycastle/crypto/generators/GOST3410KeyPairGenerator.java \
@@ -250,11 +236,7 @@
 org/bouncycastle/crypto/package.html \
 org/bouncycastle/crypto/paddings/package.html \
 org/bouncycastle/crypto/params/CCMParameters.java \
-org/bouncycastle/crypto/params/ECDomainParameters.java \
-org/bouncycastle/crypto/params/ECKeyGenerationParameters.java \
-org/bouncycastle/crypto/params/ECKeyParameters.java \
-org/bouncycastle/crypto/params/ECPrivateKeyParameters.java \
-org/bouncycastle/crypto/params/ECPublicKeyParameters.java \
+org/bouncycastle/math/ec/test \
 org/bouncycastle/crypto/params/ElGamalKeyGenerationParameters.java \
 org/bouncycastle/crypto/params/ElGamalKeyParameters.java \
 org/bouncycastle/crypto/params/ElGamalParameters.java \
@@ -282,7 +264,6 @@
 org/bouncycastle/crypto/params/RSABlindingParameters.java \
 org/bouncycastle/crypto/params/package.html \
 org/bouncycastle/crypto/signers/DSADigestSigner.java \
-org/bouncycastle/crypto/signers/ECDSASigner.java \
 org/bouncycastle/crypto/signers/ECGOST3410Signer.java \
 org/bouncycastle/crypto/signers/ECNRSigner.java \
 org/bouncycastle/crypto/signers/GOST3410Signer.java \
@@ -305,10 +286,6 @@
 org/bouncycastle/jce/X509V3CertificateGenerator.java \
 org/bouncycastle/jce/exception/ExtCertificateEncodingException.java \
 org/bouncycastle/jce/exception/ExtIOException.java \
-org/bouncycastle/jce/interfaces/ECKey.java \
-org/bouncycastle/jce/interfaces/ECPointEncoder.java \
-org/bouncycastle/jce/interfaces/ECPrivateKey.java \
-org/bouncycastle/jce/interfaces/ECPublicKey.java \
 org/bouncycastle/jce/interfaces/ElGamalKey.java \
 org/bouncycastle/jce/interfaces/ElGamalPrivateKey.java \
 org/bouncycastle/jce/interfaces/ElGamalPublicKey.java \
@@ -324,12 +301,8 @@
 org/bouncycastle/jce/provider/BrokenJCEBlockCipher.java \
 org/bouncycastle/jce/provider/BrokenKDF2BytesGenerator.java \
 org/bouncycastle/jce/provider/BrokenPBE.java \
-org/bouncycastle/jce/provider/DSABase.java \
-org/bouncycastle/jce/provider/DSAEncoder.java \
 org/bouncycastle/jce/provider/ElGamalUtil.java \
 org/bouncycastle/jce/provider/GOST3410Util.java \
-org/bouncycastle/jce/provider/JCEECPrivateKey.java \
-org/bouncycastle/jce/provider/JCEECPublicKey.java \
 org/bouncycastle/jce/provider/JCEElGamalCipher.java \
 org/bouncycastle/jce/provider/JCEElGamalPrivateKey.java \
 org/bouncycastle/jce/provider/JCEElGamalPublicKey.java \
@@ -371,12 +344,6 @@
 org/bouncycastle/jce/provider/symmetric/NoekeonMappings.java \
 org/bouncycastle/jce/provider/symmetric/SEED.java \
 org/bouncycastle/jce/provider/symmetric/SEEDMappings.java \
-org/bouncycastle/jce/spec/ECKeySpec.java \
-org/bouncycastle/jce/spec/ECNamedCurveParameterSpec.java \
-org/bouncycastle/jce/spec/ECNamedCurveSpec.java \
-org/bouncycastle/jce/spec/ECParameterSpec.java \
-org/bouncycastle/jce/spec/ECPrivateKeySpec.java \
-org/bouncycastle/jce/spec/ECPublicKeySpec.java \
 org/bouncycastle/jce/spec/ElGamalGenParameterSpec.java \
 org/bouncycastle/jce/spec/ElGamalKeySpec.java \
 org/bouncycastle/jce/spec/ElGamalParameterSpec.java \
@@ -392,6 +359,12 @@
 org/bouncycastle/jce/spec/MQVPrivateKeySpec.java \
 org/bouncycastle/jce/spec/MQVPublicKeySpec.java \
 org/bouncycastle/jce/spec/package.html \
+org/bouncycastle/math/ec/ReferenceMultiplier.java \
+org/bouncycastle/math/ec/WNafMultiplier.java \
+org/bouncycastle/math/ec/WNafPreCompInfo.java \
+org/bouncycastle/math/ec/WTauNafMultiplier.java \
+org/bouncycastle/math/ec/WTauNafPreCompInfo.java \
+org/bouncycastle/math/ec/package.html \
 org/bouncycastle/openssl/PEMException.java \
 org/bouncycastle/openssl/PEMReader.java \
 org/bouncycastle/openssl/PasswordException.java \
diff --git a/jarjar-rules.txt b/jarjar-rules.txt
new file mode 100644
index 0000000..2f40de1
--- /dev/null
+++ b/jarjar-rules.txt
@@ -0,0 +1 @@
+rule org.bouncycastle.** com.android.@0
diff --git a/patches/README b/patches/README
index 7b4b872..e586dd5 100644
--- a/patches/README
+++ b/patches/README
@@ -23,7 +23,6 @@
 - PKCS12BagAttributeCarrier also uses OrderedTable to cut down on memory allocation
 - X509CertificateObject.getEncoded caches its result
 - Added IndexedPKIXParameters for faster cert lookup in CertPathValidatorUtilities.findTrustAnchor
-- CertPathValidatorUtilities.findTrustAnchor fast path compares encoded certs similar to PKIXCertPathValidatorSpi
 - Added ASN1Collection for use as new parent for ASN1Collection and ASN1Set to reduce small Vector allocation
 - removed references to SecretKeyFactory.PBE/PKCS5 SecretKeyFactory.PBE/PKCS12
 - OpenSSLDigest uses NativeCrypto JNI API
@@ -31,7 +30,10 @@
 - PKCS12 KeyStore.getCreationDate tries to mimic RI behavior on null and missing aliases
 - Make PKCS12 KeyStore throw error when setting non-PrivateKey, instead of on get
 - Make PKCS12 KeyStore tolerate setting with an empty certificate chain
+- Fixed cut & paste instanceof error in EncryptedPrivateKeyInfo
+- Make BouncyCastleProvider.PROVIDER_NAME final
 - Added wrapper for SecretKeyFactory.PBKDF2WithHmacSHA1
+- Added DSA support to JDKKeyManager.engineGetKeySpec
 
 Other security changes:
 - blacklist fraudulent Comodo certificates in PKIXCertPathValidatorSpi
diff --git a/patches/android.patch b/patches/android.patch
index 6a83259..3ad2f08 100644
--- a/patches/android.patch
+++ b/patches/android.patch
@@ -1,6 +1,6 @@
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/ASN1Collection.java bcprov-jdk16-145/org/bouncycastle/asn1/ASN1Collection.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/asn1/ASN1Collection.java	1970-01-01 00:00:00.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/ASN1Collection.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/asn1/ASN1Collection.java	2011-09-03 18:25:17.000000000 +0000
 @@ -0,0 +1,298 @@
 +package org.bouncycastle.asn1;
 +
@@ -302,7 +302,7 @@
 +}
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/ASN1InputStream.java bcprov-jdk16-145/org/bouncycastle/asn1/ASN1InputStream.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/asn1/ASN1InputStream.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/ASN1InputStream.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/asn1/ASN1InputStream.java	2011-09-03 18:25:17.000000000 +0000
 @@ -348,7 +348,9 @@
              case BMP_STRING:
                  return new DERBMPString(bytes);
@@ -316,7 +316,7 @@
              case GENERALIZED_TIME:
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/ASN1Null.java bcprov-jdk16-145/org/bouncycastle/asn1/ASN1Null.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/asn1/ASN1Null.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/ASN1Null.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/asn1/ASN1Null.java	2011-09-03 18:25:17.000000000 +0000
 @@ -8,9 +8,11 @@
  public abstract class ASN1Null
      extends ASN1Object
@@ -332,7 +332,7 @@
      {
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/ASN1Sequence.java bcprov-jdk16-145/org/bouncycastle/asn1/ASN1Sequence.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/asn1/ASN1Sequence.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/ASN1Sequence.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/asn1/ASN1Sequence.java	2011-09-03 18:25:17.000000000 +0000
 @@ -2,12 +2,20 @@
  
  import java.io.IOException;
@@ -496,7 +496,7 @@
  }
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/ASN1Set.java bcprov-jdk16-145/org/bouncycastle/asn1/ASN1Set.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/asn1/ASN1Set.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/ASN1Set.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/asn1/ASN1Set.java	2011-09-03 18:25:17.000000000 +0000
 @@ -3,12 +3,20 @@
  import java.io.ByteArrayOutputStream;
  import java.io.IOException;
@@ -845,7 +845,7 @@
  }
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/DERBoolean.java bcprov-jdk16-145/org/bouncycastle/asn1/DERBoolean.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/asn1/DERBoolean.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/DERBoolean.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/asn1/DERBoolean.java	2011-09-03 18:25:17.000000000 +0000
 @@ -5,7 +5,9 @@
  public class DERBoolean
      extends ASN1Object
@@ -918,7 +918,7 @@
      {
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/DERInputStream.java bcprov-jdk16-145/org/bouncycastle/asn1/DERInputStream.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/asn1/DERInputStream.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/DERInputStream.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/asn1/DERInputStream.java	2011-09-03 18:25:17.000000000 +0000
 @@ -144,7 +144,9 @@
                  return new DERConstructedSet(v);
              }
@@ -943,7 +943,7 @@
                      {
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/DERNull.java bcprov-jdk16-145/org/bouncycastle/asn1/DERNull.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/asn1/DERNull.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/DERNull.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/asn1/DERNull.java	2011-09-03 18:25:17.000000000 +0000
 @@ -10,9 +10,13 @@
  {
      public static final DERNull INSTANCE = new DERNull();
@@ -962,7 +962,7 @@
  
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/DERObjectIdentifier.java bcprov-jdk16-145/org/bouncycastle/asn1/DERObjectIdentifier.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/asn1/DERObjectIdentifier.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/DERObjectIdentifier.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/asn1/DERObjectIdentifier.java	2011-09-03 18:25:17.000000000 +0000
 @@ -111,7 +111,13 @@
              }
          }
@@ -995,7 +995,7 @@
      public String getId()
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/DERPrintableString.java bcprov-jdk16-145/org/bouncycastle/asn1/DERPrintableString.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/asn1/DERPrintableString.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/DERPrintableString.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/asn1/DERPrintableString.java	2011-09-03 18:25:17.000000000 +0000
 @@ -9,7 +9,9 @@
      extends ASN1Object
      implements DERString
@@ -1031,7 +1031,7 @@
      public String getString()
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/OrderedTable.java bcprov-jdk16-145/org/bouncycastle/asn1/OrderedTable.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/asn1/OrderedTable.java	1970-01-01 00:00:00.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/OrderedTable.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/asn1/OrderedTable.java	2011-09-03 18:25:17.000000000 +0000
 @@ -0,0 +1,281 @@
 +package org.bouncycastle.asn1;
 +
@@ -1314,9 +1314,27 @@
 +        }
 +    }
 +}
+diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java bcprov-jdk16-145/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java
+--- bcprov-jdk16-145.orig/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java	2010-01-11 21:46:14.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java	2011-09-03 18:25:17.000000000 +0000
+@@ -37,10 +37,13 @@
+     public static EncryptedPrivateKeyInfo getInstance(
+         Object  obj)
+     {
+-        if (obj instanceof EncryptedData)
++        // BEGIN android-changed
++        //     fix copy and paste error in instanceof call
++        if (obj instanceof EncryptedPrivateKeyInfo)
+         {
+             return (EncryptedPrivateKeyInfo)obj;
+         }
++        // END android-changed
+         else if (obj instanceof ASN1Sequence)
+         { 
+             return new EncryptedPrivateKeyInfo((ASN1Sequence)obj);
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java bcprov-jdk16-145/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java	2011-09-03 18:25:17.000000000 +0000
 @@ -10,7 +10,10 @@
      //
      static final String                 pkcs_1                    = "1.2.840.113549.1.1";
@@ -1343,7 +1361,7 @@
      // md4 OBJECT IDENTIFIER ::=
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java bcprov-jdk16-145/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java	2011-09-03 18:25:17.000000000 +0000
 @@ -19,7 +19,9 @@
      private AlgorithmIdentifier maskGenAlgorithm;
      private AlgorithmIdentifier pSourceAlgorithm;
@@ -1357,7 +1375,7 @@
      
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java bcprov-jdk16-145/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java	2011-09-03 18:25:17.000000000 +0000
 @@ -20,7 +20,9 @@
      private DERInteger          saltLength;
      private DERInteger          trailerField;
@@ -1371,7 +1389,7 @@
      public final static DERInteger          DEFAULT_TRAILER_FIELD = new DERInteger(1);
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/util/ASN1Dump.java bcprov-jdk16-145/org/bouncycastle/asn1/util/ASN1Dump.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/asn1/util/ASN1Dump.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/util/ASN1Dump.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/asn1/util/ASN1Dump.java	2011-09-03 18:25:17.000000000 +0000
 @@ -90,7 +90,9 @@
              {
                  Object  o = e.nextElement();
@@ -1385,7 +1403,7 @@
                      buf.append("NULL");
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/AttCertIssuer.java bcprov-jdk16-145/org/bouncycastle/asn1/x509/AttCertIssuer.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/AttCertIssuer.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/x509/AttCertIssuer.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/asn1/x509/AttCertIssuer.java	2011-09-03 18:25:17.000000000 +0000
 @@ -45,7 +45,7 @@
          ASN1TaggedObject obj,
          boolean          explicit)
@@ -1397,7 +1415,7 @@
      /**
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/BasicConstraints.java bcprov-jdk16-145/org/bouncycastle/asn1/x509/BasicConstraints.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/BasicConstraints.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/x509/BasicConstraints.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/asn1/x509/BasicConstraints.java	2011-09-03 18:25:17.000000000 +0000
 @@ -14,7 +14,9 @@
  public class BasicConstraints
      extends ASN1Encodable
@@ -1444,7 +1462,7 @@
  
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java bcprov-jdk16-145/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java	2011-09-03 18:25:17.000000000 +0000
 @@ -96,11 +96,15 @@
          }
          if (onlyContainsUserCerts)
@@ -1483,7 +1501,7 @@
          seq = new DERSequence(vec);
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/X509Extensions.java bcprov-jdk16-145/org/bouncycastle/asn1/x509/X509Extensions.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/X509Extensions.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/x509/X509Extensions.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/asn1/x509/X509Extensions.java	2011-09-03 18:25:17.000000000 +0000
 @@ -9,6 +9,9 @@
  import org.bouncycastle.asn1.DERObject;
  import org.bouncycastle.asn1.DERObjectIdentifier;
@@ -1672,7 +1690,7 @@
              }
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/X509Name.java bcprov-jdk16-145/org/bouncycastle/asn1/x509/X509Name.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/X509Name.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/x509/X509Name.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/asn1/x509/X509Name.java	2011-09-03 18:25:17.000000000 +0000
 @@ -247,8 +247,10 @@
       */
      public static final Hashtable SymbolLookUp = DefaultLookUp;
@@ -2138,7 +2156,7 @@
                  {
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/X509NameElementList.java bcprov-jdk16-145/org/bouncycastle/asn1/x509/X509NameElementList.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/X509NameElementList.java	1970-01-01 00:00:00.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/x509/X509NameElementList.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/asn1/x509/X509NameElementList.java	2011-09-03 18:25:17.000000000 +0000
 @@ -0,0 +1,206 @@
 +package org.bouncycastle.asn1.x509;
 +
@@ -2348,7 +2366,7 @@
 +}
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/X509NameTokenizer.java bcprov-jdk16-145/org/bouncycastle/asn1/x509/X509NameTokenizer.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/X509NameTokenizer.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/x509/X509NameTokenizer.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/asn1/x509/X509NameTokenizer.java	2011-09-03 18:25:17.000000000 +0000
 @@ -58,6 +58,17 @@
                  }
                  else
@@ -2376,7 +2394,7 @@
 \ No newline at end of file
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/crypto/PBEParametersGenerator.java bcprov-jdk16-145/org/bouncycastle/crypto/PBEParametersGenerator.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/crypto/PBEParametersGenerator.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/crypto/PBEParametersGenerator.java	2011-09-06 19:05:41.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/crypto/PBEParametersGenerator.java	2011-09-03 18:25:17.000000000 +0000
 @@ -136,7 +136,8 @@
      public static byte[] PKCS12PasswordToBytes(
          char[]  password)
@@ -2396,8 +2414,8 @@
  }
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/crypto/digests/OpenSSLDigest.java bcprov-jdk16-145/org/bouncycastle/crypto/digests/OpenSSLDigest.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/crypto/digests/OpenSSLDigest.java	1970-01-01 00:00:00.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/crypto/digests/OpenSSLDigest.java	2011-09-06 19:05:42.000000000 +0000
-@@ -0,0 +1,122 @@
++++ bcprov-jdk16-145/org/bouncycastle/crypto/digests/OpenSSLDigest.java	2011-09-03 18:25:17.000000000 +0000
+@@ -0,0 +1,159 @@
 +/*
 + * Copyright (C) 2008 The Android Open Source Project
 + *
@@ -2430,12 +2448,24 @@
 +    private final String algorithm;
 +
 +    /**
-+     * Holds the OpenSSL name of the hashing algorithm, e.g. "sha1";
++     * Holds the EVP_MD for the hashing algorithm, e.g. EVP_get_digestbyname("sha1");
 +     */
-+    private final String openssl;
++    private final int evp_md;
 +
 +    /**
-+     * Holds a pointer to the native message digest context.
++     * Holds the output size of the message digest.
++     */
++    private final int size;
++
++    /**
++     * Holds the block size of the message digest.
++     */
++    private final int blockSize;
++
++    /**
++     * Holds a pointer to the native message digest context. It is
++     * lazily initialized to avoid having to reallocate on reset when
++     * its unlikely to be reused.
 +     */
 +    private int ctx;
 +
@@ -2447,25 +2477,12 @@
 +    /**
 +     * Creates a new OpenSSLMessageDigest instance for the given algorithm
 +     * name.
-+     *
-+     * @param algorithm The standard name of the algorithm, e.g. "SHA-1".
-+     * @param algorithm The name of the openssl algorithm, e.g. "sha1".
 +     */
-+    private OpenSSLDigest(String algorithm, String openssl) {
++    private OpenSSLDigest(String algorithm, int evp_md, int size, int blockSize) {
 +        this.algorithm = algorithm;
-+        this.openssl = openssl;
-+        ctx = NativeCrypto.EVP_MD_CTX_create();
-+        try {
-+            NativeCrypto.EVP_DigestInit(ctx, openssl);
-+        } catch (Exception ex) {
-+            throw new RuntimeException(ex.getMessage() + " (" + algorithm + ")");
-+        }
-+    }
-+
-+    public int doFinal(byte[] out, int outOff) {
-+        int i = NativeCrypto.EVP_DigestFinal(ctx, out, outOff);
-+        reset();
-+        return i;
++        this.evp_md = evp_md;
++        this.size = size;
++        this.blockSize = blockSize;
 +    }
 +
 +    public String getAlgorithmName() {
@@ -2473,56 +2490,94 @@
 +    }
 +
 +    public int getDigestSize() {
-+        return NativeCrypto.EVP_MD_CTX_size(ctx);
++        return size;
 +    }
 +
 +    public int getByteLength() {
-+        return NativeCrypto.EVP_MD_CTX_block_size(ctx);
++        return blockSize;
 +    }
 +
 +    public void reset() {
-+        NativeCrypto.EVP_DigestInit(ctx, openssl);
++        free();
 +    }
 +
 +    public void update(byte in) {
 +        singleByte[0] = in;
-+        NativeCrypto.EVP_DigestUpdate(ctx, singleByte, 0, 1);
++        update(singleByte, 0, 1);
 +    }
 +
 +    public void update(byte[] in, int inOff, int len) {
-+        NativeCrypto.EVP_DigestUpdate(ctx, in, inOff, len);
++        NativeCrypto.EVP_DigestUpdate(getCtx(), in, inOff, len);
++    }
++
++    public int doFinal(byte[] out, int outOff) {
++        int i = NativeCrypto.EVP_DigestFinal(getCtx(), out, outOff);
++        ctx = 0; // EVP_DigestFinal frees the context as a side effect
++        reset();
++        return i;
++    }
++
++    private int getCtx() {
++        if (ctx == 0) {
++            ctx = NativeCrypto.EVP_DigestInit(evp_md);
++        }
++        return ctx;
++    }
++
++    private void free() {
++        if (ctx != 0) {
++            NativeCrypto.EVP_MD_CTX_destroy(ctx);
++            ctx = 0;
++        }
 +    }
 +
 +    @Override
 +    protected void finalize() throws Throwable {
-+        super.finalize();
-+        NativeCrypto.EVP_MD_CTX_destroy(ctx);
-+        ctx = 0;
++        try {
++            free();
++        } finally {
++            super.finalize();
++        }
 +    }
 +
 +    public static class MD5 extends OpenSSLDigest {
-+        public MD5() { super("MD5", "md5"); }
++        private static final int EVP_MD = NativeCrypto.EVP_get_digestbyname("md5");
++        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
++        private static final int BLOCK_SIZE = NativeCrypto.EVP_MD_block_size(EVP_MD);
++        public MD5() { super("MD5", EVP_MD, SIZE, BLOCK_SIZE); }
 +    }
 +
 +    public static class SHA1 extends OpenSSLDigest {
-+        public SHA1() { super("SHA-1", "sha1"); }
++        private static final int EVP_MD = NativeCrypto.EVP_get_digestbyname("sha1");
++        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
++        private static final int BLOCK_SIZE = NativeCrypto.EVP_MD_block_size(EVP_MD);
++        public SHA1() { super("SHA-1", EVP_MD, SIZE, BLOCK_SIZE); }
 +    }
 +
 +    public static class SHA256 extends OpenSSLDigest {
-+        public SHA256() { super("SHA-256", "sha256"); }
++        private static final int EVP_MD = NativeCrypto.EVP_get_digestbyname("sha256");
++        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
++        private static final int BLOCK_SIZE = NativeCrypto.EVP_MD_block_size(EVP_MD);
++        public SHA256() { super("SHA-256", EVP_MD, SIZE, BLOCK_SIZE); }
 +    }
 +
 +    public static class SHA384 extends OpenSSLDigest {
-+        public SHA384() { super("SHA-384", "sha384"); }
++        private static final int EVP_MD = NativeCrypto.EVP_get_digestbyname("sha384");
++        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
++        private static final int BLOCK_SIZE = NativeCrypto.EVP_MD_block_size(EVP_MD);
++        public SHA384() { super("SHA-384", EVP_MD, SIZE, BLOCK_SIZE); }
 +    }
 +
 +    public static class SHA512 extends OpenSSLDigest {
-+        public SHA512() { super("SHA-512", "sha512"); }
++        private static final int EVP_MD = NativeCrypto.EVP_get_digestbyname("sha512");
++        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
++        private static final int BLOCK_SIZE = NativeCrypto.EVP_MD_block_size(EVP_MD);
++        public SHA512() { super("SHA-512", EVP_MD, SIZE, BLOCK_SIZE); }
 +    }
 +}
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/crypto/engines/RC2Engine.java bcprov-jdk16-145/org/bouncycastle/crypto/engines/RC2Engine.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/crypto/engines/RC2Engine.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/crypto/engines/RC2Engine.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/crypto/engines/RC2Engine.java	2011-09-03 18:25:17.000000000 +0000
 @@ -313,4 +313,4 @@
          out[outOff + 6] = (byte)x76;
          out[outOff + 7] = (byte)(x76 >> 8);
@@ -2532,7 +2587,7 @@
 \ No newline at end of file
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/crypto/macs/HMac.java bcprov-jdk16-145/org/bouncycastle/crypto/macs/HMac.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/crypto/macs/HMac.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/crypto/macs/HMac.java	2011-09-06 19:05:41.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/crypto/macs/HMac.java	2011-09-03 18:25:17.000000000 +0000
 @@ -32,23 +32,23 @@
      {
          blockLengths = new Hashtable();
@@ -2574,7 +2629,7 @@
      private static int getByteLength(
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/crypto/signers/RSADigestSigner.java bcprov-jdk16-145/org/bouncycastle/crypto/signers/RSADigestSigner.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/crypto/signers/RSADigestSigner.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/crypto/signers/RSADigestSigner.java	2011-09-06 19:05:41.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/crypto/signers/RSADigestSigner.java	2011-09-03 18:25:17.000000000 +0000
 @@ -46,8 +46,10 @@
          oidMap.put("SHA-384", NISTObjectIdentifiers.id_sha384);
          oidMap.put("SHA-512", NISTObjectIdentifiers.id_sha512);
@@ -2590,61 +2645,43 @@
  
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/crypto/util/PrivateKeyFactory.java bcprov-jdk16-145/org/bouncycastle/crypto/util/PrivateKeyFactory.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/crypto/util/PrivateKeyFactory.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/crypto/util/PrivateKeyFactory.java	2011-09-06 19:05:42.000000000 +0000
-@@ -7,31 +7,39 @@
- import org.bouncycastle.asn1.DERInteger;
++++ bcprov-jdk16-145/org/bouncycastle/crypto/util/PrivateKeyFactory.java	2011-09-03 18:25:17.000000000 +0000
+@@ -8,7 +8,9 @@
  import org.bouncycastle.asn1.DERObject;
  import org.bouncycastle.asn1.DERObjectIdentifier;
--import org.bouncycastle.asn1.nist.NISTNamedCurves;
+ import org.bouncycastle.asn1.nist.NISTNamedCurves;
 -import org.bouncycastle.asn1.oiw.ElGamalParameter;
 +// BEGIN android-removed
-+// import org.bouncycastle.asn1.nist.NISTNamedCurves;
 +// import org.bouncycastle.asn1.oiw.ElGamalParameter;
 +// END android-removed
  import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
  import org.bouncycastle.asn1.pkcs.DHParameter;
  import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
- import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+@@ -16,7 +18,9 @@
  import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure;
--import org.bouncycastle.asn1.sec.ECPrivateKeyStructure;
--import org.bouncycastle.asn1.sec.SECNamedCurves;
+ import org.bouncycastle.asn1.sec.ECPrivateKeyStructure;
+ import org.bouncycastle.asn1.sec.SECNamedCurves;
 -import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
 +// BEGIN android-removed
-+// import org.bouncycastle.asn1.sec.ECPrivateKeyStructure;
-+// import org.bouncycastle.asn1.sec.SECNamedCurves;
 +// import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
 +// END android-removed
  import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
  import org.bouncycastle.asn1.x509.DSAParameter;
--import org.bouncycastle.asn1.x9.X962NamedCurves;
--import org.bouncycastle.asn1.x9.X962Parameters;
--import org.bouncycastle.asn1.x9.X9ECParameters;
--import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
-+// BEGIN android-removed
-+// import org.bouncycastle.asn1.x9.X962NamedCurves;
-+// import org.bouncycastle.asn1.x9.X962Parameters;
-+// import org.bouncycastle.asn1.x9.X9ECParameters;
-+// import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
-+// END android-removed
- import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
- import org.bouncycastle.crypto.params.DHParameters;
- import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
- import org.bouncycastle.crypto.params.DSAParameters;
+ import org.bouncycastle.asn1.x9.X962NamedCurves;
+@@ -30,8 +34,10 @@
  import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
--import org.bouncycastle.crypto.params.ECDomainParameters;
--import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+ import org.bouncycastle.crypto.params.ECDomainParameters;
+ import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
 -import org.bouncycastle.crypto.params.ElGamalParameters;
 -import org.bouncycastle.crypto.params.ElGamalPrivateKeyParameters;
 +// BEGIN android-removed
-+// import org.bouncycastle.crypto.params.ECDomainParameters;
-+// import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
 +// import org.bouncycastle.crypto.params.ElGamalParameters;
 +// import org.bouncycastle.crypto.params.ElGamalPrivateKeyParameters;
 +// END android-removed
  import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
  
  import java.io.IOException;
-@@ -113,75 +121,77 @@
+@@ -113,52 +119,56 @@
  
              return new DHPrivateKeyParameters(derX.getValue(), dhParams);
          }
@@ -2655,68 +2692,6 @@
 -
 -            return new ElGamalPrivateKeyParameters(derX.getValue(), new ElGamalParameters(params.getP(), params.getG()));
 -        }
--        else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_dsa))
--        {
--            DERInteger derX = (DERInteger)keyInfo.getPrivateKey();
--            DEREncodable de = keyInfo.getAlgorithmId().getParameters();
--
--            DSAParameters parameters = null;
--            if (de != null)
--            {
--                DSAParameter params = DSAParameter.getInstance(de.getDERObject());
--                parameters = new DSAParameters(params.getP(), params.getQ(), params.getG());
--            }
--
--            return new DSAPrivateKeyParameters(derX.getValue(), parameters);
--        }
--        else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_ecPublicKey))
--        {
--            X962Parameters      params = new X962Parameters((DERObject)keyInfo.getAlgorithmId().getParameters());
--            ECDomainParameters  dParams = null;
--            
--            if (params.isNamedCurve())
--            {
--                DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters();
--                X9ECParameters      ecP = X962NamedCurves.getByOID(oid);
--
--                if (ecP == null)
--                {
--                    ecP = SECNamedCurves.getByOID(oid);
--
--                    if (ecP == null)
--                    {
--                        ecP = NISTNamedCurves.getByOID(oid);
--
--                        if (ecP == null)
--                        {
--                            ecP = TeleTrusTNamedCurves.getByOID(oid);
--                        }
--                    }
--                }
--
--                dParams = new ECDomainParameters(
--                                            ecP.getCurve(),
--                                            ecP.getG(),
--                                            ecP.getN(),
--                                            ecP.getH(),
--                                            ecP.getSeed());
--            }
--            else
--            {
--                X9ECParameters ecP = new X9ECParameters(
--                            (ASN1Sequence)params.getParameters());
--                dParams = new ECDomainParameters(
--                                            ecP.getCurve(),
--                                            ecP.getG(),
--                                            ecP.getN(),
--                                            ecP.getH(),
--                                            ecP.getSeed());
--            }
--
--            ECPrivateKeyStructure   ec = new ECPrivateKeyStructure((ASN1Sequence)keyInfo.getPrivateKey());
--
--            return new ECPrivateKeyParameters(ec.getKey(), dParams);
--        }
 +        // BEGIN android-removed
 +        // else if (algId.getObjectId().equals(OIWObjectIdentifiers.elGamalAlgorithm))
 +        // {
@@ -2725,129 +2700,110 @@
 +        //
 +        //     return new ElGamalPrivateKeyParameters(derX.getValue(), new ElGamalParameters(params.getP(), params.getG()));
 +        // }
-+        // else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_dsa))
-+        // {
-+        //     DERInteger derX = (DERInteger)keyInfo.getPrivateKey();
-+        //     DEREncodable de = keyInfo.getAlgorithmId().getParameters();
-+        //
-+        //     DSAParameters parameters = null;
-+        //     if (de != null)
-+        //     {
-+        //         DSAParameter params = DSAParameter.getInstance(de.getDERObject());
-+        //         parameters = new DSAParameters(params.getP(), params.getQ(), params.getG());
-+        //     }
-+        //
-+        //     return new DSAPrivateKeyParameters(derX.getValue(), parameters);
-+        // }
-+        // else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_ecPublicKey))
-+        // {
-+        //     X962Parameters      params = new X962Parameters((DERObject)keyInfo.getAlgorithmId().getParameters());
-+        //     ECDomainParameters  dParams = null;
-+        //
-+        //     if (params.isNamedCurve())
-+        //     {
-+        //         DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters();
-+        //         X9ECParameters      ecP = X962NamedCurves.getByOID(oid);
-+        //
-+        //         if (ecP == null)
-+        //         {
-+        //             ecP = SECNamedCurves.getByOID(oid);
-+        //
-+        //             if (ecP == null)
-+        //             {
-+        //                 ecP = NISTNamedCurves.getByOID(oid);
-+        //
-+        //                 if (ecP == null)
-+        //                 {
-+        //                     ecP = TeleTrusTNamedCurves.getByOID(oid);
-+        //                 }
-+        //             }
-+        //         }
-+        //
-+        //         dParams = new ECDomainParameters(
-+        //                                     ecP.getCurve(),
-+        //                                     ecP.getG(),
-+        //                                     ecP.getN(),
-+        //                                     ecP.getH(),
-+        //                                     ecP.getSeed());
-+        //     }
-+        //     else
-+        //     {
-+        //         X9ECParameters ecP = new X9ECParameters(
-+        //                     (ASN1Sequence)params.getParameters());
-+        //         dParams = new ECDomainParameters(
-+        //                                     ecP.getCurve(),
-+        //                                     ecP.getG(),
-+        //                                     ecP.getN(),
-+        //                                     ecP.getH(),
-+        //                                     ecP.getSeed());
-+        //     }
-+        //
-+        //     ECPrivateKeyStructure   ec = new ECPrivateKeyStructure((ASN1Sequence)keyInfo.getPrivateKey());
-+        //
-+        //     return new ECPrivateKeyParameters(ec.getKey(), dParams);
-+        // }
 +        // END android-removed
-         else
+         else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_dsa))
          {
-             throw new RuntimeException("algorithm identifier in key not recognised");
+             DERInteger derX = (DERInteger)keyInfo.getPrivateKey();
+             DEREncodable de = keyInfo.getAlgorithmId().getParameters();
+-
++        
+             DSAParameters parameters = null;
+             if (de != null)
+             {
+                 DSAParameter params = DSAParameter.getInstance(de.getDERObject());
+                 parameters = new DSAParameters(params.getP(), params.getQ(), params.getG());
+             }
+-
++        
+             return new DSAPrivateKeyParameters(derX.getValue(), parameters);
+         }
+         else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_ecPublicKey))
+         {
+             X962Parameters      params = new X962Parameters((DERObject)keyInfo.getAlgorithmId().getParameters());
+             ECDomainParameters  dParams = null;
+-            
++        
+             if (params.isNamedCurve())
+             {
+                 DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters();
+                 X9ECParameters      ecP = X962NamedCurves.getByOID(oid);
+-
++        
+                 if (ecP == null)
+                 {
+                     ecP = SECNamedCurves.getByOID(oid);
+-
++        
+                     if (ecP == null)
+                     {
+                         ecP = NISTNamedCurves.getByOID(oid);
+-
+-                        if (ecP == null)
+-                        {
+-                            ecP = TeleTrusTNamedCurves.getByOID(oid);
+-                        }
++        
++                        // BEGIN android-removed
++                        // if (ecP == null)
++                        // {
++                        //     ecP = TeleTrusTNamedCurves.getByOID(oid);
++                        // }
++                        // END android-removed
+                     }
+                 }
+-
++        
+                 dParams = new ECDomainParameters(
+                                             ecP.getCurve(),
+                                             ecP.getG(),
+@@ -177,9 +187,9 @@
+                                             ecP.getH(),
+                                             ecP.getSeed());
+             }
+-
++        
+             ECPrivateKeyStructure   ec = new ECPrivateKeyStructure((ASN1Sequence)keyInfo.getPrivateKey());
+-
++        
+             return new ECPrivateKeyParameters(ec.getKey(), dParams);
+         }
+         else
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/crypto/util/PublicKeyFactory.java bcprov-jdk16-145/org/bouncycastle/crypto/util/PublicKeyFactory.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/crypto/util/PublicKeyFactory.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/crypto/util/PublicKeyFactory.java	2011-09-06 19:05:42.000000000 +0000
-@@ -10,32 +10,40 @@
- import org.bouncycastle.asn1.DERObject;
++++ bcprov-jdk16-145/org/bouncycastle/crypto/util/PublicKeyFactory.java	2011-09-03 18:25:17.000000000 +0000
+@@ -11,12 +11,16 @@
  import org.bouncycastle.asn1.DERObjectIdentifier;
  import org.bouncycastle.asn1.DEROctetString;
--import org.bouncycastle.asn1.nist.NISTNamedCurves;
+ import org.bouncycastle.asn1.nist.NISTNamedCurves;
 -import org.bouncycastle.asn1.oiw.ElGamalParameter;
 +// BEGIN android-removed
-+// import org.bouncycastle.asn1.nist.NISTNamedCurves;
 +// import org.bouncycastle.asn1.oiw.ElGamalParameter;
 +// END android-removed
  import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
  import org.bouncycastle.asn1.pkcs.DHParameter;
  import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
--import org.bouncycastle.asn1.sec.SECNamedCurves;
+ import org.bouncycastle.asn1.sec.SECNamedCurves;
 -import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
 +// BEGIN android-removed
-+// import org.bouncycastle.asn1.sec.SECNamedCurves;
 +// import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
 +// END android-removed
  import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
  import org.bouncycastle.asn1.x509.DSAParameter;
  import org.bouncycastle.asn1.x509.RSAPublicKeyStructure;
- import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
- import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
--import org.bouncycastle.asn1.x9.X962NamedCurves;
--import org.bouncycastle.asn1.x9.X962Parameters;
--import org.bouncycastle.asn1.x9.X9ECParameters;
--import org.bouncycastle.asn1.x9.X9ECPoint;
-+// BEGIN android-removed
-+// import org.bouncycastle.asn1.x9.X962NamedCurves;
-+// import org.bouncycastle.asn1.x9.X962Parameters;
-+// import org.bouncycastle.asn1.x9.X9ECParameters;
-+// import org.bouncycastle.asn1.x9.X9ECPoint;
-+// END android-removed
- import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
- import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
- import org.bouncycastle.crypto.params.DHParameters;
- import org.bouncycastle.crypto.params.DHPublicKeyParameters;
- import org.bouncycastle.crypto.params.DSAParameters;
+@@ -34,8 +38,10 @@
  import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
--import org.bouncycastle.crypto.params.ECDomainParameters;
--import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+ import org.bouncycastle.crypto.params.ECDomainParameters;
+ import org.bouncycastle.crypto.params.ECPublicKeyParameters;
 -import org.bouncycastle.crypto.params.ElGamalParameters;
 -import org.bouncycastle.crypto.params.ElGamalPublicKeyParameters;
 +// BEGIN android-removed
-+// import org.bouncycastle.crypto.params.ECDomainParameters;
-+// import org.bouncycastle.crypto.params.ECPublicKeyParameters;
 +// import org.bouncycastle.crypto.params.ElGamalParameters;
 +// import org.bouncycastle.crypto.params.ElGamalPublicKeyParameters;
 +// END android-removed
  import org.bouncycastle.crypto.params.RSAKeyParameters;
  
  import java.io.IOException;
-@@ -112,13 +120,15 @@
+@@ -112,13 +118,15 @@
  
              return new DHPublicKeyParameters(derY.getValue(), dhParams);
          }
@@ -2870,122 +2826,65 @@
          else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_dsa)
                   || algId.getObjectId().equals(OIWObjectIdentifiers.dsaWithSHA1))
          {
-@@ -134,58 +144,60 @@
- 
-             return new DSAPublicKeyParameters(derY.getValue(), parameters);
-         }
--        else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_ecPublicKey))
--        {
--            X962Parameters      params = new X962Parameters((DERObject)keyInfo.getAlgorithmId().getParameters());
--            ECDomainParameters  dParams = null;
+@@ -138,27 +146,29 @@
+         {
+             X962Parameters      params = new X962Parameters((DERObject)keyInfo.getAlgorithmId().getParameters());
+             ECDomainParameters  dParams = null;
 -            
--            if (params.isNamedCurve())
--            {
--                DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters();
--                X9ECParameters      ecP = X962NamedCurves.getByOID(oid);
++        
+             if (params.isNamedCurve())
+             {
+                 DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters();
+                 X9ECParameters      ecP = X962NamedCurves.getByOID(oid);
 -
--                if (ecP == null)
--                {
--                    ecP = SECNamedCurves.getByOID(oid);
++        
+                 if (ecP == null)
+                 {
+                     ecP = SECNamedCurves.getByOID(oid);
 -
--                    if (ecP == null)
--                    {
--                        ecP = NISTNamedCurves.getByOID(oid);
++        
+                     if (ecP == null)
+                     {
+                         ecP = NISTNamedCurves.getByOID(oid);
 -
 -                        if (ecP == null)
 -                        {
 -                            ecP = TeleTrusTNamedCurves.getByOID(oid);
 -                        }
--                    }
--                }
++        
++                        // BEGIN android-removed
++                        // if (ecP == null)
++                        // {
++                        //     ecP = TeleTrusTNamedCurves.getByOID(oid);
++                        // }
++                        // END android-removed
+                     }
+                 }
 -
--                dParams = new ECDomainParameters(
--                                            ecP.getCurve(),
--                                            ecP.getG(),
--                                            ecP.getN(),
--                                            ecP.getH(),
--                                            ecP.getSeed());
--            }
--            else
--            {
--                X9ECParameters ecP = new X9ECParameters(
--                            (ASN1Sequence)params.getParameters());
--                dParams = new ECDomainParameters(
--                                            ecP.getCurve(),
--                                            ecP.getG(),
--                                            ecP.getN(),
--                                            ecP.getH(),
--                                            ecP.getSeed());
--            }
++        
+                 dParams = new ECDomainParameters(
+                                             ecP.getCurve(),
+                                             ecP.getG(),
+@@ -177,13 +187,13 @@
+                                             ecP.getH(),
+                                             ecP.getSeed());
+             }
 -
--            DERBitString    bits = keyInfo.getPublicKeyData();
--            byte[]          data = bits.getBytes();
--            ASN1OctetString key = new DEROctetString(data);
++        
+             DERBitString    bits = keyInfo.getPublicKeyData();
+             byte[]          data = bits.getBytes();
+             ASN1OctetString key = new DEROctetString(data);
 -
--            X9ECPoint       derQ = new X9ECPoint(dParams.getCurve(), key);
++        
+             X9ECPoint       derQ = new X9ECPoint(dParams.getCurve(), key);
 -            
--            return new ECPublicKeyParameters(derQ.getPoint(), dParams);
--        }
-+        // BEGIN android-removed
-+        // else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_ecPublicKey))
-+        // {
-+        //     X962Parameters      params = new X962Parameters((DERObject)keyInfo.getAlgorithmId().getParameters());
-+        //     ECDomainParameters  dParams = null;
-+        //
-+        //     if (params.isNamedCurve())
-+        //     {
-+        //         DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters();
-+        //         X9ECParameters      ecP = X962NamedCurves.getByOID(oid);
-+        //
-+        //         if (ecP == null)
-+        //         {
-+        //             ecP = SECNamedCurves.getByOID(oid);
-+        //
-+        //             if (ecP == null)
-+        //             {
-+        //                 ecP = NISTNamedCurves.getByOID(oid);
-+        //
-+        //                 if (ecP == null)
-+        //                 {
-+        //                     ecP = TeleTrusTNamedCurves.getByOID(oid);
-+        //                 }
-+        //             }
-+        //         }
-+        //
-+        //         dParams = new ECDomainParameters(
-+        //                                     ecP.getCurve(),
-+        //                                     ecP.getG(),
-+        //                                     ecP.getN(),
-+        //                                     ecP.getH(),
-+        //                                     ecP.getSeed());
-+        //     }
-+        //     else
-+        //     {
-+        //         X9ECParameters ecP = new X9ECParameters(
-+        //                     (ASN1Sequence)params.getParameters());
-+        //         dParams = new ECDomainParameters(
-+        //                                     ecP.getCurve(),
-+        //                                     ecP.getG(),
-+        //                                     ecP.getN(),
-+        //                                     ecP.getH(),
-+        //                                     ecP.getSeed());
-+        //     }
-+        //
-+        //     DERBitString    bits = keyInfo.getPublicKeyData();
-+        //     byte[]          data = bits.getBytes();
-+        //     ASN1OctetString key = new DEROctetString(data);
-+        //
-+        //     X9ECPoint       derQ = new X9ECPoint(dParams.getCurve(), key);
-+        //
-+        //     return new ECPublicKeyParameters(derQ.getPoint(), dParams);
-+        // }
-+        // END android-removed
++        
+             return new ECPublicKeyParameters(derQ.getPoint(), dParams);
+         }
          else
-         {
-             throw new RuntimeException("algorithm identifier in key not recognised");
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/PKCS10CertificationRequest.java bcprov-jdk16-145/org/bouncycastle/jce/PKCS10CertificationRequest.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/PKCS10CertificationRequest.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/PKCS10CertificationRequest.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/PKCS10CertificationRequest.java	2011-09-03 18:25:17.000000000 +0000
 @@ -78,8 +78,11 @@
  
      static
@@ -3049,8 +2948,20 @@
  
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/BouncyCastleProvider.java bcprov-jdk16-145/org/bouncycastle/jce/provider/BouncyCastleProvider.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/BouncyCastleProvider.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/BouncyCastleProvider.java	2011-09-06 19:05:42.000000000 +0000
-@@ -53,7 +53,12 @@
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/BouncyCastleProvider.java	2011-09-03 18:25:17.000000000 +0000
+@@ -45,7 +45,10 @@
+ {
+     private static String info = "BouncyCastle Security Provider v1.45";
+ 
+-    public static String PROVIDER_NAME = "BC";
++    // BEGIN android-changed
++    //     this constant should be final
++    public static final String PROVIDER_NAME = "BC";
++    // END android-changed
+ 
+     /*
+      * Configurable symmetric ciphers
+@@ -53,7 +56,12 @@
      private static final String SYMMETRIC_CIPHER_PACKAGE = "org.bouncycastle.jce.provider.symmetric.";
      private static final String[] SYMMETRIC_CIPHERS =
      {
@@ -3064,18 +2975,7 @@
      };
  
      /*
-@@ -62,7 +67,9 @@
-     private static final String ASYMMETRIC_CIPHER_PACKAGE = "org.bouncycastle.jce.provider.asymmetric.";
-     private static final String[] ASYMMETRIC_CIPHERS =
-     {
--        "EC"
-+        // BEGIN android-removed
-+        // "EC"
-+        // END android-removed
-     };
- 
-     /**
-@@ -89,26 +96,28 @@
+@@ -89,26 +97,28 @@
          loadAlgorithms(SYMMETRIC_CIPHER_PACKAGE, SYMMETRIC_CIPHERS);
          loadAlgorithms(ASYMMETRIC_CIPHER_PACKAGE, ASYMMETRIC_CIPHERS);
  
@@ -3124,7 +3024,7 @@
  
  
          //
-@@ -117,14 +126,24 @@
+@@ -117,14 +127,24 @@
          put("KeyStore.BKS", "org.bouncycastle.jce.provider.JDKKeyStore");
          put("KeyStore.BouncyCastle", "org.bouncycastle.jce.provider.JDKKeyStore$BouncyCastleStore");
          put("KeyStore.PKCS12", "org.bouncycastle.jce.provider.JDKPKCS12KeyStore$BCPKCS12KeyStore");
@@ -3157,7 +3057,7 @@
  
          put("Alg.Alias.KeyStore.UBER", "BouncyCastle");
          put("Alg.Alias.KeyStore.BOUNCYCASTLE", "BouncyCastle");
-@@ -141,44 +160,63 @@
+@@ -141,44 +161,63 @@
          //
          put("AlgorithmParameterGenerator.DH", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DH");
          put("AlgorithmParameterGenerator.DSA", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DSA");
@@ -3245,7 +3145,7 @@
          put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND40BITRC2-CBC", "PKCS12PBE");
          put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND40BITRC4", "PKCS12PBE");
          put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND128BITRC2-CBC", "PKCS12PBE");
-@@ -192,7 +230,7 @@
+@@ -192,7 +231,7 @@
          put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.5", "PKCS12PBE");
          put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.6", "PKCS12PBE");
          put("Alg.Alias.AlgorithmParameters.PBEWithSHAAnd3KeyTripleDES", "PKCS12PBE");
@@ -3254,7 +3154,7 @@
          put("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc.getId(), "PKCS12PBE");
          put("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc.getId(), "PKCS12PBE");
          put("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes256_cbc.getId(), "PKCS12PBE");
-@@ -202,22 +240,24 @@
+@@ -202,22 +241,24 @@
  
          put("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.id_RSAES_OAEP, "OAEP");
          
@@ -3295,7 +3195,7 @@
          
          put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND128BITAES-CBC-BC", "PKCS12PBE");
          put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND192BITAES-CBC-BC", "PKCS12PBE");
-@@ -234,12 +274,14 @@
+@@ -234,12 +275,14 @@
          put("Alg.Alias.AlgorithmParameters.PBEWITHSHA-256AND128BITAES-CBC-BC","PKCS12PBE");
          put("Alg.Alias.AlgorithmParameters.PBEWITHSHA-256AND192BITAES-CBC-BC","PKCS12PBE");
          put("Alg.Alias.AlgorithmParameters.PBEWITHSHA-256AND256BITAES-CBC-BC","PKCS12PBE");
@@ -3316,7 +3216,7 @@
          
          //
          // key agreement
-@@ -252,97 +294,129 @@
+@@ -252,97 +295,129 @@
          //
          put("Cipher.DES", "org.bouncycastle.jce.provider.JCEBlockCipher$DES");
          put("Cipher.DESEDE", "org.bouncycastle.jce.provider.JCEBlockCipher$DESede");
@@ -3512,7 +3412,7 @@
  
          put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc.getId(), "PBEWITHSHAAND128BITAES-CBC-BC");
          put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc.getId(), "PBEWITHSHAAND192BITAES-CBC-BC");
-@@ -350,7 +424,7 @@
+@@ -350,7 +425,7 @@
          put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc.getId(), "PBEWITHSHA256AND128BITAES-CBC-BC");
          put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.getId(), "PBEWITHSHA256AND192BITAES-CBC-BC");
          put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.getId(), "PBEWITHSHA256AND256BITAES-CBC-BC");
@@ -3521,7 +3421,7 @@
          put("Cipher.PBEWITHSHAAND128BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
          put("Cipher.PBEWITHSHAAND192BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
          put("Cipher.PBEWITHSHAAND256BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
-@@ -372,7 +446,9 @@
+@@ -372,7 +447,9 @@
          put("Cipher.PBEWITHMD5AND256BITAES-CBC-OPENSSL", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
          
          put("Cipher.PBEWITHSHAANDTWOFISH-CBC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHAAndTwofish");
@@ -3532,7 +3432,7 @@
  
          put("Alg.Alias.Cipher.1.2.840.113549.1.12.1.1", "PBEWITHSHAAND128BITRC4");
          put("Alg.Alias.Cipher.1.2.840.113549.1.12.1.2", "PBEWITHSHAAND40BITRC4");
-@@ -387,38 +463,49 @@
+@@ -387,38 +464,49 @@
          put("KeyGenerator.DES", "org.bouncycastle.jce.provider.JCEKeyGenerator$DES");
          put("Alg.Alias.KeyGenerator." + OIWObjectIdentifiers.desCBC, "DES");
          put("KeyGenerator.DESEDE", "org.bouncycastle.jce.provider.JCEKeyGenerator$DESede");
@@ -3610,7 +3510,7 @@
  
          //
          // key pair generators.
-@@ -426,14 +513,18 @@
+@@ -426,14 +514,18 @@
          put("KeyPairGenerator.RSA", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$RSA");
          put("KeyPairGenerator.DH", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$DH");
          put("KeyPairGenerator.DSA", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$DSA");
@@ -3633,7 +3533,7 @@
  
          //
          // key factories
-@@ -441,20 +532,24 @@
+@@ -441,20 +533,24 @@
          put("KeyFactory.RSA", "org.bouncycastle.jce.provider.JDKKeyFactory$RSA");
          put("KeyFactory.DH", "org.bouncycastle.jce.provider.JDKKeyFactory$DH");
          put("KeyFactory.DSA", "org.bouncycastle.jce.provider.JDKKeyFactory$DSA");
@@ -3666,7 +3566,7 @@
  
          //
          // Algorithm parameters
-@@ -462,16 +557,22 @@
+@@ -462,16 +558,22 @@
          put("AlgorithmParameters.DES", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
          put("Alg.Alias.AlgorithmParameters." + OIWObjectIdentifiers.desCBC, "DES");
          put("AlgorithmParameters.DESEDE", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
@@ -3697,7 +3597,7 @@
  
          
          //
-@@ -479,8 +580,10 @@
+@@ -479,8 +581,10 @@
          //
          put("SecretKeyFactory.DES", "org.bouncycastle.jce.provider.JCESecretKeyFactory$DES");
          put("SecretKeyFactory.DESEDE", "org.bouncycastle.jce.provider.JCESecretKeyFactory$DESede");
@@ -3710,7 +3610,7 @@
          put("SecretKeyFactory.PBEWITHMD5ANDDES", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD5AndDES");
          put("SecretKeyFactory.PBEWITHMD5ANDRC2", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD5AndRC2");
          put("SecretKeyFactory.PBEWITHSHA1ANDDES", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHA1AndDES");
-@@ -492,31 +595,41 @@
+@@ -492,31 +596,41 @@
          put("SecretKeyFactory.PBEWITHSHAAND128BITRC2-CBC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAnd128BitRC2");
          put("SecretKeyFactory.PBEWITHSHAAND40BITRC2-CBC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAnd40BitRC2");
          put("SecretKeyFactory.PBEWITHSHAANDTWOFISH-CBC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAndTwofish");
@@ -3767,7 +3667,7 @@
          put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC, "PBEWITHMD5ANDDES");
          put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC, "PBEWITHMD5ANDRC2");
          put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC, "PBEWITHSHA1ANDDES");
-@@ -553,6 +666,10 @@
+@@ -553,6 +667,10 @@
          put("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc.getId(), "PBEWITHSHA256AND128BITAES-CBC-BC");
          put("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.getId(), "PBEWITHSHA256AND192BITAES-CBC-BC");
          put("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.getId(), "PBEWITHSHA256AND256BITAES-CBC-BC");
@@ -3778,7 +3678,7 @@
  
          addMacAlgorithms();
  
-@@ -561,16 +678,23 @@
+@@ -561,16 +679,23 @@
          addSignatureAlgorithms();
  
      // Certification Path API
@@ -3809,7 +3709,7 @@
      }
  
      private void loadAlgorithms(String packageName, String[] names)
-@@ -631,68 +755,72 @@
+@@ -631,68 +756,72 @@
      //
      private void addMacAlgorithms()
      {
@@ -3938,7 +3838,7 @@
          addHMACAlgorithm("SHA256", "org.bouncycastle.jce.provider.JCEMac$SHA256", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACSHA256");
          addHMACAlias("SHA256", PKCSObjectIdentifiers.id_hmacWithSHA256);
          addHMACAlgorithm("SHA384", "org.bouncycastle.jce.provider.JCEMac$SHA384", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACSHA384");
-@@ -700,16 +828,20 @@
+@@ -700,16 +829,20 @@
          addHMACAlgorithm("SHA512", "org.bouncycastle.jce.provider.JCEMac$SHA512", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACSHA512");
          addHMACAlias("SHA512", PKCSObjectIdentifiers.id_hmacWithSHA512);
  
@@ -3966,7 +3866,7 @@
          put("Alg.Alias.Mac.1.3.14.3.2.26", "PBEWITHHMACSHA");
      }
  
-@@ -747,9 +879,11 @@
+@@ -747,9 +880,11 @@
          put("Alg.Alias.MessageDigest.SHA1", "SHA-1");
          put("Alg.Alias.MessageDigest.SHA", "SHA-1");
          put("Alg.Alias.MessageDigest." + OIWObjectIdentifiers.idSHA1, "SHA-1");
@@ -3981,7 +3881,7 @@
          put("MessageDigest.SHA-256", "org.bouncycastle.jce.provider.JDKMessageDigest$SHA256");
          put("Alg.Alias.MessageDigest.SHA256", "SHA-256");
          put("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha256, "SHA-256");
-@@ -760,27 +894,31 @@
+@@ -760,27 +895,31 @@
          put("Alg.Alias.MessageDigest.SHA512", "SHA-512");
          put("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha512, "SHA-512");
          
@@ -4032,7 +3932,7 @@
      }
      
      //
-@@ -788,55 +926,70 @@
+@@ -788,55 +927,70 @@
      //
      private void addSignatureAlgorithms()
      {
@@ -4141,7 +4041,7 @@
  
          put("Alg.Alias.Signature.SHA256withRSAEncryption", "SHA256WithRSAEncryption");
          put("Alg.Alias.Signature.SHA384withRSAEncryption", "SHA384WithRSAEncryption");
-@@ -850,24 +1003,30 @@
+@@ -850,24 +1004,30 @@
          put("Alg.Alias.Signature.SHA384WITHRSAENCRYPTION", "SHA384WithRSAEncryption");
          put("Alg.Alias.Signature.SHA512WITHRSAENCRYPTION", "SHA512WithRSAEncryption");
  
@@ -4184,7 +4084,7 @@
          put("Alg.Alias.Signature.SHA256WithRSA", "SHA256WithRSAEncryption");
          put("Alg.Alias.Signature.SHA256withRSA", "SHA256WithRSAEncryption");
          put("Alg.Alias.Signature.SHA384WithRSA", "SHA384WithRSAEncryption");
-@@ -877,92 +1036,110 @@
+@@ -877,92 +1037,110 @@
          put("Alg.Alias.Signature.SHA1/RSA", "SHA1WithRSAEncryption");
          put("Alg.Alias.Signature.SHA-1/RSA", "SHA1WithRSAEncryption");
          put("Alg.Alias.Signature." + PKCSObjectIdentifiers.sha1WithRSAEncryption, "SHA1WithRSAEncryption");
@@ -4368,7 +4268,7 @@
      {
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java bcprov-jdk16-145/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java	2011-09-03 18:25:17.000000000 +0000
 @@ -24,6 +24,7 @@
  import java.security.spec.DSAPublicKeySpec;
  import java.text.ParseException;
@@ -4408,7 +4308,7 @@
  import org.bouncycastle.x509.X509AttributeCertificate;
  import org.bouncycastle.x509.X509CRLStoreSelector;
  import org.bouncycastle.x509.X509CertStoreSelector;
-@@ -110,29 +119,32 @@
+@@ -110,38 +119,38 @@
          "privilegeWithdrawn",
          "aACompromise" };
      
@@ -4462,9 +4362,10 @@
 +    // BEGIN android-changed
      /**
       * Search the given Set of TrustAnchor's for one that is the
-      * issuer of the given X509 certificate. Uses the specified
-@@ -140,8 +152,7 @@
-      * if null.
+-     * issuer of the given X509 certificate. Uses the specified
+-     * provider for signature verification, or the default provider
+-     * if null.
++     * issuer of the given X509 certificate.
       *
       * @param cert the X509 certificate
 -     * @param trustAnchors a Set of TrustAnchor's
@@ -4473,7 +4374,7 @@
       *
       * @return the <code>TrustAnchor</code> object if found or
       * <code>null</code> if not.
-@@ -152,10 +163,21 @@
+@@ -152,10 +161,21 @@
       */
      protected static TrustAnchor findTrustAnchor(
          X509Certificate cert,
@@ -4497,7 +4398,7 @@
          TrustAnchor trust = null;
          PublicKey trustPublicKey = null;
          Exception invalidKeyEx = null;
-@@ -172,21 +194,49 @@
+@@ -172,7 +192,9 @@
              throw new AnnotatedException("Cannot set subject search criteria for trust anchor.", ex);
          }
  
@@ -4505,53 +4406,10 @@
 +        // BEGIN android-changed
 +        Iterator iter = params.getTrustAnchors().iterator();
 +        // END android-changed
-+        // BEGIN android-added
-+        byte[] certBytes = null;
-+        try {
-+            certBytes = cert.getEncoded();
-+        } catch (Exception e) {
-+            // ignore, just continue
-+        }
-+        // END android-added
          while (iter.hasNext() && trust == null)
          {
              trust = (TrustAnchor) iter.next();
--            if (trust.getTrustedCert() != null)
-+            // BEGIN android-changed
-+            X509Certificate trustCert = trust.getTrustedCert();
-+            // END android-changed
-+            // BEGIN android-added
-+            // If the trust anchor is identical to the certificate we're
-+            // done. Just return the anchor.
-+            // There is similar code in PKIXCertPathValidatorSpi.
-+            try {
-+                byte[] trustBytes = trustCert.getEncoded();
-+                if (certBytes != null && Arrays.equals(trustBytes, certBytes)) {
-+                    return trust;
-+                }
-+            } catch (Exception e) {
-+                // ignore, continue and verify the certificate
-+            }
-+            // END android-added
-+            // BEGIN android-changed
-+            if (trustCert != null)
-             {
--                if (certSelectX509.match(trust.getTrustedCert()))
-+                if (certSelectX509.match(trustCert))
-                 {
--                    trustPublicKey = trust.getTrustedCert().getPublicKey();
-+                    trustPublicKey = trustCert.getPublicKey();
-                 }
-                 else
-                 {
-                     trust = null;
-                 }
-             }
-+            // END android-changed
-             else if (trust.getCAName() != null
-                     && trust.getCAPublicKey() != null)
-             {
-@@ -216,7 +266,9 @@
+@@ -216,7 +238,9 @@
              {
                  try
                  {
@@ -4562,7 +4420,7 @@
                  }
                  catch (Exception ex)
                  {
-@@ -248,7 +300,9 @@
+@@ -248,7 +272,9 @@
              {
                  // look for URI
                  List list = (List) it.next();
@@ -4573,7 +4431,7 @@
                  {
                      // found
                      String temp = (String) list.get(1);
-@@ -721,38 +775,40 @@
+@@ -721,38 +747,40 @@
          {
              try
              {
@@ -4646,7 +4504,7 @@
              }
              catch (Exception e)
              {
-@@ -819,35 +875,37 @@
+@@ -819,35 +847,37 @@
          return certs;
      }
  
@@ -4715,7 +4573,7 @@
          CRLDistPoint crldp, ExtendedPKIXParameters pkixParams)
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEBlockCipher.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEBlockCipher.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEBlockCipher.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEBlockCipher.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEBlockCipher.java	2011-09-03 18:25:17.000000000 +0000
 @@ -7,22 +7,31 @@
  import org.bouncycastle.crypto.InvalidCipherTextException;
  import org.bouncycastle.crypto.engines.AESFastEngine;
@@ -5664,7 +5522,7 @@
       */
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java	2011-09-03 18:25:17.000000000 +0000
 @@ -37,9 +37,11 @@
  
      static
@@ -5682,7 +5540,7 @@
          algorithms.put("DESEDE", i192);
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEDigestUtil.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEDigestUtil.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEDigestUtil.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEDigestUtil.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEDigestUtil.java	2011-09-03 18:25:17.000000000 +0000
 @@ -12,7 +12,9 @@
  import org.bouncycastle.crypto.Digest;
  import org.bouncycastle.crypto.digests.MD5Digest;
@@ -5763,10 +5621,342 @@
              || (sha256.contains(digest1) && sha256.contains(digest2))
              || (sha384.contains(digest1) && sha384.contains(digest2))
              || (sha512.contains(digest1) && sha512.contains(digest2))
+diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEECPrivateKey.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEECPrivateKey.java
+--- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEECPrivateKey.java	2010-01-11 21:46:14.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEECPrivateKey.java	2011-09-03 18:25:17.000000000 +0000
+@@ -20,7 +20,9 @@
+ import org.bouncycastle.asn1.DERObject;
+ import org.bouncycastle.asn1.DERObjectIdentifier;
+ import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+-import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
++// BEGIN android-removed
++// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
++// END android-removed
+ import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+ import org.bouncycastle.asn1.sec.ECPrivateKeyStructure;
+ import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+@@ -199,21 +201,23 @@
+             DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters();
+             X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+ 
+-            if (ecP == null) // GOST Curve
+-            {
+-                ECDomainParameters gParam = ECGOST3410NamedCurves.getByOID(oid);
+-                EllipticCurve ellipticCurve = EC5Util.convertCurve(gParam.getCurve(), gParam.getSeed());
+-
+-                ecSpec = new ECNamedCurveSpec(
+-                        ECGOST3410NamedCurves.getName(oid),
+-                        ellipticCurve,
+-                        new ECPoint(
+-                                gParam.getG().getX().toBigInteger(),
+-                                gParam.getG().getY().toBigInteger()),
+-                        gParam.getN(),
+-                        gParam.getH());
+-            }
+-            else
++            // BEGIN android-removed
++            // if (ecP == null) // GOST Curve
++            // {
++            //     ECDomainParameters gParam = ECGOST3410NamedCurves.getByOID(oid);
++            //     EllipticCurve ellipticCurve = EC5Util.convertCurve(gParam.getCurve(), gParam.getSeed());
++            //
++            //     ecSpec = new ECNamedCurveSpec(
++            //             ECGOST3410NamedCurves.getName(oid),
++            //             ellipticCurve,
++            //             new ECPoint(
++            //                     gParam.getG().getX().toBigInteger(),
++            //                     gParam.getG().getY().toBigInteger()),
++            //             gParam.getN(),
++            //             gParam.getH());
++            // }
++            // else
++            // END android-removed
+             {
+                 EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
+ 
+@@ -321,11 +325,13 @@
+             keyStructure = new ECPrivateKeyStructure(this.getS(), params);
+         }
+ 
+-        if (algorithm.equals("ECGOST3410"))
+-        {
+-            info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params.getDERObject()), keyStructure.getDERObject());
+-        }
+-        else
++        // BEGIN android-removed
++        // if (algorithm.equals("ECGOST3410"))
++        // {
++        //     info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params.getDERObject()), keyStructure.getDERObject());
++        // }
++        // else
++        // END android-removed
+         {
+ 
+             info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params.getDERObject()), keyStructure.getDERObject());
+diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEECPublicKey.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEECPublicKey.java
+--- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEECPublicKey.java	2010-01-11 21:46:14.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEECPublicKey.java	2011-09-03 18:25:17.000000000 +0000
+@@ -20,8 +20,10 @@
+ import org.bouncycastle.asn1.DERObjectIdentifier;
+ import org.bouncycastle.asn1.DEROctetString;
+ import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+-import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+-import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
++// BEGIN android-removed
++// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
++// import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
++// END android-removed
+ import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+ import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+ import org.bouncycastle.asn1.x9.X962Parameters;
+@@ -31,11 +33,15 @@
+ import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+ import org.bouncycastle.crypto.params.ECDomainParameters;
+ import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+-import org.bouncycastle.jce.ECGOST3410NamedCurveTable;
++// BEGIN android-removed
++// import org.bouncycastle.jce.ECGOST3410NamedCurveTable;
++// END android-removed
+ import org.bouncycastle.jce.interfaces.ECPointEncoder;
+ import org.bouncycastle.jce.provider.asymmetric.ec.EC5Util;
+ import org.bouncycastle.jce.provider.asymmetric.ec.ECUtil;
+-import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
++// BEGIN android-removed
++// import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
++// END android-removed
+ import org.bouncycastle.jce.spec.ECNamedCurveSpec;
+ import org.bouncycastle.math.ec.ECCurve;
+ 
+@@ -46,7 +52,9 @@
+     private org.bouncycastle.math.ec.ECPoint q;
+     private ECParameterSpec         ecSpec;
+     private boolean                 withCompression;
+-    private GOST3410PublicKeyAlgParameters       gostParams;
++    // BEGIN android-removed
++    // private GOST3410PublicKeyAlgParameters       gostParams;
++    // END android-removed
+ 
+     public JCEECPublicKey(
+         String              algorithm,
+@@ -56,7 +64,9 @@
+         this.q = key.q;
+         this.ecSpec = key.ecSpec;
+         this.withCompression = key.withCompression;
+-        this.gostParams = key.gostParams;
++        // BEGIN android-removed
++        // this.gostParams = key.gostParams;
++        // END android-removed
+     }
+     
+     public JCEECPublicKey(
+@@ -179,54 +189,56 @@
+ 
+     private void populateFromPubKeyInfo(SubjectPublicKeyInfo info)
+     {
+-        if (info.getAlgorithmId().getObjectId().equals(CryptoProObjectIdentifiers.gostR3410_2001))
+-        {
+-            DERBitString bits = info.getPublicKeyData();
+-            ASN1OctetString key;
+-            this.algorithm = "ECGOST3410";
+-
+-            try
+-            {
+-                key = (ASN1OctetString) ASN1Object.fromByteArray(bits.getBytes());
+-            }
+-            catch (IOException ex)
+-            {
+-                throw new IllegalArgumentException("error recovering public key");
+-            }
+-
+-            byte[]          keyEnc = key.getOctets();
+-            byte[]          x = new byte[32];
+-            byte[]          y = new byte[32];
+-
+-            for (int i = 0; i != x.length; i++)
+-            {
+-                x[i] = keyEnc[32 - 1 - i];
+-            }
+-
+-            for (int i = 0; i != y.length; i++)
+-            {
+-                y[i] = keyEnc[64 - 1 - i];
+-            }
+-
+-            gostParams = new GOST3410PublicKeyAlgParameters((ASN1Sequence)info.getAlgorithmId().getParameters());
+-
+-            ECNamedCurveParameterSpec spec = ECGOST3410NamedCurveTable.getParameterSpec(ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()));
+-
+-            ECCurve curve = spec.getCurve();
+-            EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getSeed());
+-
+-            this.q = curve.createPoint(new BigInteger(1, x), new BigInteger(1, y), false);
+-
+-            ecSpec = new ECNamedCurveSpec(
+-                    ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()),
+-                    ellipticCurve,
+-                    new ECPoint(
+-                            spec.getG().getX().toBigInteger(),
+-                            spec.getG().getY().toBigInteger()),
+-                            spec.getN(), spec.getH());
+-
+-        }
+-        else
++        // BEGIN android-removed
++        // if (info.getAlgorithmId().getObjectId().equals(CryptoProObjectIdentifiers.gostR3410_2001))
++        // {
++        //     DERBitString bits = info.getPublicKeyData();
++        //     ASN1OctetString key;
++        //     this.algorithm = "ECGOST3410";
++        //
++        //     try
++        //     {
++        //         key = (ASN1OctetString) ASN1Object.fromByteArray(bits.getBytes());
++        //     }
++        //     catch (IOException ex)
++        //     {
++        //         throw new IllegalArgumentException("error recovering public key");
++        //     }
++        //
++        //     byte[]          keyEnc = key.getOctets();
++        //     byte[]          x = new byte[32];
++        //     byte[]          y = new byte[32];
++        //
++        //     for (int i = 0; i != x.length; i++)
++        //     {
++        //         x[i] = keyEnc[32 - 1 - i];
++        //     }
++        //
++        //     for (int i = 0; i != y.length; i++)
++        //     {
++        //         y[i] = keyEnc[64 - 1 - i];
++        //     }
++        //
++        //     gostParams = new GOST3410PublicKeyAlgParameters((ASN1Sequence)info.getAlgorithmId().getParameters());
++        //
++        //     ECNamedCurveParameterSpec spec = ECGOST3410NamedCurveTable.getParameterSpec(ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()));
++        //
++        //     ECCurve curve = spec.getCurve();
++        //     EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getSeed());
++        //
++        //     this.q = curve.createPoint(new BigInteger(1, x), new BigInteger(1, y), false);
++        //
++        //     ecSpec = new ECNamedCurveSpec(
++        //             ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()),
++        //             ellipticCurve,
++        //             new ECPoint(
++        //                     spec.getG().getX().toBigInteger(),
++        //                     spec.getG().getY().toBigInteger()),
++        //                     spec.getN(), spec.getH());
++        //
++        // }
++        // else
++        // END android-removed
+         {
+             X962Parameters params = new X962Parameters((DERObject)info.getAlgorithmId().getParameters());
+             ECCurve                 curve;
+@@ -315,45 +327,47 @@
+         ASN1Encodable        params;
+         SubjectPublicKeyInfo info;
+ 
+-        if (algorithm.equals("ECGOST3410"))
+-        {
+-            if (gostParams != null)
+-            {
+-                params = gostParams;
+-            }
+-            else
+-            {
+-                if (ecSpec instanceof ECNamedCurveSpec)
+-                {
+-                    params = new GOST3410PublicKeyAlgParameters(
+-                                   ECGOST3410NamedCurves.getOID(((ECNamedCurveSpec)ecSpec).getName()),
+-                                   CryptoProObjectIdentifiers.gostR3411_94_CryptoProParamSet);
+-                }
+-                else
+-                {   // strictly speaking this may not be applicable...
+-                    ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
+-
+-                    X9ECParameters ecP = new X9ECParameters(
+-                        curve,
+-                        EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
+-                        ecSpec.getOrder(),
+-                        BigInteger.valueOf(ecSpec.getCofactor()),
+-                        ecSpec.getCurve().getSeed());
+-
+-                    params = new X962Parameters(ecP);
+-                }
+-            }
+-
+-            BigInteger      bX = this.q.getX().toBigInteger();
+-            BigInteger      bY = this.q.getY().toBigInteger();
+-            byte[]          encKey = new byte[64];
+-
+-            extractBytes(encKey, 0, bX);
+-            extractBytes(encKey, 32, bY);
+-
+-            info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params.getDERObject()), new DEROctetString(encKey));
+-        }
+-        else
++        // BEGIN android-removed
++        // if (algorithm.equals("ECGOST3410"))
++        // {
++        //     if (gostParams != null)
++        //     {
++        //         params = gostParams;
++        //     }
++        //     else
++        //     {
++        //         if (ecSpec instanceof ECNamedCurveSpec)
++        //         {
++        //             params = new GOST3410PublicKeyAlgParameters(
++        //                            ECGOST3410NamedCurves.getOID(((ECNamedCurveSpec)ecSpec).getName()),
++        //                            CryptoProObjectIdentifiers.gostR3411_94_CryptoProParamSet);
++        //         }
++        //         else
++        //         {   // strictly speaking this may not be applicable...
++        //             ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
++        //
++        //             X9ECParameters ecP = new X9ECParameters(
++        //                 curve,
++        //                 EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
++        //                 ecSpec.getOrder(),
++        //                 BigInteger.valueOf(ecSpec.getCofactor()),
++        //                 ecSpec.getCurve().getSeed());
++        //
++        //             params = new X962Parameters(ecP);
++        //         }
++        //     }
++        //
++        //     BigInteger      bX = this.q.getX().toBigInteger();
++        //     BigInteger      bY = this.q.getY().toBigInteger();
++        //     byte[]          encKey = new byte[64];
++        //
++        //     extractBytes(encKey, 0, bX);
++        //     extractBytes(encKey, 32, bY);
++        //
++        //     info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params.getDERObject()), new DEROctetString(encKey));
++        // }
++        // else
++        // END android-removed
+         {
+             if (ecSpec instanceof ECNamedCurveSpec)
+             {
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEKeyGenerator.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEKeyGenerator.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEKeyGenerator.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEKeyGenerator.java	2011-09-06 19:05:42.000000000 +0000
-@@ -145,30 +145,32 @@
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEKeyGenerator.java	2011-09-03 18:25:17.000000000 +0000
+@@ -57,6 +57,11 @@
+     {
+         try
+         {
++            // BEGIN android-added
++            if (random == null) {
++                random = new SecureRandom();
++            }
++            // END android-added
+             engine.init(new KeyGenerationParameters(random, keySize));
+             uninitialised = false;
+         }
+@@ -145,30 +150,32 @@
          }
      }
      
@@ -5823,7 +6013,7 @@
      /**
       * Blowfish
       */
-@@ -180,31 +182,33 @@
+@@ -180,31 +187,33 @@
              super("Blowfish", 128, new CipherKeyGenerator());
          }
      }
@@ -5882,7 +6072,7 @@
      /**
       * RC4
       */
-@@ -216,203 +220,207 @@
+@@ -216,203 +225,207 @@
              super("RC4", 128, new CipherKeyGenerator());
          }
      }
@@ -6282,7 +6472,7 @@
  
      /**
       * MD5HMAC
-@@ -427,29 +435,29 @@
+@@ -427,29 +440,29 @@
      }
  
  
@@ -6335,7 +6525,7 @@
  
  
      /**
-@@ -464,17 +472,19 @@
+@@ -464,17 +477,19 @@
          }
      }
  
@@ -6366,7 +6556,7 @@
      
      /**
       * HMACSHA256
-@@ -512,15 +522,17 @@
+@@ -512,15 +527,17 @@
          }
      }
      
@@ -6397,7 +6587,7 @@
  }
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEMac.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEMac.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEMac.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEMac.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEMac.java	2011-09-03 18:25:17.000000000 +0000
 @@ -2,29 +2,43 @@
  
  import org.bouncycastle.crypto.CipherParameters;
@@ -7150,7 +7340,7 @@
  }
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCERSACipher.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCERSACipher.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCERSACipher.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCERSACipher.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCERSACipher.java	2011-09-03 18:25:17.000000000 +0000
 @@ -534,48 +534,50 @@
          }
      }
@@ -7248,7 +7438,7 @@
  }
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java	2011-09-03 18:25:17.000000000 +0000
 @@ -125,7 +125,9 @@
       */
      public byte[] getEncoded()
@@ -7262,7 +7452,7 @@
      }
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCERSAPrivateKey.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCERSAPrivateKey.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCERSAPrivateKey.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCERSAPrivateKey.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCERSAPrivateKey.java	2011-09-03 18:25:17.000000000 +0000
 @@ -77,7 +77,9 @@
  
      public byte[] getEncoded()
@@ -7276,7 +7466,7 @@
      }
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCERSAPublicKey.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCERSAPublicKey.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCERSAPublicKey.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCERSAPublicKey.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCERSAPublicKey.java	2011-09-03 18:25:17.000000000 +0000
 @@ -90,7 +90,9 @@
  
      public byte[] getEncoded()
@@ -7290,7 +7480,7 @@
      }
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCESecretKeyFactory.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCESecretKeyFactory.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCESecretKeyFactory.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCESecretKeyFactory.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCESecretKeyFactory.java	2011-09-03 18:25:17.000000000 +0000
 @@ -321,29 +321,31 @@
          }
      }
@@ -7467,7 +7657,7 @@
  }
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEStreamCipher.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEStreamCipher.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEStreamCipher.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEStreamCipher.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEStreamCipher.java	2011-09-03 18:25:17.000000000 +0000
 @@ -5,17 +5,21 @@
  import org.bouncycastle.crypto.DataLengthException;
  import org.bouncycastle.crypto.StreamBlockCipher;
@@ -7911,7 +8101,7 @@
  }
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java	2011-09-03 18:25:17.000000000 +0000
 @@ -2,19 +2,25 @@
  
  import org.bouncycastle.crypto.generators.DHParametersGenerator;
@@ -8338,7 +8528,7 @@
  }
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java	2011-09-03 18:25:17.000000000 +0000
 @@ -10,21 +10,27 @@
  import org.bouncycastle.asn1.DERObjectIdentifier;
  import org.bouncycastle.asn1.DEROctetString;
@@ -9838,7 +10028,7 @@
  }
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKDSASigner.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKDSASigner.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKDSASigner.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKDSASigner.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKDSASigner.java	2011-09-03 18:25:17.000000000 +0000
 @@ -22,13 +22,17 @@
  import org.bouncycastle.crypto.DSA;
  import org.bouncycastle.crypto.Digest;
@@ -9989,7 +10179,7 @@
          extends JDKDSASigner
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKDigestSignature.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKDigestSignature.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKDigestSignature.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKDigestSignature.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKDigestSignature.java	2011-09-03 18:25:17.000000000 +0000
 @@ -23,14 +23,20 @@
  import org.bouncycastle.crypto.AsymmetricBlockCipher;
  import org.bouncycastle.crypto.CipherParameters;
@@ -10190,7 +10380,7 @@
  }
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKKeyFactory.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKKeyFactory.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKKeyFactory.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKKeyFactory.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKKeyFactory.java	2011-09-03 18:25:17.000000000 +0000
 @@ -36,17 +36,21 @@
  import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure;
  import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
@@ -10220,7 +10410,28 @@
      
      public JDKKeyFactory()
      {
-@@ -162,25 +166,33 @@
+@@ -140,6 +144,20 @@
+            
+            return new DHPublicKeySpec(k.getY(), k.getParams().getP(), k.getParams().getG());
+        }
++       // BEGIN android-added
++       else if (spec.isAssignableFrom(DSAPublicKeySpec.class) && key instanceof DSAPublicKey)
++       {
++            DSAPublicKey    k = (DSAPublicKey)key;
++
++            return new DSAPublicKeySpec(k.getY(), k.getParams().getP(), k.getParams().getQ(), k.getParams().getG());
++       }
++       else if (spec.isAssignableFrom(DSAPrivateKeySpec.class) && key instanceof DSAPrivateKey)
++       {
++            DSAPrivateKey    k = (DSAPrivateKey)key;
++
++            return new DSAPrivateKeySpec(k.getX(), k.getParams().getP(), k.getParams().getQ(), k.getParams().getG());
++       }
++       // END android-added
+ 
+        throw new RuntimeException("not implemented yet " + key + " " + spec);
+     }
+@@ -162,25 +180,33 @@
          }
          else if (key instanceof DHPublicKey)
          {
@@ -10268,7 +10479,7 @@
          }
          else if (key instanceof DSAPublicKey)
          {
-@@ -190,14 +202,16 @@
+@@ -190,14 +216,16 @@
          {
              return new JDKDSAPrivateKey((DSAPrivateKey)key);
          }
@@ -10293,7 +10504,7 @@
  
          throw new InvalidKeyException("key type unknown");
      }
-@@ -233,10 +247,12 @@
+@@ -233,10 +261,12 @@
          {
              return new JCEDHPublicKey(info);
          }
@@ -10310,14 +10521,10 @@
          else if (algOid.equals(X9ObjectIdentifiers.id_dsa))
          {
              return new JDKDSAPublicKey(info);
-@@ -245,18 +261,19 @@
+@@ -249,14 +279,15 @@
          {
-             return new JDKDSAPublicKey(info);
+             return new JCEECPublicKey(info);
          }
--        else if (algOid.equals(X9ObjectIdentifiers.id_ecPublicKey))
--        {
--            return new JCEECPublicKey(info);
--        }
 -        else if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_94))
 -        {
 -            return new JDKGOST3410PublicKey(info);
@@ -10327,10 +10534,6 @@
 -            return new JCEECPublicKey(info);
 -        }
 +        // BEGIN android-removed
-+        // else if (algOid.equals(X9ObjectIdentifiers.id_ecPublicKey))
-+        // {
-+        //     return new JCEECPublicKey(info);
-+        // }
 +        // else if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_94))
 +        // {
 +        //     return new JDKGOST3410PublicKey(info);
@@ -10342,7 +10545,7 @@
          else
          {
              throw new RuntimeException("algorithm identifier " + algOid + " in key not recognised");
-@@ -290,26 +307,30 @@
+@@ -290,10 +321,12 @@
          {
                return new JCEDHPrivateKey(info);
          }
@@ -10359,11 +10562,10 @@
          else if (algOid.equals(X9ObjectIdentifiers.id_dsa))
          {
                return new JDKDSAPrivateKey(info);
+@@ -302,14 +335,16 @@
+         {
+               return new JCEECPrivateKey(info);
          }
--        else if (algOid.equals(X9ObjectIdentifiers.id_ecPublicKey))
--        {
--              return new JCEECPrivateKey(info);
--        }
 -        else if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_94))
 -        {
 -              return new JDKGOST3410PrivateKey(info);
@@ -10373,10 +10575,6 @@
 -              return new JCEECPrivateKey(info);
 -        }
 +        // BEGIN android-removed
-+        // else if (algOid.equals(X9ObjectIdentifiers.id_ecPublicKey))
-+        // {
-+        //       return new JCEECPrivateKey(info);
-+        // }
 +        // else if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_94))
 +        // {
 +        //       return new JDKGOST3410PrivateKey(info);
@@ -10389,7 +10587,7 @@
          else
          {
              throw new RuntimeException("algorithm identifier " + algOid + " in key not recognised");
-@@ -440,89 +461,92 @@
+@@ -440,89 +475,92 @@
          }
      }
  
@@ -10568,7 +10766,7 @@
  }
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java	2011-09-03 18:25:17.000000000 +0000
 @@ -6,9 +6,11 @@
  import org.bouncycastle.crypto.generators.DHParametersGenerator;
  import org.bouncycastle.crypto.generators.DSAKeyPairGenerator;
@@ -10912,7 +11110,7 @@
  }
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKKeyStore.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKKeyStore.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKKeyStore.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKKeyStore.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKKeyStore.java	2011-09-03 18:25:17.000000000 +0000
 @@ -39,7 +39,12 @@
  import org.bouncycastle.crypto.CipherParameters;
  import org.bouncycastle.crypto.Digest;
@@ -11015,7 +11213,7 @@
  }
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKMessageDigest.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKMessageDigest.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKMessageDigest.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKMessageDigest.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKMessageDigest.java	2011-09-03 18:25:17.000000000 +0000
 @@ -57,36 +57,38 @@
          {
              super(new SHA1Digest());
@@ -11462,7 +11660,7 @@
  }
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java	2011-09-03 18:25:17.000000000 +0000
 @@ -255,10 +255,13 @@
              }
          }
@@ -11632,7 +11830,7 @@
                  return null;
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/PBE.java bcprov-jdk16-145/org/bouncycastle/jce/provider/PBE.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/PBE.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/PBE.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/PBE.java	2011-09-03 18:25:17.000000000 +0000
 @@ -7,12 +7,18 @@
  
  import org.bouncycastle.crypto.CipherParameters;
@@ -11707,7 +11905,7 @@
                      break;
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/PKCS12BagAttributeCarrierImpl.java bcprov-jdk16-145/org/bouncycastle/jce/provider/PKCS12BagAttributeCarrierImpl.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/PKCS12BagAttributeCarrierImpl.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/PKCS12BagAttributeCarrierImpl.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/PKCS12BagAttributeCarrierImpl.java	2011-09-03 18:25:17.000000000 +0000
 @@ -1,6 +1,9 @@
  package org.bouncycastle.jce.provider;
  
@@ -11850,7 +12048,7 @@
          {
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/PKIXCertPath.java bcprov-jdk16-145/org/bouncycastle/jce/provider/PKIXCertPath.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/PKIXCertPath.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/PKIXCertPath.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/PKIXCertPath.java	2011-09-03 18:25:17.000000000 +0000
 @@ -33,7 +33,9 @@
  import org.bouncycastle.asn1.pkcs.ContentInfo;
  import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
@@ -11915,7 +12113,7 @@
              throw new CertificateEncodingException("unsupported encoding: " + encoding);
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java bcprov-jdk16-145/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java	2011-09-03 18:25:17.000000000 +0000
 @@ -172,8 +172,9 @@
          try
          {
@@ -11930,7 +12128,7 @@
                  // chains
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java bcprov-jdk16-145/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java	2011-09-03 18:25:17.000000000 +0000
 @@ -1,5 +1,8 @@
  package org.bouncycastle.jce.provider;
  
@@ -12072,51 +12270,19 @@
  
          //
          // (b)
-@@ -90,10 +187,15 @@
-         // (d)
-         // 
+@@ -92,8 +189,10 @@
          TrustAnchor trust;
-+        // BEGIN android-added
-+        X509Certificate lastCert = (X509Certificate) certs.get(certs.size() - 1);
-+        // END android-added
          try
          {
--            trust = CertPathValidatorUtilities.findTrustAnchor((X509Certificate) certs.get(certs.size() - 1),
--                    paramsPKIX.getTrustAnchors(), paramsPKIX.getSigProvider());
 +            // BEGIN android-changed
-+            trust = CertPathValidatorUtilities.findTrustAnchor(lastCert,
+             trust = CertPathValidatorUtilities.findTrustAnchor((X509Certificate) certs.get(certs.size() - 1),
+-                    paramsPKIX.getTrustAnchors(), paramsPKIX.getSigProvider());
 +                    indexedParams != null ? indexedParams : paramsPKIX);
 +            // END android-changed
          }
          catch (AnnotatedException e)
          {
-@@ -189,12 +291,25 @@
-         X500Principal workingIssuerName;
- 
-         X509Certificate sign = trust.getTrustedCert();
-+        // BEGIN android-added
-+        boolean trustAnchorInChain = false;
-+        // END android-added
-         try
-         {
-             if (sign != null)
-             {
-                 workingIssuerName = CertPathValidatorUtilities.getSubjectPrincipal(sign);
-                 workingPublicKey = sign.getPublicKey();
-+                // BEGIN android-added
-+                // There is similar code in CertPathValidatorUtilities.
-+                try {
-+                    byte[] trustBytes = sign.getEncoded();
-+                    byte[] certBytes = lastCert.getEncoded();
-+                    trustAnchorInChain = Arrays.equals(trustBytes, certBytes);
-+                } catch(Exception e) {
-+                    // ignore, continue with trustAnchorInChain being false
-+                }
-+                // END android-added
-             }
-             else
-             {
-@@ -251,6 +366,15 @@
+@@ -251,6 +350,15 @@
  
          for (index = certs.size() - 1; index >= 0; index--)
          {
@@ -12132,51 +12298,9 @@
              // try
              // {
              //
-@@ -271,8 +395,10 @@
-             // 6.1.3
-             //
- 
-+            // BEGIN android-changed
-             RFC3280CertPathUtilities.processCertA(certPath, paramsPKIX, index, workingPublicKey,
--                verificationAlreadyPerformed, workingIssuerName, sign);
-+                verificationAlreadyPerformed, workingIssuerName, sign, i, trustAnchorInChain);
-+            // END android-changed
- 
-             RFC3280CertPathUtilities.processCertBC(certPath, index, nameConstraintValidator);
- 
-@@ -289,11 +415,18 @@
- 
-             if (i != n)
-             {
-+                // BEGIN android-added
-+                if (!(i == 1 && trustAnchorInChain)) // if not at the root certificate
-+                {
-+                // END android-added
-                 if (cert != null && cert.getVersion() == 1)
-                 {
-                     throw new CertPathValidatorException("Version 1 certificates can't be used as CA ones.", null,
-                             certPath, index);
-                 }
-+                // BEGIN android-added
-+                }
-+                // END android-added
- 
-                 RFC3280CertPathUtilities.prepareNextCertA(certPath, index);
- 
-@@ -317,7 +450,9 @@
-                 inhibitAnyPolicy = RFC3280CertPathUtilities.prepareNextCertJ(certPath, index, inhibitAnyPolicy);
- 
-                 // (k)
--                RFC3280CertPathUtilities.prepareNextCertK(certPath, index);
-+                // BEGIN android-changed
-+                RFC3280CertPathUtilities.prepareNextCertK(certPath, index, i, trustAnchorInChain);
-+                // END android-changed
- 
-                 // (l)
-                 maxPathLength = RFC3280CertPathUtilities.prepareNextCertL(certPath, index, maxPathLength);
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java bcprov-jdk16-145/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java	2011-09-03 18:25:17.000000000 +0000
 @@ -1533,7 +1533,9 @@
          for (Enumeration e = permitted.getObjects(); e.hasMoreElements();)
          {
@@ -12188,218 +12312,9 @@
              if (subtreesMap.get(tagNo) == null)
              {
                  subtreesMap.put(tagNo, new HashSet());
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/ProviderUtil.java bcprov-jdk16-145/org/bouncycastle/jce/provider/ProviderUtil.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/ProviderUtil.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/ProviderUtil.java	2011-09-06 19:05:42.000000000 +0000
-@@ -1,9 +1,13 @@
- package org.bouncycastle.jce.provider;
- 
- import org.bouncycastle.jce.ProviderConfigurationPermission;
--import org.bouncycastle.jce.provider.asymmetric.ec.EC5Util;
-+// BEGIN android-removed
-+// import org.bouncycastle.jce.provider.asymmetric.ec.EC5Util;
-+// END android-removed
- import org.bouncycastle.jce.interfaces.ConfigurableProvider;
--import org.bouncycastle.jce.spec.ECParameterSpec;
-+// BEGIN android-removed
-+// import org.bouncycastle.jce.spec.ECParameterSpec;
-+// END android-removed
- 
- import java.io.ByteArrayInputStream;
- import java.io.IOException;
-@@ -20,68 +24,74 @@
-                                                    "BC", ConfigurableProvider.EC_IMPLICITLY_CA);
- 
-     private static ThreadLocal threadSpec = new ThreadLocal();
--    private static volatile ECParameterSpec ecImplicitCaParams;
-+    // BEGIN android-removed
-+    // private static volatile ECParameterSpec ecImplicitCaParams;
-+    // END android-removed
- 
-     static void setParameter(String parameterName, Object parameter)
-     {
-         SecurityManager securityManager = System.getSecurityManager();
- 
--        if (parameterName.equals(ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA))
--        {
--            ECParameterSpec curveSpec;
--
--            if (securityManager != null)
--            {
--                securityManager.checkPermission(BC_EC_LOCAL_PERMISSION);
--            }
--
--            if (parameter instanceof ECParameterSpec || parameter == null)
--            {
--                curveSpec = (ECParameterSpec)parameter;
--            }
--            else  // assume java.security.spec
--            {
--                curveSpec = EC5Util.convertSpec((java.security.spec.ECParameterSpec)parameter, false);
--            }
--
--            if (curveSpec == null)
--            {
--                threadSpec.remove();
--            }
--            else
--            {
--                threadSpec.set(curveSpec);
--            }
--        }
--        else if (parameterName.equals(ConfigurableProvider.EC_IMPLICITLY_CA))
--        {
--            if (securityManager != null)
--            {
--                securityManager.checkPermission(BC_EC_PERMISSION);
--            }
--
--            if (parameter instanceof ECParameterSpec || parameter == null)
--            {
--                ecImplicitCaParams = (ECParameterSpec)parameter;
--            }
--            else  // assume java.security.spec
--            {
--                ecImplicitCaParams = EC5Util.convertSpec((java.security.spec.ECParameterSpec)parameter, false);
--            }
--        }
-+        // BEGIN android-removed
-+        // if (parameterName.equals(ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA))
-+        // {
-+        //     ECParameterSpec curveSpec;
-+        //
-+        //     if (securityManager != null)
-+        //     {
-+        //         securityManager.checkPermission(BC_EC_LOCAL_PERMISSION);
-+        //     }
-+        //
-+        //     if (parameter instanceof ECParameterSpec || parameter == null)
-+        //     {
-+        //         curveSpec = (ECParameterSpec)parameter;
-+        //     }
-+        //     else  // assume java.security.spec
-+        //     {
-+        //         curveSpec = EC5Util.convertSpec((java.security.spec.ECParameterSpec)parameter, false);
-+        //     }
-+        //
-+        //     if (curveSpec == null)
-+        //     {
-+        //         threadSpec.remove();
-+        //     }
-+        //     else
-+        //     {
-+        //         threadSpec.set(curveSpec);
-+        //     }
-+        // }
-+        // else if (parameterName.equals(ConfigurableProvider.EC_IMPLICITLY_CA))
-+        // {
-+        //     if (securityManager != null)
-+        //     {
-+        //         securityManager.checkPermission(BC_EC_PERMISSION);
-+        //     }
-+        //
-+        //     if (parameter instanceof ECParameterSpec || parameter == null)
-+        //     {
-+        //         ecImplicitCaParams = (ECParameterSpec)parameter;
-+        //     }
-+        //     else  // assume java.security.spec
-+        //     {
-+        //         ecImplicitCaParams = EC5Util.convertSpec((java.security.spec.ECParameterSpec)parameter, false);
-+        //     }
-+        // }
-+        // END android-removed
-     }
- 
--    public static ECParameterSpec getEcImplicitlyCa()
--    {
--        ECParameterSpec spec = (ECParameterSpec)threadSpec.get();
--
--        if (spec != null)
--        {
--            return spec;
--        }
--
--        return ecImplicitCaParams;
--    }
-+    // BEGIN android-removed
-+    // public static ECParameterSpec getEcImplicitlyCa()
-+    // {
-+    //     ECParameterSpec spec = (ECParameterSpec)threadSpec.get();
-+    //
-+    //     if (spec != null)
-+    //     {
-+    //         return spec;
-+    //     }
-+    //
-+    //     return ecImplicitCaParams;
-+    // }
-+    // END android-removed
- 
-     static int getReadLimit(InputStream in)
-         throws IOException
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java bcprov-jdk16-145/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java	2011-09-06 19:05:42.000000000 +0000
-@@ -1471,7 +1471,11 @@
-         PublicKey workingPublicKey,
-         boolean verificationAlreadyPerformed,
-         X500Principal workingIssuerName,
--        X509Certificate sign)
-+        X509Certificate sign,
-+        // BEGIN android-added
-+        int i, 
-+        boolean trustAnchorInChain)
-+        // END android-added
-         throws ExtCertPathValidatorException
-     {
-         List certs = certPath.getCertificates();
-@@ -1485,8 +1489,15 @@
-             {
-                 // (a) (1)
-                 //
-+                // BEGIN android-added
-+                if (!(i == 1 && trustAnchorInChain)) // if not at the root certificate
-+                {
-+                // END android-added
-                 CertPathValidatorUtilities.verifyX509Certificate(cert, workingPublicKey,
-                     paramsPKIX.getSigProvider());
-+                // BEGIN android-added
-+                }
-+                // END android-added
-             }
-             catch (GeneralSecurityException e)
-             {
-@@ -2077,7 +2088,11 @@
- 
-     protected static void prepareNextCertK(
-         CertPath certPath,
--        int index)
-+        int index,
-+        // BEGIN android-added
-+        int i, 
-+        boolean trustAnchorInChain)
-+        // END android-added
-         throws CertPathValidatorException
-     {
-         List certs = certPath.getCertificates();
-@@ -2105,7 +2120,14 @@
-         }
-         else
-         {
-+            // BEGIN android-added
-+            if (!(i == 1 && trustAnchorInChain)) // if not at the root certificate
-+            {
-+            // END android-added
-             throw new CertPathValidatorException("Intermediate certificate lacks BasicConstraints");
-+            // BEGIN android-added
-+            }
-+            // END android-added
-         }
-     }
- 
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/WrapCipherSpi.java bcprov-jdk16-145/org/bouncycastle/jce/provider/WrapCipherSpi.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/WrapCipherSpi.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/WrapCipherSpi.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/WrapCipherSpi.java	2011-09-03 18:25:17.000000000 +0000
 @@ -12,8 +12,10 @@
  import org.bouncycastle.crypto.Wrapper;
  import org.bouncycastle.crypto.engines.DESedeEngine;
@@ -12474,37 +12389,24 @@
      {
          byte[] encoded;
          try
-@@ -354,15 +368,20 @@
- 
-                 DERObjectIdentifier  oid = in.getAlgorithmId().getObjectId();
- 
--                if (oid.equals(X9ObjectIdentifiers.id_ecPublicKey))
--                {
--                    privKey = new JCEECPrivateKey(in);
--                }
+@@ -358,10 +372,12 @@
+                 {
+                     privKey = new JCEECPrivateKey(in);
+                 }
 -                else if (oid.equals(CryptoProObjectIdentifiers.gostR3410_94))
 -                {
 -                    privKey = new JDKGOST3410PrivateKey(in);
 -                }
--                else if (oid.equals(X9ObjectIdentifiers.id_dsa))
 +                // BEGIN android-removed
-+                // if (oid.equals(X9ObjectIdentifiers.id_ecPublicKey))
-+                // {
-+                //     privKey = new JCEECPrivateKey(in);
-+                // }
 +                // else if (oid.equals(CryptoProObjectIdentifiers.gostR3410_94))
 +                // {
 +                //     privKey = new JDKGOST3410PrivateKey(in);
 +                // }
-+                // else if (oid.equals(X9ObjectIdentifiers.id_dsa))
 +                // END android-removed
-+                // BEGIN android-added
-+                if (oid.equals(X9ObjectIdentifiers.id_dsa))
-+                // END android-added
+                 else if (oid.equals(X9ObjectIdentifiers.id_dsa))
                  {
                      privKey = new JDKDSAPrivateKey(in);
-                 }
-@@ -405,10 +424,12 @@
+@@ -405,10 +421,12 @@
              {
                  throw new InvalidKeyException("Unknown key type " + e.getMessage());
              }
@@ -12521,7 +12423,7 @@
              catch (InvalidKeySpecException e2)
              {
                  throw new InvalidKeyException("Unknown key type " + e2.getMessage());
-@@ -433,21 +454,23 @@
+@@ -433,21 +451,23 @@
          }
      }
  
@@ -12564,7 +12466,7 @@
  }
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/X509CertificateObject.java bcprov-jdk16-145/org/bouncycastle/jce/provider/X509CertificateObject.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/X509CertificateObject.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/X509CertificateObject.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/X509CertificateObject.java	2011-09-03 18:25:17.000000000 +0000
 @@ -518,12 +518,20 @@
          return JDKKeyFactory.createPublicKeyFromPublicKeyInfo(c.getSubjectPublicKeyInfo());
      }
@@ -12598,7 +12500,7 @@
              signature = Signature.getInstance(sigName, "BC");
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/X509SignatureUtil.java bcprov-jdk16-145/org/bouncycastle/jce/provider/X509SignatureUtil.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/X509SignatureUtil.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/X509SignatureUtil.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/X509SignatureUtil.java	2011-09-03 18:25:17.000000000 +0000
 @@ -25,7 +25,9 @@
  
  class X509SignatureUtil
@@ -12689,9 +12591,938 @@
          else
          {
              return digestAlgOID.getId();            
+diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/asymmetric/ECMappings.java bcprov-jdk16-145/org/bouncycastle/jce/provider/asymmetric/ECMappings.java
+--- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/asymmetric/ECMappings.java	2010-01-11 21:46:14.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/asymmetric/ECMappings.java	2011-09-03 18:25:17.000000000 +0000
+@@ -4,8 +4,10 @@
+ 
+ import org.bouncycastle.asn1.DERObjectIdentifier;
+ import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+-import org.bouncycastle.asn1.eac.EACObjectIdentifiers;
+-import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
++// BEGIN android-removed
++// import org.bouncycastle.asn1.eac.EACObjectIdentifiers;
++// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
++// END android-removed
+ import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+ 
+ public class ECMappings
+@@ -14,39 +16,49 @@
+     public ECMappings()
+     {
+         put("KeyAgreement.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DH");
+-        put("KeyAgreement.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DHC");
+-        put("KeyAgreement.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$MQV");
+-        put("KeyAgreement." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DHwithSHA1KDF");
+-        put("KeyAgreement." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$MQVwithSHA1KDF");
++        // BEGIN android-removed
++        // put("KeyAgreement.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DHC");
++        // put("KeyAgreement.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$MQV");
++        // put("KeyAgreement." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DHwithSHA1KDF");
++        // put("KeyAgreement." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$MQVwithSHA1KDF");
++        // END android-removed
+ 
+         put("KeyFactory.EC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$EC");
+-        put("KeyFactory.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDSA");
+-        put("KeyFactory.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDH");
+-        put("KeyFactory.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDHC");
+-        put("KeyFactory.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECMQV");
++        // BEGIN android-removed
++        // put("KeyFactory.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDSA");
++        // put("KeyFactory.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDH");
++        // put("KeyFactory.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDHC");
++        // put("KeyFactory.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECMQV");
++        // END android-removed
+         put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.id_ecPublicKey, "EC");
+         // TODO Should this be an alias for ECDH?
+         put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC");
+-        put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV");
++        // BEGIN android-removed
++        // put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV");
+ 
+-        put("KeyFactory.ECGOST3410", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECGOST3410");
+-        put("Alg.Alias.KeyFactory.GOST-3410-2001", "ECGOST3410");
+-        put("Alg.Alias.KeyFactory.ECGOST-3410", "ECGOST3410");
+-        put("Alg.Alias.KeyFactory." + CryptoProObjectIdentifiers.gostR3410_2001, "ECGOST3410");
++        // put("KeyFactory.ECGOST3410", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECGOST3410");
++        // put("Alg.Alias.KeyFactory.GOST-3410-2001", "ECGOST3410");
++        // put("Alg.Alias.KeyFactory.ECGOST-3410", "ECGOST3410");
++        // put("Alg.Alias.KeyFactory." + CryptoProObjectIdentifiers.gostR3410_2001, "ECGOST3410");
++        // END android-removed
+ 
+         put("KeyPairGenerator.EC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$EC");
+-        put("KeyPairGenerator.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDSA");
+-        put("KeyPairGenerator.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDH");
+-        put("KeyPairGenerator.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDHC");
+-        put("KeyPairGenerator.ECIES", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDH");
+-        put("KeyPairGenerator.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECMQV");
++        // BEGIN android-removed
++        // put("KeyPairGenerator.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDSA");
++        // put("KeyPairGenerator.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDH");
++        // put("KeyPairGenerator.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDHC");
++        // put("KeyPairGenerator.ECIES", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDH");
++        // put("KeyPairGenerator.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECMQV");
++        // END android-removed
+         // TODO Should this be an alias for ECDH?
+         put("Alg.Alias.KeyPairGenerator." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC");
+-        put("Alg.Alias.KeyPairGenerator." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV");
++        // BEGIN android-removed
++        // put("Alg.Alias.KeyPairGenerator." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV");
+ 
+-        put("KeyPairGenerator.ECGOST3410", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECGOST3410");
+-        put("Alg.Alias.KeyPairGenerator.ECGOST-3410", "ECGOST3410");
+-        put("Alg.Alias.KeyPairGenerator.GOST-3410-2001", "ECGOST3410");
++        // put("KeyPairGenerator.ECGOST3410", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECGOST3410");
++        // put("Alg.Alias.KeyPairGenerator.ECGOST-3410", "ECGOST3410");
++        // put("Alg.Alias.KeyPairGenerator.GOST-3410-2001", "ECGOST3410");
++        // END android-removed
+ 
+         put("Signature.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA");
+         put("Signature.NONEwithECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSAnone");
+@@ -58,23 +70,27 @@
+         put("Alg.Alias.Signature.SHA1WithECDSA", "ECDSA");
+         put("Alg.Alias.Signature.ECDSAWithSHA1", "ECDSA");
+         put("Alg.Alias.Signature.1.2.840.10045.4.1", "ECDSA");
+-        put("Alg.Alias.Signature." + TeleTrusTObjectIdentifiers.ecSignWithSha1, "ECDSA");
++        // BEGIN android-removed
++        // put("Alg.Alias.Signature." + TeleTrusTObjectIdentifiers.ecSignWithSha1, "ECDSA");
+ 
+-        addSignatureAlgorithm("SHA224", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA224", X9ObjectIdentifiers.ecdsa_with_SHA224);
++        // addSignatureAlgorithm("SHA224", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA224", X9ObjectIdentifiers.ecdsa_with_SHA224);
++        // END android-removed
+         addSignatureAlgorithm("SHA256", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA256", X9ObjectIdentifiers.ecdsa_with_SHA256);
+         addSignatureAlgorithm("SHA384", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA384", X9ObjectIdentifiers.ecdsa_with_SHA384);
+         addSignatureAlgorithm("SHA512", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA512", X9ObjectIdentifiers.ecdsa_with_SHA512);
+-        addSignatureAlgorithm("RIPEMD160", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSARipeMD160",TeleTrusTObjectIdentifiers.ecSignWithRipemd160);
++        // BEGIN android-removed
++        // addSignatureAlgorithm("RIPEMD160", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSARipeMD160",TeleTrusTObjectIdentifiers.ecSignWithRipemd160);
+ 
+-        put("Signature.SHA1WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR");
+-        put("Signature.SHA224WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR224");
+-        put("Signature.SHA256WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR256");
+-        put("Signature.SHA384WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR384");
+-        put("Signature.SHA512WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR512");
+-
+-        addSignatureAlgorithm("SHA1", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1);
+-        addSignatureAlgorithm("SHA224", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA224", EACObjectIdentifiers.id_TA_ECDSA_SHA_224);
+-        addSignatureAlgorithm("SHA256", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA256", EACObjectIdentifiers.id_TA_ECDSA_SHA_256);
++        // put("Signature.SHA1WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR");
++        // put("Signature.SHA224WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR224");
++        // put("Signature.SHA256WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR256");
++        // put("Signature.SHA384WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR384");
++        // put("Signature.SHA512WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR512");
++
++        // addSignatureAlgorithm("SHA1", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1);
++        // addSignatureAlgorithm("SHA224", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA224", EACObjectIdentifiers.id_TA_ECDSA_SHA_224);
++        // addSignatureAlgorithm("SHA256", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA256", EACObjectIdentifiers.id_TA_ECDSA_SHA_256);
++        // END android-removed
+     }
+ 
+     private void addSignatureAlgorithm(
+diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/asymmetric/ec/ECUtil.java bcprov-jdk16-145/org/bouncycastle/jce/provider/asymmetric/ec/ECUtil.java
+--- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/asymmetric/ec/ECUtil.java	2010-01-11 21:46:14.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/asymmetric/ec/ECUtil.java	2011-09-03 18:25:17.000000000 +0000
+@@ -1,10 +1,14 @@
+ package org.bouncycastle.jce.provider.asymmetric.ec;
+ 
+ import org.bouncycastle.asn1.DERObjectIdentifier;
+-import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
++// BEGIN android-removed
++// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
++// END android-removed
+ import org.bouncycastle.asn1.nist.NISTNamedCurves;
+ import org.bouncycastle.asn1.sec.SECNamedCurves;
+-import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
++// BEGIN android-removed
++// import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
++// END android-removed
+ import org.bouncycastle.asn1.x9.X962NamedCurves;
+ import org.bouncycastle.asn1.x9.X9ECParameters;
+ import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+@@ -167,14 +171,16 @@
+             {
+                 oid = NISTNamedCurves.getOID(name);
+             }
+-            if (oid == null)
+-            {
+-                oid = TeleTrusTNamedCurves.getOID(name);
+-            }
+-            if (oid == null)
+-            {
+-                oid = ECGOST3410NamedCurves.getOID(name);
+-            }
++            // BEGIN android-removed
++            // if (oid == null)
++            // {
++            //     oid = TeleTrusTNamedCurves.getOID(name);
++            // }
++            // if (oid == null)
++            // {
++            //     oid = ECGOST3410NamedCurves.getOID(name);
++            // }
++            // END android-removed
+         }
+ 
+         return oid;
+@@ -192,10 +198,12 @@
+             {
+                 params = NISTNamedCurves.getByOID(oid);
+             }
+-            if (params == null)
+-            {
+-                params = TeleTrusTNamedCurves.getByOID(oid);
+-            }
++            // BEGIN android-removed
++            // if (params == null)
++            // {
++            //     params = TeleTrusTNamedCurves.getByOID(oid);
++            // }
++            // END android-removed
+         }
+ 
+         return params;
+@@ -213,14 +221,16 @@
+             {
+                 name = NISTNamedCurves.getName(oid);
+             }
+-            if (name == null)
+-            {
+-                name = TeleTrusTNamedCurves.getName(oid);
+-            }
+-            if (name == null)
+-            {
+-                name = ECGOST3410NamedCurves.getName(oid);
+-            }
++            // BEGIN android-removed
++            // if (name == null)
++            // {
++            //     name = TeleTrusTNamedCurves.getName(oid);
++            // }
++            // if (name == null)
++            // {
++            //     name = ECGOST3410NamedCurves.getName(oid);
++            // }
++            // END android-removed
+         }
+ 
+         return name;
+diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java bcprov-jdk16-145/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java
+--- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java	2010-01-11 21:46:14.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java	2011-09-03 18:25:17.000000000 +0000
+@@ -24,20 +24,26 @@
+ import org.bouncycastle.crypto.CipherParameters;
+ import org.bouncycastle.crypto.DerivationFunction;
+ import org.bouncycastle.crypto.agreement.ECDHBasicAgreement;
+-import org.bouncycastle.crypto.agreement.ECDHCBasicAgreement;
+-import org.bouncycastle.crypto.agreement.ECMQVBasicAgreement;
+-import org.bouncycastle.crypto.agreement.kdf.DHKDFParameters;
+-import org.bouncycastle.crypto.agreement.kdf.ECDHKEKGenerator;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.agreement.ECDHCBasicAgreement;
++// import org.bouncycastle.crypto.agreement.ECMQVBasicAgreement;
++// import org.bouncycastle.crypto.agreement.kdf.DHKDFParameters;
++// import org.bouncycastle.crypto.agreement.kdf.ECDHKEKGenerator;
++// END android-removed
+ import org.bouncycastle.crypto.digests.SHA1Digest;
+ import org.bouncycastle.crypto.params.ECDomainParameters;
+ import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+ import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+-import org.bouncycastle.crypto.params.MQVPrivateParameters;
+-import org.bouncycastle.crypto.params.MQVPublicParameters;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.params.MQVPrivateParameters;
++// import org.bouncycastle.crypto.params.MQVPublicParameters;
++// END android-removed
+ import org.bouncycastle.jce.interfaces.ECPrivateKey;
+ import org.bouncycastle.jce.interfaces.ECPublicKey;
+-import org.bouncycastle.jce.interfaces.MQVPrivateKey;
+-import org.bouncycastle.jce.interfaces.MQVPublicKey;
++// BEGIN android-removed
++// import org.bouncycastle.jce.interfaces.MQVPrivateKey;
++// import org.bouncycastle.jce.interfaces.MQVPublicKey;
++// END android-removed
+ 
+ /**
+  * Diffie-Hellman key agreement using elliptic curve keys, ala IEEE P1363
+@@ -70,7 +76,9 @@
+     private BigInteger             result;
+     private ECDomainParameters     parameters;
+     private BasicAgreement         agreement;
+-    private DerivationFunction     kdf;
++    // BEGIN android-removed
++    // private DerivationFunction     kdf;
++    // END android-removed
+ 
+     private byte[] bigIntToBytes(
+         BigInteger    r)
+@@ -85,7 +93,9 @@
+     {
+         this.kaAlgorithm = kaAlgorithm;
+         this.agreement = agreement;
+-        this.kdf = kdf;
++        // BEGIN android-removed
++        // this.kdf = kdf;
++        // END android-removed
+     }
+ 
+     protected Key engineDoPhase(
+@@ -104,25 +114,27 @@
+         }
+ 
+         CipherParameters pubKey;        
+-        if (agreement instanceof ECMQVBasicAgreement)
+-        {
+-            if (!(key instanceof MQVPublicKey))
+-            {
+-                throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+-                    + getSimpleName(MQVPublicKey.class) + " for doPhase");
+-            }
+-
+-            MQVPublicKey mqvPubKey = (MQVPublicKey)key;
+-            ECPublicKeyParameters staticKey = (ECPublicKeyParameters)
+-                ECUtil.generatePublicKeyParameter(mqvPubKey.getStaticKey());
+-            ECPublicKeyParameters ephemKey = (ECPublicKeyParameters)
+-                ECUtil.generatePublicKeyParameter(mqvPubKey.getEphemeralKey());
+-
+-            pubKey = new MQVPublicParameters(staticKey, ephemKey);
+-
+-            // TODO Validate that all the keys are using the same parameters?
+-        }
+-        else
++        // BEGIN android-removed
++        // if (agreement instanceof ECMQVBasicAgreement)
++        // {
++        //     if (!(key instanceof MQVPublicKey))
++        //     {
++        //         throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
++        //             + getSimpleName(MQVPublicKey.class) + " for doPhase");
++        //     }
++        //
++        //     MQVPublicKey mqvPubKey = (MQVPublicKey)key;
++        //     ECPublicKeyParameters staticKey = (ECPublicKeyParameters)
++        //         ECUtil.generatePublicKeyParameter(mqvPubKey.getStaticKey());
++        //     ECPublicKeyParameters ephemKey = (ECPublicKeyParameters)
++        //         ECUtil.generatePublicKeyParameter(mqvPubKey.getEphemeralKey());
++        //
++        //     pubKey = new MQVPublicParameters(staticKey, ephemKey);
++        //
++        //     // TODO Validate that all the keys are using the same parameters?
++        // }
++        // else
++        // END android-removed
+         {
+             if (!(key instanceof ECPublicKey))
+             {
+@@ -143,11 +155,13 @@
+     protected byte[] engineGenerateSecret()
+         throws IllegalStateException
+     {
+-        if (kdf != null)
+-        {
+-            throw new UnsupportedOperationException(
+-                "KDF can only be used when algorithm is known");
+-        }
++        // BEGIN android-removed
++        // if (kdf != null)
++        // {
++        //     throw new UnsupportedOperationException(
++        //         "KDF can only be used when algorithm is known");
++        // }
++        // END android-removed
+ 
+         return bigIntToBytes(result);
+     }
+@@ -175,23 +189,25 @@
+     {
+         byte[] secret = bigIntToBytes(result);
+ 
+-        if (kdf != null)
+-        {
+-            if (!algorithms.containsKey(algorithm))
+-            {
+-                throw new NoSuchAlgorithmException("unknown algorithm encountered: " + algorithm);
+-            }
+-            
+-            int    keySize = ((Integer)algorithms.get(algorithm)).intValue();
+-
+-            DHKDFParameters params = new DHKDFParameters(new DERObjectIdentifier(algorithm), keySize, secret);
+-
+-            byte[] keyBytes = new byte[keySize / 8];
+-            kdf.init(params);
+-            kdf.generateBytes(keyBytes, 0, keyBytes.length);
+-            secret = keyBytes;
+-        }
+-        else
++        // BEGIN android-removed
++        // if (kdf != null)
++        // {
++        //     if (!algorithms.containsKey(algorithm))
++        //     {
++        //         throw new NoSuchAlgorithmException("unknown algorithm encountered: " + algorithm);
++        //     }
++        //  
++        //     int    keySize = ((Integer)algorithms.get(algorithm)).intValue();
++        //
++        //     DHKDFParameters params = new DHKDFParameters(new DERObjectIdentifier(algorithm), keySize, secret);
++        //
++        //     byte[] keyBytes = new byte[keySize / 8];
++        //     kdf.init(params);
++        //     kdf.generateBytes(keyBytes, 0, keyBytes.length);
++        //     secret = keyBytes;
++        // }
++        // else
++        // END android-removed
+         {
+             // TODO Should we be ensuring the key is the right length?
+         }
+@@ -219,35 +235,37 @@
+     private void initFromKey(Key key)
+         throws InvalidKeyException
+     {
+-        if (agreement instanceof ECMQVBasicAgreement)
+-        {
+-            if (!(key instanceof MQVPrivateKey))
+-            {
+-                throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+-                    + getSimpleName(MQVPrivateKey.class) + " for initialisation");
+-            }
+-
+-            MQVPrivateKey mqvPrivKey = (MQVPrivateKey)key;
+-            ECPrivateKeyParameters staticPrivKey = (ECPrivateKeyParameters)
+-                ECUtil.generatePrivateKeyParameter(mqvPrivKey.getStaticPrivateKey());
+-            ECPrivateKeyParameters ephemPrivKey = (ECPrivateKeyParameters)
+-                ECUtil.generatePrivateKeyParameter(mqvPrivKey.getEphemeralPrivateKey());
+-
+-            ECPublicKeyParameters ephemPubKey = null;
+-            if (mqvPrivKey.getEphemeralPublicKey() != null)
+-            {
+-                ephemPubKey = (ECPublicKeyParameters)
+-                    ECUtil.generatePublicKeyParameter(mqvPrivKey.getEphemeralPublicKey());
+-            }
+-
+-            MQVPrivateParameters localParams = new MQVPrivateParameters(staticPrivKey, ephemPrivKey, ephemPubKey);
+-            this.parameters = staticPrivKey.getParameters();
+-
+-            // TODO Validate that all the keys are using the same parameters?
+-
+-            agreement.init(localParams);
+-        }
+-        else
++        // BEGIN android-removed
++        // if (agreement instanceof ECMQVBasicAgreement)
++        // {
++        //     if (!(key instanceof MQVPrivateKey))
++        //     {
++        //         throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
++        //             + getSimpleName(MQVPrivateKey.class) + " for initialisation");
++        //     }
++        //
++        //     MQVPrivateKey mqvPrivKey = (MQVPrivateKey)key;
++        //     ECPrivateKeyParameters staticPrivKey = (ECPrivateKeyParameters)
++        //         ECUtil.generatePrivateKeyParameter(mqvPrivKey.getStaticPrivateKey());
++        //     ECPrivateKeyParameters ephemPrivKey = (ECPrivateKeyParameters)
++        //         ECUtil.generatePrivateKeyParameter(mqvPrivKey.getEphemeralPrivateKey());
++        //
++        //     ECPublicKeyParameters ephemPubKey = null;
++        //     if (mqvPrivKey.getEphemeralPublicKey() != null)
++        //     {
++        //         ephemPubKey = (ECPublicKeyParameters)
++        //             ECUtil.generatePublicKeyParameter(mqvPrivKey.getEphemeralPublicKey());
++        //     }
++        //
++        //     MQVPrivateParameters localParams = new MQVPrivateParameters(staticPrivKey, ephemPrivKey, ephemPubKey);
++        //     this.parameters = staticPrivKey.getParameters();
++        //
++        //     // TODO Validate that all the keys are using the same parameters?
++        //
++        //     agreement.init(localParams);
++        // }
++        // else
++        // END android-removed
+         {
+             if (!(key instanceof ECPrivateKey))
+             {
+@@ -278,39 +296,41 @@
+         }
+     }
+ 
+-    public static class DHC
+-        extends KeyAgreement
+-    {
+-        public DHC()
+-        {
+-            super("ECDHC", new ECDHCBasicAgreement(), null);
+-        }
+-    }
+-
+-    public static class MQV
+-        extends KeyAgreement
+-    {
+-        public MQV()
+-        {
+-            super("ECMQV", new ECMQVBasicAgreement(), null);
+-        }
+-    }
+-
+-    public static class DHwithSHA1KDF
+-        extends KeyAgreement
+-    {
+-        public DHwithSHA1KDF()
+-        {
+-            super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
+-        }
+-    }
+-
+-    public static class MQVwithSHA1KDF
+-        extends KeyAgreement
+-    {
+-        public MQVwithSHA1KDF()
+-        {
+-            super("ECMQVwithSHA1KDF", new ECMQVBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
+-        }
+-    }
++    // BEGIN android-removed
++    // public static class DHC
++    //     extends KeyAgreement
++    // {
++    //     public DHC()
++    //     {
++    //         super("ECDHC", new ECDHCBasicAgreement(), null);
++    //     }
++    // }
++    //
++    // public static class MQV
++    //     extends KeyAgreement
++    // {
++    //     public MQV()
++    //     {
++    //         super("ECMQV", new ECMQVBasicAgreement(), null);
++    //     }
++    // }
++    //
++    // public static class DHwithSHA1KDF
++    //     extends KeyAgreement
++    // {
++    //     public DHwithSHA1KDF()
++    //     {
++    //         super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
++    //     }
++    // }
++    //
++    // public static class MQVwithSHA1KDF
++    //     extends KeyAgreement
++    // {
++    //     public MQVwithSHA1KDF()
++    //     {
++    //         super("ECMQVwithSHA1KDF", new ECMQVBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
++    //     }
++    // }
++    // END android-removed
+ }
+diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java bcprov-jdk16-145/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java
+--- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java	2010-01-11 21:46:14.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java	2011-09-03 18:25:17.000000000 +0000
+@@ -10,10 +10,14 @@
+ import java.util.Hashtable;
+ 
+ import org.bouncycastle.asn1.DERObjectIdentifier;
+-import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
++// BEGIN android-removed
++// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
++// END android-removed
+ import org.bouncycastle.asn1.nist.NISTNamedCurves;
+ import org.bouncycastle.asn1.sec.SECNamedCurves;
+-import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
++// BEGIN android-removed
++// import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
++// END android-removed
+ import org.bouncycastle.asn1.x9.X962NamedCurves;
+ import org.bouncycastle.asn1.x9.X9ECParameters;
+ import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+@@ -83,7 +87,13 @@
+             SecureRandom    random)
+         {
+             this.strength = strength;
++            // BEGIN android-added
++            if (random != null) {
++            // END android-added
+             this.random = random;
++            // BEGIN android-added
++            }
++            // END android-added
+             this.ecParams = ecParameters.get(new Integer(strength));
+ 
+             if (ecParams != null)
+@@ -108,6 +118,11 @@
+             SecureRandom            random)
+             throws InvalidAlgorithmParameterException
+         {
++            // BEGIN android-added
++            if (random == null) {
++                random = this.random;
++            }
++            // END android-added
+             if (params instanceof ECParameterSpec)
+             {
+                 ECParameterSpec p = (ECParameterSpec)params;
+@@ -135,23 +150,25 @@
+             {
+                 final String curveName = ((ECGenParameterSpec)params).getName();
+ 
+-                if (this.algorithm.equals("ECGOST3410"))
+-                {
+-                    ECDomainParameters  ecP = ECGOST3410NamedCurves.getByName(curveName);
+-                    if (ecP == null)
+-                    {
+-                        throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName);
+-                    }
+-
+-                    this.ecParams = new ECNamedCurveSpec(
+-                                                    curveName,
+-                                                    ecP.getCurve(),
+-                                                    ecP.getG(),
+-                                                    ecP.getN(),
+-                                                    ecP.getH(),
+-                                                    ecP.getSeed());
+-                }
+-                else
++                // BEGIN android-removed
++                // if (this.algorithm.equals("ECGOST3410"))
++                // {
++                //     ECDomainParameters  ecP = ECGOST3410NamedCurves.getByName(curveName);
++                //     if (ecP == null)
++                //     {
++                //         throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName);
++                //     }
++                //
++                //     this.ecParams = new ECNamedCurveSpec(
++                //                                     curveName,
++                //                                     ecP.getCurve(),
++                //                                     ecP.getG(),
++                //                                     ecP.getN(),
++                //                                     ecP.getH(),
++                //                                     ecP.getSeed());
++                // }
++                // else
++                // END android-removed
+                 {
+                     X9ECParameters  ecP = X962NamedCurves.getByName(curveName);
+                     if (ecP == null)
+@@ -161,10 +178,12 @@
+                         {
+                             ecP = NISTNamedCurves.getByName(curveName);
+                         }
+-                        if (ecP == null)
+-                        {
+-                            ecP = TeleTrusTNamedCurves.getByName(curveName);
+-                        }
++                        // BEGIN android-removed
++                        // if (ecP == null)
++                        // {
++                        //     ecP = TeleTrusTNamedCurves.getByName(curveName);
++                        // }
++                        // END android-removed
+                         if (ecP == null)
+                         {
+                             // See if it's actually an OID string (SunJSSE ServerHandshaker setupEphemeralECDHKeys bug)
+@@ -180,10 +199,12 @@
+                                 {
+                                     ecP = NISTNamedCurves.getByOID(oid);
+                                 }
+-                                if (ecP == null)
+-                                {
+-                                    ecP = TeleTrusTNamedCurves.getByOID(oid);
+-                                }
++                                // BEGIN android-removed
++                                // if (ecP == null)
++                                // {
++                                //     ecP = TeleTrusTNamedCurves.getByOID(oid);
++                                // }
++                                // END android-removed
+                                 if (ecP == null)
+                                 {
+                                     throw new InvalidAlgorithmParameterException("unknown curve OID: " + curveName);
+@@ -239,7 +260,15 @@
+         {
+             if (!initialised)
+             {
+-                throw new IllegalStateException("EC Key Pair Generator not initialised");
++                // BEGIN android-removed
++                // throw new IllegalStateException("EC Key Pair Generator not initialised");
++                // END android-removed
++                // BEGIN android-added
++                /*
++                 * KeyPairGenerator documentation says that a default initialization must be provided
++                 */
++                initialize(192, random);
++                // END android-added
+             }
+ 
+             AsymmetricCipherKeyPair     pair = engine.generateKeyPair();
+@@ -279,14 +308,16 @@
+         }
+     }
+ 
+-    public static class ECGOST3410
+-        extends EC
+-    {
+-        public ECGOST3410()
+-        {
+-            super("ECGOST3410");
+-        }
+-    }
++    // BEGIN android-removed
++    // public static class ECGOST3410
++    //     extends EC
++    // {
++    //     public ECGOST3410()
++    //     {
++    //         super("ECGOST3410");
++    //     }
++    // }
++    // END android-removed
+ 
+     public static class ECDH
+         extends EC
+@@ -314,4 +345,4 @@
+             super("ECMQV");
+         }
+     }
+-}
+\ No newline at end of file
++}
+diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java bcprov-jdk16-145/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java
+--- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java	2010-01-11 21:46:14.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java	2011-09-03 18:25:17.000000000 +0000
+@@ -18,15 +18,21 @@
+ import org.bouncycastle.crypto.CipherParameters;
+ import org.bouncycastle.crypto.DSA;
+ import org.bouncycastle.crypto.Digest;
+-import org.bouncycastle.crypto.digests.RIPEMD160Digest;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
++// END android-removed
+ import org.bouncycastle.crypto.digests.SHA1Digest;
+-import org.bouncycastle.crypto.digests.SHA224Digest;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.digests.SHA224Digest;
++// END android-removed
+ import org.bouncycastle.crypto.digests.SHA256Digest;
+ import org.bouncycastle.crypto.digests.SHA384Digest;
+ import org.bouncycastle.crypto.digests.SHA512Digest;
+ import org.bouncycastle.crypto.params.ParametersWithRandom;
+ import org.bouncycastle.crypto.signers.ECDSASigner;
+-import org.bouncycastle.crypto.signers.ECNRSigner;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.signers.ECNRSigner;
++// END android-removed
+ import org.bouncycastle.jce.interfaces.ECKey;
+ import org.bouncycastle.jce.provider.DSABase;
+ import org.bouncycastle.jce.provider.DSAEncoder;
+@@ -123,14 +129,16 @@
+         }
+     }
+ 
+-    static public class ecDSA224
+-        extends Signature
+-    {
+-        public ecDSA224()
+-        {
+-            super(new SHA224Digest(), new ECDSASigner(), new StdDSAEncoder());
+-        }
+-    }
++    // BEGIN android-removed
++    // static public class ecDSA224
++    //     extends Signature
++    // {
++    //     public ecDSA224()
++    //     {
++    //         super(new SHA224Digest(), new ECDSASigner(), new StdDSAEncoder());
++    //     }
++    // }
++    // END android-removed
+ 
+     static public class ecDSA256
+         extends Signature
+@@ -159,86 +167,88 @@
+         }
+     }
+ 
+-    static public class ecDSARipeMD160
+-        extends Signature
+-    {
+-        public ecDSARipeMD160()
+-        {
+-            super(new RIPEMD160Digest(), new ECDSASigner(), new StdDSAEncoder());
+-        }
+-    }
+-
+-    static public class ecNR
+-        extends Signature
+-    {
+-        public ecNR()
+-        {
+-            super(new SHA1Digest(), new ECNRSigner(), new StdDSAEncoder());
+-        }
+-    }
+-
+-    static public class ecNR224
+-        extends Signature
+-    {
+-        public ecNR224()
+-        {
+-            super(new SHA224Digest(), new ECNRSigner(), new StdDSAEncoder());
+-        }
+-    }
+-
+-    static public class ecNR256
+-        extends Signature
+-    {
+-        public ecNR256()
+-        {
+-            super(new SHA256Digest(), new ECNRSigner(), new StdDSAEncoder());
+-        }
+-    }
+-
+-    static public class ecNR384
+-        extends Signature
+-    {
+-        public ecNR384()
+-        {
+-            super(new SHA384Digest(), new ECNRSigner(), new StdDSAEncoder());
+-        }
+-    }
+-
+-    static public class ecNR512
+-        extends Signature
+-    {
+-        public ecNR512()
+-        {
+-            super(new SHA512Digest(), new ECNRSigner(), new StdDSAEncoder());
+-        }
+-    }
+-
+-    static public class ecCVCDSA
+-        extends Signature
+-    {
+-        public ecCVCDSA()
+-        {
+-            super(new SHA1Digest(), new ECDSASigner(), new CVCDSAEncoder());
+-        }
+-    }
+-
+-    static public class ecCVCDSA224
+-        extends Signature
+-    {
+-        public ecCVCDSA224()
+-        {
+-            super(new SHA224Digest(), new ECDSASigner(), new CVCDSAEncoder());
+-        }
+-    }
+-
+-    static public class ecCVCDSA256
+-        extends Signature
+-    {
+-        public ecCVCDSA256()
+-        {
+-            super(new SHA256Digest(), new ECDSASigner(), new CVCDSAEncoder());
+-        }
+-    }
++    // BEGIN android-removed
++    // static public class ecDSARipeMD160
++    //     extends Signature
++    // {
++    //     public ecDSARipeMD160()
++    //     {
++    //         super(new RIPEMD160Digest(), new ECDSASigner(), new StdDSAEncoder());
++    //     }
++    // }
++    //
++    // static public class ecNR
++    //     extends Signature
++    // {
++    //     public ecNR()
++    //     {
++    //         super(new SHA1Digest(), new ECNRSigner(), new StdDSAEncoder());
++    //     }
++    // }
++    //
++    // static public class ecNR224
++    //     extends Signature
++    // {
++    //     public ecNR224()
++    //     {
++    //         super(new SHA224Digest(), new ECNRSigner(), new StdDSAEncoder());
++    //     }
++    // }
++    //
++    // static public class ecNR256
++    //     extends Signature
++    // {
++    //     public ecNR256()
++    //     {
++    //         super(new SHA256Digest(), new ECNRSigner(), new StdDSAEncoder());
++    //     }
++    // }
++    //
++    // static public class ecNR384
++    //     extends Signature
++    // {
++    //     public ecNR384()
++    //     {
++    //         super(new SHA384Digest(), new ECNRSigner(), new StdDSAEncoder());
++    //     }
++    // }
++    //
++    // static public class ecNR512
++    //     extends Signature
++    // {
++    //     public ecNR512()
++    //     {
++    //         super(new SHA512Digest(), new ECNRSigner(), new StdDSAEncoder());
++    //     }
++    // }
++    //
++    // static public class ecCVCDSA
++    //     extends Signature
++    // {
++    //     public ecCVCDSA()
++    //     {
++    //         super(new SHA1Digest(), new ECDSASigner(), new CVCDSAEncoder());
++    //     }
++    // }
++    //
++    // static public class ecCVCDSA224
++    //     extends Signature
++    // {
++    //     public ecCVCDSA224()
++    //     {
++    //         super(new SHA224Digest(), new ECDSASigner(), new CVCDSAEncoder());
++    //     }
++    // }
++    //
++    // static public class ecCVCDSA256
++    //     extends Signature
++    // {
++    //     public ecCVCDSA256()
++    //     {
++    //         super(new SHA256Digest(), new ECDSASigner(), new CVCDSAEncoder());
++    //     }
++    // }
++    // END android-removed
+ 
+     private static class StdDSAEncoder
+         implements DSAEncoder
+@@ -332,4 +342,4 @@
+             return sig;
+         }
+     }
+-}
+\ No newline at end of file
++}
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/symmetric/AES.java bcprov-jdk16-145/org/bouncycastle/jce/provider/symmetric/AES.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/symmetric/AES.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/symmetric/AES.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/symmetric/AES.java	2011-09-03 18:25:17.000000000 +0000
 @@ -5,7 +5,9 @@
  import org.bouncycastle.crypto.engines.AESEngine;
  import org.bouncycastle.crypto.engines.AESFastEngine;
@@ -12928,7 +13759,7 @@
          extends JDKAlgorithmParameters.IVAlgorithmParameters
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/symmetric/AESMappings.java bcprov-jdk16-145/org/bouncycastle/jce/provider/symmetric/AESMappings.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/symmetric/AESMappings.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/symmetric/AESMappings.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/jce/provider/symmetric/AESMappings.java	2011-09-03 18:25:17.000000000 +0000
 @@ -26,55 +26,63 @@
          put("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
          put("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
@@ -13034,7 +13865,7 @@
  }
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/x509/X509Util.java bcprov-jdk16-145/org/bouncycastle/x509/X509Util.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/x509/X509Util.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/x509/X509Util.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/x509/X509Util.java	2011-09-03 18:25:17.000000000 +0000
 @@ -43,8 +43,10 @@
      
      static
@@ -13096,7 +13927,7 @@
      
 diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/x509/extension/X509ExtensionUtil.java bcprov-jdk16-145/org/bouncycastle/x509/extension/X509ExtensionUtil.java
 --- bcprov-jdk16-145.orig/org/bouncycastle/x509/extension/X509ExtensionUtil.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/x509/extension/X509ExtensionUtil.java	2011-09-06 19:05:42.000000000 +0000
++++ bcprov-jdk16-145/org/bouncycastle/x509/extension/X509ExtensionUtil.java	2011-09-03 18:25:17.000000000 +0000
 @@ -62,7 +62,9 @@
              {
                  GeneralName genName = GeneralName.getInstance(it.nextElement());
diff --git a/src/main/java/org/bouncycastle/asn1/nist/NISTNamedCurves.java b/src/main/java/org/bouncycastle/asn1/nist/NISTNamedCurves.java
new file mode 100644
index 0000000..821e0d1
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/nist/NISTNamedCurves.java
@@ -0,0 +1,96 @@
+package org.bouncycastle.asn1.nist;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.sec.SECNamedCurves;
+import org.bouncycastle.asn1.sec.SECObjectIdentifiers;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.util.Strings;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+/**
+ * Utility class for fetching curves using their NIST names as published in FIPS-PUB 186-2
+ */
+public class NISTNamedCurves
+{
+    static final Hashtable objIds = new Hashtable();
+    static final Hashtable names = new Hashtable();
+
+    static void defineCurve(String name, DERObjectIdentifier oid)
+    {
+        objIds.put(name, oid);
+        names.put(oid, name);
+    }
+
+    static
+    {
+        // TODO Missing the "K-" curves
+
+        defineCurve("B-571", SECObjectIdentifiers.sect571r1);
+        defineCurve("B-409", SECObjectIdentifiers.sect409r1);
+        defineCurve("B-283", SECObjectIdentifiers.sect283r1);
+        defineCurve("B-233", SECObjectIdentifiers.sect233r1);
+        defineCurve("B-163", SECObjectIdentifiers.sect163r2);
+        defineCurve("P-521", SECObjectIdentifiers.secp521r1);
+        defineCurve("P-384", SECObjectIdentifiers.secp384r1);
+        defineCurve("P-256", SECObjectIdentifiers.secp256r1);
+        defineCurve("P-224", SECObjectIdentifiers.secp224r1);
+        defineCurve("P-192", SECObjectIdentifiers.secp192r1);
+    }
+
+    public static X9ECParameters getByName(
+        String  name)
+    {
+        DERObjectIdentifier oid = (DERObjectIdentifier)objIds.get(Strings.toUpperCase(name));
+
+        if (oid != null)
+        {
+            return getByOID(oid);
+        }
+
+        return null;
+    }
+
+    /**
+     * return the X9ECParameters object for the named curve represented by
+     * the passed in object identifier. Null if the curve isn't present.
+     *
+     * @param oid an object identifier representing a named curve, if present.
+     */
+    public static X9ECParameters getByOID(
+        DERObjectIdentifier  oid)
+    {
+        return SECNamedCurves.getByOID(oid);
+    }
+
+    /**
+     * return the object identifier signified by the passed in name. Null
+     * if there is no object identifier associated with name.
+     *
+     * @return the object identifier associated with name, if present.
+     */
+    public static DERObjectIdentifier getOID(
+        String  name)
+    {
+        return (DERObjectIdentifier)objIds.get(Strings.toUpperCase(name));
+    }
+
+    /**
+     * return the named curve name represented by the given object identifier.
+     */
+    public static String getName(
+        DERObjectIdentifier  oid)
+    {
+        return (String)names.get(oid);
+    }
+
+    /**
+     * returns an enumeration containing the name strings for curves
+     * contained in this structure.
+     */
+    public static Enumeration getNames()
+    {
+        return objIds.keys();
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java b/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java
index 77c4b04..0ca629a 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java
@@ -37,10 +37,13 @@
     public static EncryptedPrivateKeyInfo getInstance(
         Object  obj)
     {
-        if (obj instanceof EncryptedData)
+        // BEGIN android-changed
+        //     fix copy and paste error in instanceof call
+        if (obj instanceof EncryptedPrivateKeyInfo)
         {
             return (EncryptedPrivateKeyInfo)obj;
         }
+        // END android-changed
         else if (obj instanceof ASN1Sequence)
         { 
             return new EncryptedPrivateKeyInfo((ASN1Sequence)obj);
diff --git a/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKeyStructure.java b/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKeyStructure.java
new file mode 100644
index 0000000..b9a0407
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKeyStructure.java
@@ -0,0 +1,128 @@
+package org.bouncycastle.asn1.sec;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.util.BigIntegers;
+
+/**
+ * the elliptic curve private key object from SEC 1
+ */
+public class ECPrivateKeyStructure
+    extends ASN1Encodable
+{
+    private ASN1Sequence  seq;
+
+    public ECPrivateKeyStructure(
+        ASN1Sequence  seq)
+    {
+        this.seq = seq;
+    }
+
+    public ECPrivateKeyStructure(
+        BigInteger  key)
+    {
+        byte[] bytes = BigIntegers.asUnsignedByteArray(key);
+
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(new DERInteger(1));
+        v.add(new DEROctetString(bytes));
+
+        seq = new DERSequence(v);
+    }
+
+    public ECPrivateKeyStructure(
+        BigInteger    key,
+        ASN1Encodable parameters)
+    {
+        this(key, null, parameters);
+    }
+
+    public ECPrivateKeyStructure(
+        BigInteger    key,
+        DERBitString  publicKey,
+        ASN1Encodable parameters)
+    {
+        byte[] bytes = BigIntegers.asUnsignedByteArray(key);
+
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(new DERInteger(1));
+        v.add(new DEROctetString(bytes));
+
+        if (parameters != null)
+        {
+            v.add(new DERTaggedObject(true, 0, parameters));
+        }
+
+        if (publicKey != null)
+        {
+            v.add(new DERTaggedObject(true, 1, publicKey));
+        }
+
+        seq = new DERSequence(v);
+    }
+
+    public BigInteger getKey()
+    {
+        ASN1OctetString  octs = (ASN1OctetString)seq.getObjectAt(1);
+
+        return new BigInteger(1, octs.getOctets());
+    }
+
+    public DERBitString getPublicKey()
+    {
+        return (DERBitString)getObjectInTag(1);
+    }
+
+    public ASN1Object getParameters()
+    {
+        return getObjectInTag(0);
+    }
+
+    private ASN1Object getObjectInTag(int tagNo)
+    {
+        Enumeration e = seq.getObjects();
+
+        while (e.hasMoreElements())
+        {
+            DEREncodable obj = (DEREncodable)e.nextElement();
+
+            if (obj instanceof ASN1TaggedObject)
+            {
+                ASN1TaggedObject tag = (ASN1TaggedObject)obj;
+                if (tag.getTagNo() == tagNo)
+                {
+                    return (ASN1Object)((DEREncodable)tag.getObject()).getDERObject();
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * ECPrivateKey ::= SEQUENCE {
+     *     version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+     *     privateKey OCTET STRING,
+     *     parameters [0] Parameters OPTIONAL,
+     *     publicKey [1] BIT STRING OPTIONAL }
+     */
+    public DERObject toASN1Object()
+    {
+        return seq;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java b/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java
new file mode 100644
index 0000000..67ead06
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java
@@ -0,0 +1,1029 @@
+package org.bouncycastle.asn1.sec;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.asn1.x9.X9ECParametersHolder;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.ec.ECConstants;
+import org.bouncycastle.util.Strings;
+import org.bouncycastle.util.encoders.Hex;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+public class SECNamedCurves
+{
+    private static BigInteger fromHex(
+        String hex)
+    {
+        return new BigInteger(1, Hex.decode(hex));
+    }
+
+    /*
+     * secp112r1
+     */
+    static X9ECParametersHolder secp112r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = (2^128 - 3) / 76439
+            BigInteger p = fromHex("DB7C2ABF62E35E668076BEAD208B");
+            BigInteger a = fromHex("DB7C2ABF62E35E668076BEAD2088");
+            BigInteger b = fromHex("659EF8BA043916EEDE8911702B22");
+            byte[] S = Hex.decode("00F50B028E4D696E676875615175290472783FB1");
+            BigInteger n = fromHex("DB7C2ABF62E35E7628DFAC6561C5");
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve curve = new ECCurve.Fp(p, a, b);
+            //ECPoint G = curve.decodePoint(Hex.decode("02"
+            //+ "09487239995A5EE76B55F9C2F098"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "09487239995A5EE76B55F9C2F098"
+                + "A89CE5AF8724C0A23E0E0FF77500"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp112r2
+     */
+    static X9ECParametersHolder secp112r2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = (2^128 - 3) / 76439
+            BigInteger p = fromHex("DB7C2ABF62E35E668076BEAD208B");
+            BigInteger a = fromHex("6127C24C05F38A0AAAF65C0EF02C");
+            BigInteger b = fromHex("51DEF1815DB5ED74FCC34C85D709");
+            byte[] S = Hex.decode("002757A1114D696E6768756151755316C05E0BD4");
+            BigInteger n = fromHex("36DF0AAFD8B8D7597CA10520D04B");
+            BigInteger h = BigInteger.valueOf(4);
+
+            ECCurve curve = new ECCurve.Fp(p, a, b);
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "4BA30AB5E892B4E1649DD0928643"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "4BA30AB5E892B4E1649DD0928643"
+                + "ADCD46F5882E3747DEF36E956E97"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp128r1
+     */
+    static X9ECParametersHolder secp128r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^128 - 2^97 - 1
+            BigInteger p = fromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF");
+            BigInteger a = fromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC");
+            BigInteger b = fromHex("E87579C11079F43DD824993C2CEE5ED3");
+            byte[] S = Hex.decode("000E0D4D696E6768756151750CC03A4473D03679");
+            BigInteger n = fromHex("FFFFFFFE0000000075A30D1B9038A115");
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve curve = new ECCurve.Fp(p, a, b);
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "161FF7528B899B2D0C28607CA52C5B86"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "161FF7528B899B2D0C28607CA52C5B86"
+                + "CF5AC8395BAFEB13C02DA292DDED7A83"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp128r2
+     */
+    static X9ECParametersHolder secp128r2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^128 - 2^97 - 1
+            BigInteger p = fromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF");
+            BigInteger a = fromHex("D6031998D1B3BBFEBF59CC9BBFF9AEE1");
+            BigInteger b = fromHex("5EEEFCA380D02919DC2C6558BB6D8A5D");
+            byte[] S = Hex.decode("004D696E67687561517512D8F03431FCE63B88F4");
+            BigInteger n = fromHex("3FFFFFFF7FFFFFFFBE0024720613B5A3");
+            BigInteger h = BigInteger.valueOf(4);
+
+            ECCurve curve = new ECCurve.Fp(p, a, b);
+            //ECPoint G = curve.decodePoint(Hex.decode("02"
+            //+ "7B6AA5D85E572983E6FB32A7CDEBC140"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "7B6AA5D85E572983E6FB32A7CDEBC140"
+                + "27B6916A894D3AEE7106FE805FC34B44"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp160k1
+     */
+    static X9ECParametersHolder secp160k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^160 - 2^32 - 2^14 - 2^12 - 2^9 - 2^8 - 2^7 - 2^3 - 2^2 - 1
+            BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73");
+            BigInteger a = ECConstants.ZERO;
+            BigInteger b = BigInteger.valueOf(7);
+            byte[] S = null;
+            BigInteger n = fromHex("0100000000000000000001B8FA16DFAB9ACA16B6B3");
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve curve = new ECCurve.Fp(p, a, b);
+//            ECPoint G = curve.decodePoint(Hex.decode("02"
+//                + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB"
+                + "938CF935318FDCED6BC28286531733C3F03C4FEE"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp160r1
+     */
+    static X9ECParametersHolder secp160r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^160 - 2^31 - 1
+            BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF");
+            BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC");
+            BigInteger b = fromHex("1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45");
+            byte[] S = Hex.decode("1053CDE42C14D696E67687561517533BF3F83345");
+            BigInteger n = fromHex("0100000000000000000001F4C8F927AED3CA752257");
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve curve = new ECCurve.Fp(p, a, b);
+            //ECPoint G = curve.decodePoint(Hex.decode("02"
+                //+ "4A96B5688EF573284664698968C38BB913CBFC82"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "4A96B5688EF573284664698968C38BB913CBFC82"
+                + "23A628553168947D59DCC912042351377AC5FB32"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp160r2
+     */
+    static X9ECParametersHolder secp160r2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^160 - 2^32 - 2^14 - 2^12 - 2^9 - 2^8 - 2^7 - 2^3 - 2^2 - 1
+            BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73");
+            BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70");
+            BigInteger b = fromHex("B4E134D3FB59EB8BAB57274904664D5AF50388BA");
+            byte[] S = Hex.decode("B99B99B099B323E02709A4D696E6768756151751");
+            BigInteger n = fromHex("0100000000000000000000351EE786A818F3A1A16B");
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve curve = new ECCurve.Fp(p, a, b);
+            //ECPoint G = curve.decodePoint(Hex.decode("02"
+            //+ "52DCB034293A117E1F4FF11B30F7199D3144CE6D"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "52DCB034293A117E1F4FF11B30F7199D3144CE6D"
+                + "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp192k1
+     */
+    static X9ECParametersHolder secp192k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^192 - 2^32 - 2^12 - 2^8 - 2^7 - 2^6 - 2^3 - 1
+            BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37");
+            BigInteger a = ECConstants.ZERO;
+            BigInteger b = BigInteger.valueOf(3);
+            byte[] S = null;
+            BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D");
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve curve = new ECCurve.Fp(p, a, b);
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"
+                + "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp192r1
+     */
+    static X9ECParametersHolder secp192r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^192 - 2^64 - 1
+            BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF");
+            BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC");
+            BigInteger b = fromHex("64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1");
+            byte[] S = Hex.decode("3045AE6FC8422F64ED579528D38120EAE12196D5");
+            BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831");
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve curve = new ECCurve.Fp(p, a, b);
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"
+                + "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp224k1
+     */
+    static X9ECParametersHolder secp224k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^224 - 2^32 - 2^12 - 2^11 - 2^9 - 2^7 - 2^4 - 2 - 1
+            BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D");
+            BigInteger a = ECConstants.ZERO;
+            BigInteger b = BigInteger.valueOf(5);
+            byte[] S = null;
+            BigInteger n = fromHex("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7");
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve curve = new ECCurve.Fp(p, a, b);
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"
+                + "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp224r1
+     */
+    static X9ECParametersHolder secp224r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^224 - 2^96 + 1
+            BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001");
+            BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE");
+            BigInteger b = fromHex("B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4");
+            byte[] S = Hex.decode("BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5");
+            BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D");
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve curve = new ECCurve.Fp(p, a, b);
+            //ECPoint G = curve.decodePoint(Hex.decode("02"
+            //+ "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"
+                + "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp256k1
+     */
+    static X9ECParametersHolder secp256k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
+            BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F");
+            BigInteger a = ECConstants.ZERO;
+            BigInteger b = BigInteger.valueOf(7);
+            byte[] S = null;
+            BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve curve = new ECCurve.Fp(p, a, b);
+            //ECPoint G = curve.decodePoint(Hex.decode("02"
+            //+ "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
+                + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp256r1
+     */
+    static X9ECParametersHolder secp256r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^224 (2^32 - 1) + 2^192 + 2^96 - 1
+            BigInteger p = fromHex("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF");
+            BigInteger a = fromHex("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC");
+            BigInteger b = fromHex("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B");
+            byte[] S = Hex.decode("C49D360886E704936A6678E1139D26B7819F7E90");
+            BigInteger n = fromHex("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551");
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve curve = new ECCurve.Fp(p, a, b);
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"
+                + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp384r1
+     */
+    static X9ECParametersHolder secp384r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^384 - 2^128 - 2^96 + 2^32 - 1
+            BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF");
+            BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC");
+            BigInteger b = fromHex("B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF");
+            byte[] S = Hex.decode("A335926AA319A27A1D00896A6773A4827ACDAC73");
+            BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973");
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve curve = new ECCurve.Fp(p, a, b);
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7"
+                + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp521r1
+     */
+    static X9ECParametersHolder secp521r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^521 - 1
+            BigInteger p = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+            BigInteger a = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC");
+            BigInteger b = fromHex("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00");
+            byte[] S = Hex.decode("D09E8800291CB85396CC6717393284AAA0DA64BA");
+            BigInteger n = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409");
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve curve = new ECCurve.Fp(p, a, b);
+            //ECPoint G = curve.decodePoint(Hex.decode("02"
+            //+ "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"
+                + "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+    
+    /*
+     * sect113r1
+     */
+    static X9ECParametersHolder sect113r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 113;
+            int k = 9;
+
+            BigInteger a = fromHex("003088250CA6E7C7FE649CE85820F7");
+            BigInteger b = fromHex("00E8BEE4D3E2260744188BE0E9C723");
+            byte[] S = Hex.decode("10E723AB14D696E6768756151756FEBF8FCB49A9");
+            BigInteger n = fromHex("0100000000000000D9CCEC8A39E56F");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "009D73616F35F4AB1407D73562C10F"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "009D73616F35F4AB1407D73562C10F"
+                + "00A52830277958EE84D1315ED31886"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect113r2
+     */
+    static X9ECParametersHolder sect113r2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 113;
+            int k = 9;
+
+            BigInteger a = fromHex("00689918DBEC7E5A0DD6DFC0AA55C7");
+            BigInteger b = fromHex("0095E9A9EC9B297BD4BF36E059184F");
+            byte[] S = Hex.decode("10C0FB15760860DEF1EEF4D696E676875615175D");
+            BigInteger n = fromHex("010000000000000108789B2496AF93");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "01A57A6A7B26CA5EF52FCDB8164797"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "01A57A6A7B26CA5EF52FCDB8164797"
+                + "00B3ADC94ED1FE674C06E695BABA1D"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect131r1
+     */
+    static X9ECParametersHolder sect131r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 131;
+            int k1 = 2;
+            int k2 = 3;
+            int k3 = 8;
+
+            BigInteger a = fromHex("07A11B09A76B562144418FF3FF8C2570B8");
+            BigInteger b = fromHex("0217C05610884B63B9C6C7291678F9D341");
+            byte[] S = Hex.decode("4D696E676875615175985BD3ADBADA21B43A97E2");
+            BigInteger n = fromHex("0400000000000000023123953A9464B54D");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "0081BAF91FDF9833C40F9C181343638399"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "0081BAF91FDF9833C40F9C181343638399"
+                + "078C6E7EA38C001F73C8134B1B4EF9E150"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect131r2
+     */
+    static X9ECParametersHolder sect131r2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 131;
+            int k1 = 2;
+            int k2 = 3;
+            int k3 = 8;
+
+            BigInteger a = fromHex("03E5A88919D7CAFCBF415F07C2176573B2");
+            BigInteger b = fromHex("04B8266A46C55657AC734CE38F018F2192");
+            byte[] S = Hex.decode("985BD3ADBAD4D696E676875615175A21B43A97E3");
+            BigInteger n = fromHex("0400000000000000016954A233049BA98F");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "0356DCD8F2F95031AD652D23951BB366A8"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "0356DCD8F2F95031AD652D23951BB366A8"
+                + "0648F06D867940A5366D9E265DE9EB240F"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect163k1
+     */
+    static X9ECParametersHolder sect163k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 163;
+            int k1 = 3;
+            int k2 = 6;
+            int k3 = 7;
+
+            BigInteger a = BigInteger.valueOf(1);
+            BigInteger b = BigInteger.valueOf(1);
+            byte[] S = null;
+            BigInteger n = fromHex("04000000000000000000020108A2E0CC0D99F8A5EF");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8"
+                + "0289070FB05D38FF58321F2E800536D538CCDAA3D9"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect163r1
+     */
+    static X9ECParametersHolder sect163r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 163;
+            int k1 = 3;
+            int k2 = 6;
+            int k3 = 7;
+
+            BigInteger a = fromHex("07B6882CAAEFA84F9554FF8428BD88E246D2782AE2");
+            BigInteger b = fromHex("0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9");
+            byte[] S = Hex.decode("24B7B137C8A14D696E6768756151756FD0DA2E5C");
+            BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "0369979697AB43897789566789567F787A7876A654"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "0369979697AB43897789566789567F787A7876A654"
+                + "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect163r2
+     */
+    static X9ECParametersHolder sect163r2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 163;
+            int k1 = 3;
+            int k2 = 6;
+            int k3 = 7;
+
+            BigInteger a = BigInteger.valueOf(1);
+            BigInteger b = fromHex("020A601907B8C953CA1481EB10512F78744A3205FD");
+            byte[] S = Hex.decode("85E25BFE5C86226CDB12016F7553F9D0E693A268");
+            BigInteger n = fromHex("040000000000000000000292FE77E70C12A4234C33");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "03F0EBA16286A2D57EA0991168D4994637E8343E36"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "03F0EBA16286A2D57EA0991168D4994637E8343E36"
+                + "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect193r1
+     */
+    static X9ECParametersHolder sect193r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 193;
+            int k = 15;
+
+            BigInteger a = fromHex("0017858FEB7A98975169E171F77B4087DE098AC8A911DF7B01");
+            BigInteger b = fromHex("00FDFB49BFE6C3A89FACADAA7A1E5BBC7CC1C2E5D831478814");
+            byte[] S = Hex.decode("103FAEC74D696E676875615175777FC5B191EF30");
+            BigInteger n = fromHex("01000000000000000000000000C7F34A778F443ACC920EBA49");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1"
+                + "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect193r2
+     */
+    static X9ECParametersHolder sect193r2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 193;
+            int k = 15;
+
+            BigInteger a = fromHex("0163F35A5137C2CE3EA6ED8667190B0BC43ECD69977702709B");
+            BigInteger b = fromHex("00C9BB9E8927D4D64C377E2AB2856A5B16E3EFB7F61D4316AE");
+            byte[] S = Hex.decode("10B7B4D696E676875615175137C8A16FD0DA2211");
+            BigInteger n = fromHex("010000000000000000000000015AAB561B005413CCD4EE99D5");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F"
+                + "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect233k1
+     */
+    static X9ECParametersHolder sect233k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 233;
+            int k = 74;
+
+            BigInteger a = ECConstants.ZERO;
+            BigInteger b = BigInteger.valueOf(1);
+            byte[] S = null;
+            BigInteger n = fromHex("8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF");
+            BigInteger h = BigInteger.valueOf(4);
+
+            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+            //ECPoint G = curve.decodePoint(Hex.decode("02"
+            //+ "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126"
+                + "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect233r1
+     */
+    static X9ECParametersHolder sect233r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 233;
+            int k = 74;
+
+            BigInteger a = BigInteger.valueOf(1);
+            BigInteger b = fromHex("0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD");
+            byte[] S = Hex.decode("74D59FF07F6B413D0EA14B344B20A2DB049B50C3");
+            BigInteger n = fromHex("01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B"
+                + "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect239k1
+     */
+    static X9ECParametersHolder sect239k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 239;
+            int k = 158;
+
+            BigInteger a = ECConstants.ZERO;
+            BigInteger b = BigInteger.valueOf(1);
+            byte[] S = null;
+            BigInteger n = fromHex("2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5");
+            BigInteger h = BigInteger.valueOf(4);
+
+            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC"
+                + "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect283k1
+     */
+    static X9ECParametersHolder sect283k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 283;
+            int k1 = 5;
+            int k2 = 7;
+            int k3 = 12;
+
+            BigInteger a = ECConstants.ZERO;
+            BigInteger b = BigInteger.valueOf(1);
+            byte[] S = null;
+            BigInteger n = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61");
+            BigInteger h = BigInteger.valueOf(4);
+
+            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);
+            //ECPoint G = curve.decodePoint(Hex.decode("02"
+            //+ "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836"
+                + "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect283r1
+     */
+    static X9ECParametersHolder sect283r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 283;
+            int k1 = 5;
+            int k2 = 7;
+            int k3 = 12;
+
+            BigInteger a = BigInteger.valueOf(1);
+            BigInteger b = fromHex("027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5");
+            byte[] S = Hex.decode("77E2B07370EB0F832A6DD5B62DFC88CD06BB84BE");
+            BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053"
+                + "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect409k1
+     */
+    static X9ECParametersHolder sect409k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 409;
+            int k = 87;
+
+            BigInteger a = ECConstants.ZERO;
+            BigInteger b = BigInteger.valueOf(1);
+            byte[] S = null;
+            BigInteger n = fromHex("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF");
+            BigInteger h = BigInteger.valueOf(4);
+
+            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746"
+                + "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect409r1
+     */
+    static X9ECParametersHolder sect409r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 409;
+            int k = 87;
+
+            BigInteger a = BigInteger.valueOf(1);
+            BigInteger b = fromHex("0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F");
+            byte[] S = Hex.decode("4099B5A457F9D69F79213D094C4BCD4D4262210B");
+            BigInteger n = fromHex("010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7"
+                + "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect571k1
+     */
+    static X9ECParametersHolder sect571k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 571;
+            int k1 = 2;
+            int k2 = 5;
+            int k3 = 10;
+
+            BigInteger a = ECConstants.ZERO;
+            BigInteger b = BigInteger.valueOf(1);
+            byte[] S = null;
+            BigInteger n = fromHex("020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001");
+            BigInteger h = BigInteger.valueOf(4);
+
+            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);
+            //ECPoint G = curve.decodePoint(Hex.decode("02"
+            //+ "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972"
+                + "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect571r1
+     */
+    static X9ECParametersHolder sect571r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 571;
+            int k1 = 2;
+            int k2 = 5;
+            int k3 = 10;
+
+            BigInteger a = BigInteger.valueOf(1);
+            BigInteger b = fromHex("02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A");
+            byte[] S = Hex.decode("2AA058F73A0E33AB486B0F610410C53A7F132310");
+            BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19"));
+            ECPoint G = curve.decodePoint(Hex.decode("04"
+                + "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19"
+                + "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+
+    static final Hashtable objIds = new Hashtable();
+    static final Hashtable curves = new Hashtable();
+    static final Hashtable names = new Hashtable();
+
+    static void defineCurve(String name, DERObjectIdentifier oid, X9ECParametersHolder holder)
+    {
+        objIds.put(name, oid);
+        names.put(oid, name);
+        curves.put(oid, holder);
+    }
+
+    static
+    {
+        defineCurve("secp112r1", SECObjectIdentifiers.secp112r1, secp112r1);
+        defineCurve("secp112r2", SECObjectIdentifiers.secp112r2, secp112r2);
+        defineCurve("secp128r1", SECObjectIdentifiers.secp128r1, secp128r1);
+        defineCurve("secp128r2", SECObjectIdentifiers.secp128r2, secp128r2);
+        defineCurve("secp160k1", SECObjectIdentifiers.secp160k1, secp160k1);
+        defineCurve("secp160r1", SECObjectIdentifiers.secp160r1, secp160r1);
+        defineCurve("secp160r2", SECObjectIdentifiers.secp160r2, secp160r2);
+        defineCurve("secp192k1", SECObjectIdentifiers.secp192k1, secp192k1);
+        defineCurve("secp192r1", SECObjectIdentifiers.secp192r1, secp192r1);
+        defineCurve("secp224k1", SECObjectIdentifiers.secp224k1, secp224k1);
+        defineCurve("secp224r1", SECObjectIdentifiers.secp224r1, secp224r1); 
+        defineCurve("secp256k1", SECObjectIdentifiers.secp256k1, secp256k1);
+        defineCurve("secp256r1", SECObjectIdentifiers.secp256r1, secp256r1); 
+        defineCurve("secp384r1", SECObjectIdentifiers.secp384r1, secp384r1); 
+        defineCurve("secp521r1", SECObjectIdentifiers.secp521r1, secp521r1); 
+
+        defineCurve("sect113r1", SECObjectIdentifiers.sect113r1, sect113r1);
+        defineCurve("sect113r2", SECObjectIdentifiers.sect113r2, sect113r2);
+        defineCurve("sect131r1", SECObjectIdentifiers.sect131r1, sect131r1);
+        defineCurve("sect131r2", SECObjectIdentifiers.sect131r2, sect131r2);
+        defineCurve("sect163k1", SECObjectIdentifiers.sect163k1, sect163k1);
+        defineCurve("sect163r1", SECObjectIdentifiers.sect163r1, sect163r1);
+        defineCurve("sect163r2", SECObjectIdentifiers.sect163r2, sect163r2);
+        defineCurve("sect193r1", SECObjectIdentifiers.sect193r1, sect193r1);
+        defineCurve("sect193r2", SECObjectIdentifiers.sect193r2, sect193r2);
+        defineCurve("sect233k1", SECObjectIdentifiers.sect233k1, sect233k1);
+        defineCurve("sect233r1", SECObjectIdentifiers.sect233r1, sect233r1);
+        defineCurve("sect239k1", SECObjectIdentifiers.sect239k1, sect239k1);
+        defineCurve("sect283k1", SECObjectIdentifiers.sect283k1, sect283k1);
+        defineCurve("sect283r1", SECObjectIdentifiers.sect283r1, sect283r1);
+        defineCurve("sect409k1", SECObjectIdentifiers.sect409k1, sect409k1);
+        defineCurve("sect409r1", SECObjectIdentifiers.sect409r1, sect409r1);
+        defineCurve("sect571k1", SECObjectIdentifiers.sect571k1, sect571k1);
+        defineCurve("sect571r1", SECObjectIdentifiers.sect571r1, sect571r1); 
+    }
+
+    public static X9ECParameters getByName(
+        String name)
+    {
+        DERObjectIdentifier oid = (DERObjectIdentifier)objIds.get(Strings.toLowerCase(name));
+
+        if (oid != null)
+        {
+            return getByOID(oid);
+        }
+
+        return null;
+    }
+
+    /**
+     * return the X9ECParameters object for the named curve represented by
+     * the passed in object identifier. Null if the curve isn't present.
+     *
+     * @param oid an object identifier representing a named curve, if present.
+     */
+    public static X9ECParameters getByOID(
+        DERObjectIdentifier oid)
+    {
+        X9ECParametersHolder holder = (X9ECParametersHolder)curves.get(oid);
+
+        if (holder != null)
+        {
+            return holder.getParameters();
+        }
+
+        return null;
+    }
+
+    /**
+     * return the object identifier signified by the passed in name. Null
+     * if there is no object identifier associated with name.
+     *
+     * @return the object identifier associated with name, if present.
+     */
+    public static DERObjectIdentifier getOID(
+        String name)
+    {
+        return (DERObjectIdentifier)objIds.get(Strings.toLowerCase(name));
+    }
+
+    /**
+     * return the named curve name represented by the given object identifier.
+     */
+    public static String getName(
+        DERObjectIdentifier oid)
+    {
+        return (String)names.get(oid);
+    }
+
+    /**
+     * returns an enumeration containing the name strings for curves
+     * contained in this structure.
+     */
+    public static Enumeration getNames()
+    {
+        return objIds.keys();
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java b/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java
new file mode 100644
index 0000000..fe066f1
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java
@@ -0,0 +1,50 @@
+package org.bouncycastle.asn1.sec;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+
+public interface SECObjectIdentifiers
+{
+    /**
+     *  ellipticCurve OBJECT IDENTIFIER ::= {
+     *        iso(1) identified-organization(3) certicom(132) curve(0)
+     *  }
+     */
+    static final DERObjectIdentifier ellipticCurve = new DERObjectIdentifier("1.3.132.0");
+
+    static final DERObjectIdentifier sect163k1 = new DERObjectIdentifier(ellipticCurve + ".1");
+    static final DERObjectIdentifier sect163r1 = new DERObjectIdentifier(ellipticCurve + ".2");
+    static final DERObjectIdentifier sect239k1 = new DERObjectIdentifier(ellipticCurve + ".3");
+    static final DERObjectIdentifier sect113r1 = new DERObjectIdentifier(ellipticCurve + ".4");
+    static final DERObjectIdentifier sect113r2 = new DERObjectIdentifier(ellipticCurve + ".5");
+    static final DERObjectIdentifier secp112r1 = new DERObjectIdentifier(ellipticCurve + ".6");
+    static final DERObjectIdentifier secp112r2 = new DERObjectIdentifier(ellipticCurve + ".7");
+    static final DERObjectIdentifier secp160r1 = new DERObjectIdentifier(ellipticCurve + ".8");
+    static final DERObjectIdentifier secp160k1 = new DERObjectIdentifier(ellipticCurve + ".9");
+    static final DERObjectIdentifier secp256k1 = new DERObjectIdentifier(ellipticCurve + ".10");
+    static final DERObjectIdentifier sect163r2 = new DERObjectIdentifier(ellipticCurve + ".15");
+    static final DERObjectIdentifier sect283k1 = new DERObjectIdentifier(ellipticCurve + ".16");
+    static final DERObjectIdentifier sect283r1 = new DERObjectIdentifier(ellipticCurve + ".17");
+    static final DERObjectIdentifier sect131r1 = new DERObjectIdentifier(ellipticCurve + ".22");
+    static final DERObjectIdentifier sect131r2 = new DERObjectIdentifier(ellipticCurve + ".23");
+    static final DERObjectIdentifier sect193r1 = new DERObjectIdentifier(ellipticCurve + ".24");
+    static final DERObjectIdentifier sect193r2 = new DERObjectIdentifier(ellipticCurve + ".25");
+    static final DERObjectIdentifier sect233k1 = new DERObjectIdentifier(ellipticCurve + ".26");
+    static final DERObjectIdentifier sect233r1 = new DERObjectIdentifier(ellipticCurve + ".27");
+    static final DERObjectIdentifier secp128r1 = new DERObjectIdentifier(ellipticCurve + ".28");
+    static final DERObjectIdentifier secp128r2 = new DERObjectIdentifier(ellipticCurve + ".29");
+    static final DERObjectIdentifier secp160r2 = new DERObjectIdentifier(ellipticCurve + ".30");
+    static final DERObjectIdentifier secp192k1 = new DERObjectIdentifier(ellipticCurve + ".31");
+    static final DERObjectIdentifier secp224k1 = new DERObjectIdentifier(ellipticCurve + ".32");
+    static final DERObjectIdentifier secp224r1 = new DERObjectIdentifier(ellipticCurve + ".33");
+    static final DERObjectIdentifier secp384r1 = new DERObjectIdentifier(ellipticCurve + ".34");
+    static final DERObjectIdentifier secp521r1 = new DERObjectIdentifier(ellipticCurve + ".35");
+    static final DERObjectIdentifier sect409k1 = new DERObjectIdentifier(ellipticCurve + ".36");
+    static final DERObjectIdentifier sect409r1 = new DERObjectIdentifier(ellipticCurve + ".37");
+    static final DERObjectIdentifier sect571k1 = new DERObjectIdentifier(ellipticCurve + ".38");
+    static final DERObjectIdentifier sect571r1 = new DERObjectIdentifier(ellipticCurve + ".39");
+
+    static final DERObjectIdentifier secp192r1 = X9ObjectIdentifiers.prime192v1;
+    static final DERObjectIdentifier secp256r1 = X9ObjectIdentifiers.prime256v1;
+
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java b/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java
new file mode 100644
index 0000000..bda8dad
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java
@@ -0,0 +1,621 @@
+package org.bouncycastle.asn1.x9;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.util.Strings;
+import org.bouncycastle.util.encoders.Hex;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+
+/**
+ * table of the current named curves defined in X.962 EC-DSA.
+ */
+public class X962NamedCurves
+{
+    static X9ECParametersHolder prime192v1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            ECCurve cFp192v1 = new ECCurve.Fp(
+                new BigInteger("6277101735386680763835789423207666416083908700390324961279"),
+                new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16),
+                new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16));
+
+            return new X9ECParameters(
+                cFp192v1,
+                cFp192v1.decodePoint(
+                    Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")),
+                new BigInteger("ffffffffffffffffffffffff99def836146bc9b1b4d22831", 16),
+                BigInteger.valueOf(1),
+                Hex.decode("3045AE6FC8422f64ED579528D38120EAE12196D5"));
+        }
+    };
+
+    static X9ECParametersHolder prime192v2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            ECCurve cFp192v2 = new ECCurve.Fp(
+                new BigInteger("6277101735386680763835789423207666416083908700390324961279"),
+                new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16),
+                new BigInteger("cc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953", 16));
+
+            return new X9ECParameters(
+                cFp192v2,
+                cFp192v2.decodePoint(
+                    Hex.decode("03eea2bae7e1497842f2de7769cfe9c989c072ad696f48034a")),
+                new BigInteger("fffffffffffffffffffffffe5fb1a724dc80418648d8dd31", 16),
+                BigInteger.valueOf(1),
+                Hex.decode("31a92ee2029fd10d901b113e990710f0d21ac6b6"));
+        }
+    };
+
+    static X9ECParametersHolder prime192v3 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            ECCurve cFp192v3 = new ECCurve.Fp(
+                new BigInteger("6277101735386680763835789423207666416083908700390324961279"),
+                new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16),
+                new BigInteger("22123dc2395a05caa7423daeccc94760a7d462256bd56916", 16));
+
+            return new X9ECParameters(
+                cFp192v3,
+                cFp192v3.decodePoint(
+                    Hex.decode("027d29778100c65a1da1783716588dce2b8b4aee8e228f1896")),
+                new BigInteger("ffffffffffffffffffffffff7a62d031c83f4294f640ec13", 16),
+                BigInteger.valueOf(1),
+                Hex.decode("c469684435deb378c4b65ca9591e2a5763059a2e"));
+        }
+    };
+
+    static X9ECParametersHolder prime239v1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            ECCurve cFp239v1 = new ECCurve.Fp(
+                new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"),
+                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16),
+                new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16));
+
+            return new X9ECParameters(
+                cFp239v1,
+                cFp239v1.decodePoint(
+                    Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")),
+                new BigInteger("7fffffffffffffffffffffff7fffff9e5e9a9f5d9071fbd1522688909d0b", 16),
+                BigInteger.valueOf(1),
+                Hex.decode("e43bb460f0b80cc0c0b075798e948060f8321b7d"));
+        }
+    };
+
+    static X9ECParametersHolder prime239v2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            ECCurve cFp239v2 = new ECCurve.Fp(
+                new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"),
+                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16),
+                new BigInteger("617fab6832576cbbfed50d99f0249c3fee58b94ba0038c7ae84c8c832f2c", 16));
+
+            return new X9ECParameters(
+                cFp239v2,
+                cFp239v2.decodePoint(
+                    Hex.decode("0238af09d98727705120c921bb5e9e26296a3cdcf2f35757a0eafd87b830e7")),
+                new BigInteger("7fffffffffffffffffffffff800000cfa7e8594377d414c03821bc582063", 16),
+                BigInteger.valueOf(1),
+                Hex.decode("e8b4011604095303ca3b8099982be09fcb9ae616"));
+        }
+    };
+
+    static X9ECParametersHolder prime239v3 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            ECCurve cFp239v3 = new ECCurve.Fp(
+                new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"),
+                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16),
+                new BigInteger("255705fa2a306654b1f4cb03d6a750a30c250102d4988717d9ba15ab6d3e", 16));
+
+            return new X9ECParameters(
+                cFp239v3,
+                cFp239v3.decodePoint(
+                    Hex.decode("036768ae8e18bb92cfcf005c949aa2c6d94853d0e660bbf854b1c9505fe95a")),
+                new BigInteger("7fffffffffffffffffffffff7fffff975deb41b3a6057c3c432146526551", 16),
+                BigInteger.valueOf(1),
+                Hex.decode("7d7374168ffe3471b60a857686a19475d3bfa2ff"));
+        }
+    };
+
+    static X9ECParametersHolder prime256v1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            ECCurve cFp256v1 = new ECCurve.Fp(
+                new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853951"),
+                new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16),
+                new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16));
+
+            return new X9ECParameters(
+                cFp256v1,
+                cFp256v1.decodePoint(
+                    Hex.decode("036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296")),
+                new BigInteger("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 16),
+                BigInteger.valueOf(1),
+                Hex.decode("c49d360886e704936a6678e1139d26b7819f7e90"));
+        }
+    };
+
+    /*
+     * F2m Curves
+     */
+    static X9ECParametersHolder c2pnb163v1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m163v1n = new BigInteger("0400000000000000000001E60FC8821CC74DAEAFC1", 16);
+            BigInteger c2m163v1h = BigInteger.valueOf(2);
+
+            ECCurve c2m163v1 = new ECCurve.F2m(
+                163,
+                1, 2, 8,
+                new BigInteger("072546B5435234A422E0789675F432C89435DE5242", 16),
+                new BigInteger("00C9517D06D5240D3CFF38C74B20B6CD4D6F9DD4D9", 16),
+                c2m163v1n, c2m163v1h);
+
+            return new X9ECParameters(
+                c2m163v1,
+                c2m163v1.decodePoint(
+                    Hex.decode("0307AF69989546103D79329FCC3D74880F33BBE803CB")),
+                c2m163v1n, c2m163v1h,
+                Hex.decode("D2COFB15760860DEF1EEF4D696E6768756151754"));
+        }
+    };
+
+    static X9ECParametersHolder c2pnb163v2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m163v2n = new BigInteger("03FFFFFFFFFFFFFFFFFFFDF64DE1151ADBB78F10A7", 16);
+            BigInteger c2m163v2h = BigInteger.valueOf(2);
+
+            ECCurve c2m163v2 = new ECCurve.F2m(
+                163,
+                1, 2, 8,
+                new BigInteger("0108B39E77C4B108BED981ED0E890E117C511CF072", 16),
+                new BigInteger("0667ACEB38AF4E488C407433FFAE4F1C811638DF20", 16),
+                c2m163v2n, c2m163v2h);
+
+            return new X9ECParameters(
+                c2m163v2,
+                c2m163v2.decodePoint(
+                    Hex.decode("030024266E4EB5106D0A964D92C4860E2671DB9B6CC5")),
+                c2m163v2n, c2m163v2h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2pnb163v3 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m163v3n = new BigInteger("03FFFFFFFFFFFFFFFFFFFE1AEE140F110AFF961309", 16);
+            BigInteger c2m163v3h = BigInteger.valueOf(2);
+
+            ECCurve c2m163v3 = new ECCurve.F2m(
+                163,
+                1, 2, 8,
+                new BigInteger("07A526C63D3E25A256A007699F5447E32AE456B50E", 16),
+                new BigInteger("03F7061798EB99E238FD6F1BF95B48FEEB4854252B", 16),
+                c2m163v3n, c2m163v3h);
+
+            return new X9ECParameters(
+                c2m163v3,
+                c2m163v3.decodePoint(
+                    Hex.decode("0202F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB")),
+                c2m163v3n, c2m163v3h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2pnb176w1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m176w1n = new BigInteger("010092537397ECA4F6145799D62B0A19CE06FE26AD", 16);
+            BigInteger c2m176w1h = BigInteger.valueOf(0xFF6E);
+
+            ECCurve c2m176w1 = new ECCurve.F2m(
+                176,
+                1, 2, 43,
+                new BigInteger("00E4E6DB2995065C407D9D39B8D0967B96704BA8E9C90B", 16),
+                new BigInteger("005DDA470ABE6414DE8EC133AE28E9BBD7FCEC0AE0FFF2", 16),
+                c2m176w1n, c2m176w1h);
+
+            return new X9ECParameters(
+                c2m176w1,
+                c2m176w1.decodePoint(
+                    Hex.decode("038D16C2866798B600F9F08BB4A8E860F3298CE04A5798")),
+                c2m176w1n, c2m176w1h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2tnb191v1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m191v1n = new BigInteger("40000000000000000000000004A20E90C39067C893BBB9A5", 16);
+            BigInteger c2m191v1h = BigInteger.valueOf(2);
+
+            ECCurve c2m191v1 = new ECCurve.F2m(
+                191,
+                9,
+                new BigInteger("2866537B676752636A68F56554E12640276B649EF7526267", 16),
+                new BigInteger("2E45EF571F00786F67B0081B9495A3D95462F5DE0AA185EC", 16),
+                c2m191v1n, c2m191v1h);
+
+            return new X9ECParameters(
+                c2m191v1,
+                c2m191v1.decodePoint(
+                    Hex.decode("0236B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D")),
+                c2m191v1n, c2m191v1h,
+                Hex.decode("4E13CA542744D696E67687561517552F279A8C84"));
+        }
+    };
+
+    static X9ECParametersHolder c2tnb191v2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m191v2n = new BigInteger("20000000000000000000000050508CB89F652824E06B8173", 16);
+            BigInteger c2m191v2h = BigInteger.valueOf(4);
+
+            ECCurve c2m191v2 = new ECCurve.F2m(
+                191,
+                9,
+                new BigInteger("401028774D7777C7B7666D1366EA432071274F89FF01E718", 16),
+                new BigInteger("0620048D28BCBD03B6249C99182B7C8CD19700C362C46A01", 16),
+                c2m191v2n, c2m191v2h);
+
+            return new X9ECParameters(
+                c2m191v2,
+                c2m191v2.decodePoint(
+                    Hex.decode("023809B2B7CC1B28CC5A87926AAD83FD28789E81E2C9E3BF10")),
+                c2m191v2n, c2m191v2h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2tnb191v3 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m191v3n = new BigInteger("155555555555555555555555610C0B196812BFB6288A3EA3", 16);
+            BigInteger c2m191v3h = BigInteger.valueOf(6);
+
+            ECCurve c2m191v3 = new ECCurve.F2m(
+                191,
+                9,
+                new BigInteger("6C01074756099122221056911C77D77E77A777E7E7E77FCB", 16),
+                new BigInteger("71FE1AF926CF847989EFEF8DB459F66394D90F32AD3F15E8", 16),
+                c2m191v3n, c2m191v3h);
+
+            return new X9ECParameters(
+                c2m191v3,
+                c2m191v3.decodePoint(
+                    Hex.decode("03375D4CE24FDE434489DE8746E71786015009E66E38A926DD")),
+                c2m191v3n, c2m191v3h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2pnb208w1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m208w1n = new BigInteger("0101BAF95C9723C57B6C21DA2EFF2D5ED588BDD5717E212F9D", 16);
+            BigInteger c2m208w1h = BigInteger.valueOf(0xFE48);
+
+            ECCurve c2m208w1 = new ECCurve.F2m(
+                208,
+                1, 2, 83,
+                new BigInteger("0", 16),
+                new BigInteger("00C8619ED45A62E6212E1160349E2BFA844439FAFC2A3FD1638F9E", 16),
+                c2m208w1n, c2m208w1h);
+
+            return new X9ECParameters(
+                c2m208w1,
+                c2m208w1.decodePoint(
+                    Hex.decode("0289FDFBE4ABE193DF9559ECF07AC0CE78554E2784EB8C1ED1A57A")),
+                c2m208w1n, c2m208w1h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2tnb239v1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m239v1n = new BigInteger("2000000000000000000000000000000F4D42FFE1492A4993F1CAD666E447", 16);
+            BigInteger c2m239v1h = BigInteger.valueOf(4);
+
+            ECCurve c2m239v1 = new ECCurve.F2m(
+                239,
+                36,
+                new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16),
+                new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16),
+                c2m239v1n, c2m239v1h);
+
+            return new X9ECParameters(
+                c2m239v1,
+                c2m239v1.decodePoint(
+                    Hex.decode("0257927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D")),
+                c2m239v1n, c2m239v1h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2tnb239v2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m239v2n = new BigInteger("1555555555555555555555555555553C6F2885259C31E3FCDF154624522D", 16);
+            BigInteger c2m239v2h = BigInteger.valueOf(6);
+
+            ECCurve c2m239v2 = new ECCurve.F2m(
+                239,
+                36,
+                new BigInteger("4230017757A767FAE42398569B746325D45313AF0766266479B75654E65F", 16),
+                new BigInteger("5037EA654196CFF0CD82B2C14A2FCF2E3FF8775285B545722F03EACDB74B", 16),
+                c2m239v2n, c2m239v2h);
+
+            return new X9ECParameters(
+                c2m239v2,
+                c2m239v2.decodePoint(
+                    Hex.decode("0228F9D04E900069C8DC47A08534FE76D2B900B7D7EF31F5709F200C4CA205")),
+                c2m239v2n, c2m239v2h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2tnb239v3 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m239v3n = new BigInteger("0CCCCCCCCCCCCCCCCCCCCCCCCCCCCCAC4912D2D9DF903EF9888B8A0E4CFF", 16);
+            BigInteger c2m239v3h = BigInteger.valueOf(10);
+
+            ECCurve c2m239v3 = new ECCurve.F2m(
+                239,
+                36,
+                new BigInteger("01238774666A67766D6676F778E676B66999176666E687666D8766C66A9F", 16),
+                new BigInteger("6A941977BA9F6A435199ACFC51067ED587F519C5ECB541B8E44111DE1D40", 16),
+                c2m239v3n, c2m239v3h);
+
+            return new X9ECParameters(
+                c2m239v3,
+                c2m239v3.decodePoint(
+                    Hex.decode("0370F6E9D04D289C4E89913CE3530BFDE903977D42B146D539BF1BDE4E9C92")),
+                c2m239v3n, c2m239v3h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2pnb272w1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m272w1n = new BigInteger("0100FAF51354E0E39E4892DF6E319C72C8161603FA45AA7B998A167B8F1E629521", 16);
+            BigInteger c2m272w1h = BigInteger.valueOf(0xFF06);
+
+            ECCurve c2m272w1 = new ECCurve.F2m(
+                272,
+                1, 3, 56,
+                new BigInteger("0091A091F03B5FBA4AB2CCF49C4EDD220FB028712D42BE752B2C40094DBACDB586FB20", 16),
+                new BigInteger("7167EFC92BB2E3CE7C8AAAFF34E12A9C557003D7C73A6FAF003F99F6CC8482E540F7", 16),
+                c2m272w1n, c2m272w1h);
+
+            return new X9ECParameters(
+                c2m272w1,
+                c2m272w1.decodePoint(
+                    Hex.decode("026108BABB2CEEBCF787058A056CBE0CFE622D7723A289E08A07AE13EF0D10D171DD8D")),
+                c2m272w1n, c2m272w1h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2pnb304w1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m304w1n = new BigInteger("0101D556572AABAC800101D556572AABAC8001022D5C91DD173F8FB561DA6899164443051D", 16);
+            BigInteger c2m304w1h = BigInteger.valueOf(0xFE2E);
+
+            ECCurve c2m304w1 = new ECCurve.F2m(
+                304,
+                1, 2, 11,
+                new BigInteger("00FD0D693149A118F651E6DCE6802085377E5F882D1B510B44160074C1288078365A0396C8E681", 16),
+                new BigInteger("00BDDB97E555A50A908E43B01C798EA5DAA6788F1EA2794EFCF57166B8C14039601E55827340BE", 16),
+                c2m304w1n, c2m304w1h);
+
+            return new X9ECParameters(
+                c2m304w1,
+                c2m304w1.decodePoint(
+                    Hex.decode("02197B07845E9BE2D96ADB0F5F3C7F2CFFBD7A3EB8B6FEC35C7FD67F26DDF6285A644F740A2614")),
+                c2m304w1n, c2m304w1h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2tnb359v1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m359v1n = new BigInteger("01AF286BCA1AF286BCA1AF286BCA1AF286BCA1AF286BC9FB8F6B85C556892C20A7EB964FE7719E74F490758D3B", 16);
+            BigInteger c2m359v1h = BigInteger.valueOf(0x4C);
+
+            ECCurve c2m359v1 = new ECCurve.F2m(
+                359,
+                68,
+                new BigInteger("5667676A654B20754F356EA92017D946567C46675556F19556A04616B567D223A5E05656FB549016A96656A557", 16),
+                new BigInteger("2472E2D0197C49363F1FE7F5B6DB075D52B6947D135D8CA445805D39BC345626089687742B6329E70680231988", 16),
+                c2m359v1n, c2m359v1h);
+
+            return new X9ECParameters(
+                c2m359v1,
+                c2m359v1.decodePoint(
+                    Hex.decode("033C258EF3047767E7EDE0F1FDAA79DAEE3841366A132E163ACED4ED2401DF9C6BDCDE98E8E707C07A2239B1B097")),
+                c2m359v1n, c2m359v1h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2pnb368w1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m368w1n = new BigInteger("010090512DA9AF72B08349D98A5DD4C7B0532ECA51CE03E2D10F3B7AC579BD87E909AE40A6F131E9CFCE5BD967", 16);
+            BigInteger c2m368w1h = BigInteger.valueOf(0xFF70);
+
+            ECCurve c2m368w1 = new ECCurve.F2m(
+                368,
+                1, 2, 85,
+                new BigInteger("00E0D2EE25095206F5E2A4F9ED229F1F256E79A0E2B455970D8D0D865BD94778C576D62F0AB7519CCD2A1A906AE30D", 16),
+                new BigInteger("00FC1217D4320A90452C760A58EDCD30C8DD069B3C34453837A34ED50CB54917E1C2112D84D164F444F8F74786046A", 16),
+                c2m368w1n, c2m368w1h);
+
+            return new X9ECParameters(
+                c2m368w1,
+                c2m368w1.decodePoint(
+                    Hex.decode("021085E2755381DCCCE3C1557AFA10C2F0C0C2825646C5B34A394CBCFA8BC16B22E7E789E927BE216F02E1FB136A5F")),
+                c2m368w1n, c2m368w1h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2tnb431r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m431r1n = new BigInteger("0340340340340340340340340340340340340340340340340340340323C313FAB50589703B5EC68D3587FEC60D161CC149C1AD4A91", 16);
+            BigInteger c2m431r1h = BigInteger.valueOf(0x2760);
+
+            ECCurve c2m431r1 = new ECCurve.F2m(
+                431,
+                120,
+                new BigInteger("1A827EF00DD6FC0E234CAF046C6A5D8A85395B236CC4AD2CF32A0CADBDC9DDF620B0EB9906D0957F6C6FEACD615468DF104DE296CD8F", 16),
+                new BigInteger("10D9B4A3D9047D8B154359ABFB1B7F5485B04CEB868237DDC9DEDA982A679A5A919B626D4E50A8DD731B107A9962381FB5D807BF2618", 16),
+                c2m431r1n, c2m431r1h);
+
+            return new X9ECParameters(
+                c2m431r1,
+                c2m431r1.decodePoint(
+                    Hex.decode("02120FC05D3C67A99DE161D2F4092622FECA701BE4F50F4758714E8A87BBF2A658EF8C21E7C5EFE965361F6C2999C0C247B0DBD70CE6B7")),
+                c2m431r1n, c2m431r1h,
+                null);
+        }
+    };
+
+    static final Hashtable objIds = new Hashtable();
+    static final Hashtable curves = new Hashtable();
+    static final Hashtable names = new Hashtable();
+
+    static void defineCurve(String name, DERObjectIdentifier oid, X9ECParametersHolder holder)
+    {
+        objIds.put(name, oid);
+        names.put(oid, name);
+        curves.put(oid, holder);
+    }
+
+    static
+    {
+        defineCurve("prime192v1", X9ObjectIdentifiers.prime192v1, prime192v1);
+        defineCurve("prime192v2", X9ObjectIdentifiers.prime192v2, prime192v2);
+        defineCurve("prime192v3", X9ObjectIdentifiers.prime192v3, prime192v3);
+        defineCurve("prime239v1", X9ObjectIdentifiers.prime239v1, prime239v1);
+        defineCurve("prime239v2", X9ObjectIdentifiers.prime239v2, prime239v2);
+        defineCurve("prime239v3", X9ObjectIdentifiers.prime239v3, prime239v3);
+        defineCurve("prime256v1", X9ObjectIdentifiers.prime256v1, prime256v1);
+        defineCurve("c2pnb163v1", X9ObjectIdentifiers.c2pnb163v1, c2pnb163v1);
+        defineCurve("c2pnb163v2", X9ObjectIdentifiers.c2pnb163v2, c2pnb163v2);
+        defineCurve("c2pnb163v3", X9ObjectIdentifiers.c2pnb163v3, c2pnb163v3);
+        defineCurve("c2pnb176w1", X9ObjectIdentifiers.c2pnb176w1, c2pnb176w1);
+        defineCurve("c2tnb191v1", X9ObjectIdentifiers.c2tnb191v1, c2tnb191v1);
+        defineCurve("c2tnb191v2", X9ObjectIdentifiers.c2tnb191v2, c2tnb191v2);
+        defineCurve("c2tnb191v3", X9ObjectIdentifiers.c2tnb191v3, c2tnb191v3);
+        defineCurve("c2pnb208w1", X9ObjectIdentifiers.c2pnb208w1, c2pnb208w1);
+        defineCurve("c2tnb239v1", X9ObjectIdentifiers.c2tnb239v1, c2tnb239v1);
+        defineCurve("c2tnb239v2", X9ObjectIdentifiers.c2tnb239v2, c2tnb239v2);
+        defineCurve("c2tnb239v3", X9ObjectIdentifiers.c2tnb239v3, c2tnb239v3);
+        defineCurve("c2pnb272w1", X9ObjectIdentifiers.c2pnb272w1, c2pnb272w1);
+        defineCurve("c2pnb304w1", X9ObjectIdentifiers.c2pnb304w1, c2pnb304w1);
+        defineCurve("c2tnb359v1", X9ObjectIdentifiers.c2tnb359v1, c2tnb359v1);
+        defineCurve("c2pnb368w1", X9ObjectIdentifiers.c2pnb368w1, c2pnb368w1);
+        defineCurve("c2tnb431r1", X9ObjectIdentifiers.c2tnb431r1, c2tnb431r1);
+    }
+
+    public static X9ECParameters getByName(
+        String name)
+    {
+        DERObjectIdentifier oid = (DERObjectIdentifier)objIds.get(Strings.toLowerCase(name));
+
+        if (oid != null)
+        {
+            return getByOID(oid);
+        }
+
+        return null;
+    }
+
+    /**
+     * return the X9ECParameters object for the named curve represented by
+     * the passed in object identifier. Null if the curve isn't present.
+     *
+     * @param oid an object identifier representing a named curve, if present.
+     */
+    public static X9ECParameters getByOID(
+        DERObjectIdentifier oid)
+    {
+        X9ECParametersHolder holder = (X9ECParametersHolder)curves.get(oid);
+
+        if (holder != null)
+        {
+            return holder.getParameters();
+        }
+
+        return null;
+    }
+
+    /**
+     * return the object identifier signified by the passed in name. Null
+     * if there is no object identifier associated with name.
+     *
+     * @return the object identifier associated with name, if present.
+     */
+    public static DERObjectIdentifier getOID(
+        String name)
+    {
+        return (DERObjectIdentifier)objIds.get(Strings.toLowerCase(name));
+    }
+
+    /**
+     * return the named curve name represented by the given object identifier.
+     */
+    public static String getName(
+        DERObjectIdentifier oid)
+    {
+        return (String)names.get(oid);
+    }
+
+    /**
+     * returns an enumeration containing the name strings for curves
+     * contained in this structure.
+     */
+    public static Enumeration getNames()
+    {
+        return objIds.keys();
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x9/X962Parameters.java b/src/main/java/org/bouncycastle/asn1/x9/X962Parameters.java
new file mode 100644
index 0000000..de35186
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x9/X962Parameters.java
@@ -0,0 +1,86 @@
+package org.bouncycastle.asn1.x9;
+
+import org.bouncycastle.asn1.ASN1Choice;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Null;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+public class X962Parameters
+    extends ASN1Encodable
+    implements ASN1Choice
+{
+    private DERObject           params = null;
+
+    public static X962Parameters getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof X962Parameters) 
+        {
+            return (X962Parameters)obj;
+        }
+        
+        if (obj instanceof DERObject) 
+        {
+            return new X962Parameters((DERObject)obj);
+        }
+        
+        throw new IllegalArgumentException("unknown object in getInstance()");
+    }
+    
+    public static X962Parameters getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject()); // must be explicitly tagged
+    }
+    
+    public X962Parameters(
+        X9ECParameters      ecParameters)
+    {
+        this.params = ecParameters.getDERObject();
+    }
+
+    public X962Parameters(
+        DERObjectIdentifier  namedCurve)
+    {
+        this.params = namedCurve;
+    }
+
+    public X962Parameters(
+        DERObject           obj)
+    {
+        this.params = obj;
+    }
+
+    public boolean isNamedCurve()
+    {
+        return (params instanceof DERObjectIdentifier);
+    }
+
+    public boolean isImplicitlyCA()
+    {
+        return (params instanceof ASN1Null);
+    }
+
+    public DERObject getParameters()
+    {
+        return params;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * Parameters ::= CHOICE {
+     *    ecParameters ECParameters,
+     *    namedCurve   CURVES.&id({CurveNames}),
+     *    implicitlyCA NULL
+     * }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        return params;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java b/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java
new file mode 100644
index 0000000..8f46c07
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java
@@ -0,0 +1,161 @@
+package org.bouncycastle.asn1.x9;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.math.ec.ECCurve;
+
+/**
+ * ASN.1 def for Elliptic-Curve Curve structure. See
+ * X9.62, for further details.
+ */
+public class X9Curve
+    extends ASN1Encodable
+    implements X9ObjectIdentifiers
+{
+    private ECCurve     curve;
+    private byte[]      seed;
+    private DERObjectIdentifier fieldIdentifier = null;
+
+    public X9Curve(
+        ECCurve     curve)
+    {
+        this.curve = curve;
+        this.seed = null;
+        setFieldIdentifier();
+    }
+
+    public X9Curve(
+        ECCurve     curve,
+        byte[]      seed)
+    {
+        this.curve = curve;
+        this.seed = seed;
+        setFieldIdentifier();
+    }
+
+    public X9Curve(
+        X9FieldID     fieldID,
+        ASN1Sequence  seq)
+    {
+        fieldIdentifier = fieldID.getIdentifier();
+        if (fieldIdentifier.equals(prime_field))
+        {
+            BigInteger      p = ((DERInteger)fieldID.getParameters()).getValue();
+            X9FieldElement  x9A = new X9FieldElement(p, (ASN1OctetString)seq.getObjectAt(0));
+            X9FieldElement  x9B = new X9FieldElement(p, (ASN1OctetString)seq.getObjectAt(1));
+            curve = new ECCurve.Fp(p, x9A.getValue().toBigInteger(), x9B.getValue().toBigInteger());
+        }
+        else
+        {
+            if (fieldIdentifier.equals(characteristic_two_field)) 
+            {
+                // Characteristic two field
+                DERSequence parameters = (DERSequence)fieldID.getParameters();
+                int m = ((DERInteger)parameters.getObjectAt(0)).getValue().
+                    intValue();
+                DERObjectIdentifier representation
+                    = (DERObjectIdentifier)parameters.getObjectAt(1);
+
+                int k1 = 0;
+                int k2 = 0;
+                int k3 = 0;
+                if (representation.equals(tpBasis)) 
+                {
+                    // Trinomial basis representation
+                    k1 = ((DERInteger)parameters.getObjectAt(2)).getValue().
+                        intValue();
+                }
+                else 
+                {
+                    // Pentanomial basis representation
+                    DERSequence pentanomial
+                        = (DERSequence)parameters.getObjectAt(2);
+                    k1 = ((DERInteger)pentanomial.getObjectAt(0)).getValue().
+                        intValue();
+                    k2 = ((DERInteger)pentanomial.getObjectAt(1)).getValue().
+                        intValue();
+                    k3 = ((DERInteger)pentanomial.getObjectAt(2)).getValue().
+                        intValue();
+                }
+                X9FieldElement x9A = new X9FieldElement(m, k1, k2, k3, (ASN1OctetString)seq.getObjectAt(0));
+                X9FieldElement x9B = new X9FieldElement(m, k1, k2, k3, (ASN1OctetString)seq.getObjectAt(1));
+                // TODO Is it possible to get the order (n) and cofactor(h) too?
+                curve = new ECCurve.F2m(m, k1, k2, k3, x9A.getValue().toBigInteger(), x9B.getValue().toBigInteger());
+            }
+        }
+
+        if (seq.size() == 3)
+        {
+            seed = ((DERBitString)seq.getObjectAt(2)).getBytes();
+        }
+    }
+
+    private void setFieldIdentifier()
+    {
+        if (curve instanceof ECCurve.Fp)
+        {
+            fieldIdentifier = prime_field;
+        }
+        else if (curve instanceof ECCurve.F2m)
+        {
+            fieldIdentifier = characteristic_two_field;
+        }
+        else
+        {
+            throw new IllegalArgumentException("This type of ECCurve is not "
+                    + "implemented");
+        }
+    }
+
+    public ECCurve  getCurve()
+    {
+        return curve;
+    }
+
+    public byte[]   getSeed()
+    {
+        return seed;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  Curve ::= SEQUENCE {
+     *      a               FieldElement,
+     *      b               FieldElement,
+     *      seed            BIT STRING      OPTIONAL
+     *  }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        if (fieldIdentifier.equals(prime_field)) 
+        { 
+            v.add(new X9FieldElement(curve.getA()).getDERObject());
+            v.add(new X9FieldElement(curve.getB()).getDERObject());
+        } 
+        else if (fieldIdentifier.equals(characteristic_two_field)) 
+        {
+            v.add(new X9FieldElement(curve.getA()).getDERObject());
+            v.add(new X9FieldElement(curve.getB()).getDERObject());
+        }
+
+        if (seed != null)
+        {
+            v.add(new DERBitString(seed));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java b/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java
new file mode 100644
index 0000000..c3b0d66
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java
@@ -0,0 +1,161 @@
+package org.bouncycastle.asn1.x9;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+
+import java.math.BigInteger;
+
+/**
+ * ASN.1 def for Elliptic-Curve ECParameters structure. See
+ * X9.62, for further details.
+ */
+public class X9ECParameters
+    extends ASN1Encodable
+    implements X9ObjectIdentifiers
+{
+    private static final BigInteger   ONE = BigInteger.valueOf(1);
+
+    private X9FieldID           fieldID;
+    private ECCurve             curve;
+    private ECPoint             g;
+    private BigInteger          n;
+    private BigInteger          h;
+    private byte[]              seed;
+
+    public X9ECParameters(
+        ASN1Sequence  seq)
+    {
+        if (!(seq.getObjectAt(0) instanceof DERInteger)
+           || !((DERInteger)seq.getObjectAt(0)).getValue().equals(ONE))
+        {
+            throw new IllegalArgumentException("bad version in X9ECParameters");
+        }
+
+        X9Curve     x9c = new X9Curve(
+                        new X9FieldID((ASN1Sequence)seq.getObjectAt(1)),
+                        (ASN1Sequence)seq.getObjectAt(2));
+
+        this.curve = x9c.getCurve();
+        this.g = new X9ECPoint(curve, (ASN1OctetString)seq.getObjectAt(3)).getPoint();
+        this.n = ((DERInteger)seq.getObjectAt(4)).getValue();
+        this.seed = x9c.getSeed();
+
+        if (seq.size() == 6)
+        {
+            this.h = ((DERInteger)seq.getObjectAt(5)).getValue();
+        }
+    }
+
+    public X9ECParameters(
+        ECCurve     curve,
+        ECPoint     g,
+        BigInteger  n)
+    {
+        this(curve, g, n, ONE, null);
+    }
+
+    public X9ECParameters(
+        ECCurve     curve,
+        ECPoint     g,
+        BigInteger  n,
+        BigInteger  h)
+    {
+        this(curve, g, n, h, null);
+    }
+
+    public X9ECParameters(
+        ECCurve     curve,
+        ECPoint     g,
+        BigInteger  n,
+        BigInteger  h,
+        byte[]      seed)
+    {
+        this.curve = curve;
+        this.g = g;
+        this.n = n;
+        this.h = h;
+        this.seed = seed;
+
+        if (curve instanceof ECCurve.Fp)
+        {
+            this.fieldID = new X9FieldID(((ECCurve.Fp)curve).getQ());
+        }
+        else
+        {
+            if (curve instanceof ECCurve.F2m)
+            {
+                ECCurve.F2m curveF2m = (ECCurve.F2m)curve;
+                this.fieldID = new X9FieldID(curveF2m.getM(), curveF2m.getK1(),
+                    curveF2m.getK2(), curveF2m.getK3());
+            }
+        }
+    }
+
+    public ECCurve getCurve()
+    {
+        return curve;
+    }
+
+    public ECPoint getG()
+    {
+        return g;
+    }
+
+    public BigInteger getN()
+    {
+        return n;
+    }
+
+    public BigInteger getH()
+    {
+        if (h == null)
+        {
+            return ONE;        // TODO - this should be calculated, it will cause issues with custom curves.
+        }
+
+        return h;
+    }
+
+    public byte[] getSeed()
+    {
+        return seed;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  ECParameters ::= SEQUENCE {
+     *      version         INTEGER { ecpVer1(1) } (ecpVer1),
+     *      fieldID         FieldID {{FieldTypes}},
+     *      curve           X9Curve,
+     *      base            X9ECPoint,
+     *      order           INTEGER,
+     *      cofactor        INTEGER OPTIONAL
+     *  }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(new DERInteger(1));
+        v.add(fieldID);
+        v.add(new X9Curve(curve, seed));
+        v.add(new X9ECPoint(g));
+        v.add(new DERInteger(n));
+
+        if (h != null)
+        {
+            v.add(new DERInteger(h));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x9/X9ECParametersHolder.java b/src/main/java/org/bouncycastle/asn1/x9/X9ECParametersHolder.java
new file mode 100644
index 0000000..47361f8
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x9/X9ECParametersHolder.java
@@ -0,0 +1,18 @@
+package org.bouncycastle.asn1.x9;
+
+public abstract class X9ECParametersHolder
+{
+    private X9ECParameters params;
+
+    public X9ECParameters getParameters()
+    {
+        if (params == null)
+        {
+            params = createParameters();
+        }
+
+        return params;
+    }
+
+    protected abstract X9ECParameters createParameters();
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java b/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java
new file mode 100644
index 0000000..470b3d6
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java
@@ -0,0 +1,48 @@
+package org.bouncycastle.asn1.x9;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+
+/**
+ * class for describing an ECPoint as a DER object.
+ */
+public class X9ECPoint
+    extends ASN1Encodable
+{
+    ECPoint p;
+
+    public X9ECPoint(
+        ECPoint p)
+    {
+        this.p = p;
+    }
+
+    public X9ECPoint(
+        ECCurve          c,
+        ASN1OctetString  s)
+    {
+        this.p = c.decodePoint(s.getOctets());
+    }
+
+    public ECPoint getPoint()
+    {
+        return p;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  ECPoint ::= OCTET STRING
+     * </pre>
+     * <p>
+     * Octet string produced using ECPoint.getEncoded().
+     */
+    public DERObject toASN1Object()
+    {
+        return new DEROctetString(p.getEncoded());
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x9/X9FieldElement.java b/src/main/java/org/bouncycastle/asn1/x9/X9FieldElement.java
new file mode 100644
index 0000000..2173d2a
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x9/X9FieldElement.java
@@ -0,0 +1,64 @@
+package org.bouncycastle.asn1.x9;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.math.ec.ECFieldElement;
+
+/**
+ * class for processing an FieldElement as a DER object.
+ */
+public class X9FieldElement
+    extends ASN1Encodable
+{
+    protected ECFieldElement  f;
+    
+    private static X9IntegerConverter converter = new X9IntegerConverter();
+
+    public X9FieldElement(ECFieldElement f)
+    {
+        this.f = f;
+    }
+    
+    public X9FieldElement(BigInteger p, ASN1OctetString s)
+    {
+        this(new ECFieldElement.Fp(p, new BigInteger(1, s.getOctets())));
+    }
+    
+    public X9FieldElement(int m, int k1, int k2, int k3, ASN1OctetString s)
+    {
+        this(new ECFieldElement.F2m(m, k1, k2, k3, new BigInteger(1, s.getOctets())));
+    }
+    
+    public ECFieldElement getValue()
+    {
+        return f;
+    }
+    
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  FieldElement ::= OCTET STRING
+     * </pre>
+     * <p>
+     * <ol>
+     * <li> if <i>q</i> is an odd prime then the field element is
+     * processed as an Integer and converted to an octet string
+     * according to x 9.62 4.3.1.</li>
+     * <li> if <i>q</i> is 2<sup>m</sup> then the bit string
+     * contained in the field element is converted into an octet
+     * string with the same ordering padded at the front if necessary.
+     * </li>
+     * </ol>
+     */
+    public DERObject toASN1Object()
+    {
+        int byteCount = converter.getByteLength(f);
+        byte[] paddedBigInteger = converter.integerToBytes(f.toBigInteger(), byteCount);
+
+        return new DEROctetString(paddedBigInteger);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java b/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java
new file mode 100644
index 0000000..c2c2ef9
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java
@@ -0,0 +1,109 @@
+package org.bouncycastle.asn1.x9;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+
+/**
+ * ASN.1 def for Elliptic-Curve Field ID structure. See
+ * X9.62, for further details.
+ */
+public class X9FieldID
+    extends ASN1Encodable
+    implements X9ObjectIdentifiers
+{
+    private DERObjectIdentifier     id;
+    private DERObject               parameters;
+
+    /**
+     * Constructor for elliptic curves over prime fields
+     * <code>F<sub>2</sub></code>.
+     * @param primeP The prime <code>p</code> defining the prime field.
+     */
+    public X9FieldID(BigInteger primeP)
+    {
+        this.id = prime_field;
+        this.parameters = new DERInteger(primeP);
+    }
+
+    /**
+     * Constructor for elliptic curves over binary fields
+     * <code>F<sub>2<sup>m</sup></sub></code>.
+     * @param m  The exponent <code>m</code> of
+     * <code>F<sub>2<sup>m</sup></sub></code>.
+     * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
+     * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+     * represents the reduction polynomial <code>f(z)</code>.
+     * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
+     * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+     * represents the reduction polynomial <code>f(z)</code>.
+     * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
+     * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+     * represents the reduction polynomial <code>f(z)</code>..
+     */
+    public X9FieldID(int m, int k1, int k2, int k3)
+    {
+        this.id = characteristic_two_field;
+        ASN1EncodableVector fieldIdParams = new ASN1EncodableVector();
+        fieldIdParams.add(new DERInteger(m));
+        
+        if (k2 == 0) 
+        {
+            fieldIdParams.add(tpBasis);
+            fieldIdParams.add(new DERInteger(k1));
+        } 
+        else 
+        {
+            fieldIdParams.add(ppBasis);
+            ASN1EncodableVector pentanomialParams = new ASN1EncodableVector();
+            pentanomialParams.add(new DERInteger(k1));
+            pentanomialParams.add(new DERInteger(k2));
+            pentanomialParams.add(new DERInteger(k3));
+            fieldIdParams.add(new DERSequence(pentanomialParams));
+        }
+        
+        this.parameters = new DERSequence(fieldIdParams);
+    }
+
+    public X9FieldID(
+        ASN1Sequence  seq)
+    {
+        this.id = (DERObjectIdentifier)seq.getObjectAt(0);
+        this.parameters = (DERObject)seq.getObjectAt(1);
+    }
+
+    public DERObjectIdentifier getIdentifier()
+    {
+        return id;
+    }
+
+    public DERObject getParameters()
+    {
+        return parameters;
+    }
+
+    /**
+     * Produce a DER encoding of the following structure.
+     * <pre>
+     *  FieldID ::= SEQUENCE {
+     *      fieldType       FIELD-ID.&amp;id({IOSet}),
+     *      parameters      FIELD-ID.&amp;Type({IOSet}{&#64;fieldType})
+     *  }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(this.id);
+        v.add(this.parameters);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x9/X9IntegerConverter.java b/src/main/java/org/bouncycastle/asn1/x9/X9IntegerConverter.java
new file mode 100644
index 0000000..ae820ab
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x9/X9IntegerConverter.java
@@ -0,0 +1,47 @@
+package org.bouncycastle.asn1.x9;
+
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECFieldElement;
+
+import java.math.BigInteger;
+
+public class X9IntegerConverter
+{
+    public int getByteLength(
+        ECCurve c)
+    {
+        return (c.getFieldSize() + 7) / 8;
+    }
+
+    public int getByteLength(
+        ECFieldElement fe)
+    {
+        return (fe.getFieldSize() + 7) / 8;
+    }
+
+    public byte[] integerToBytes(
+        BigInteger s,
+        int        qLength)
+    {
+        byte[] bytes = s.toByteArray();
+        
+        if (qLength < bytes.length)
+        {
+            byte[] tmp = new byte[qLength];
+        
+            System.arraycopy(bytes, bytes.length - tmp.length, tmp, 0, tmp.length);
+            
+            return tmp;
+        }
+        else if (qLength > bytes.length)
+        {
+            byte[] tmp = new byte[qLength];
+        
+            System.arraycopy(bytes, 0, tmp, tmp.length - bytes.length, bytes.length);
+            
+            return tmp; 
+        }
+    
+        return bytes;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java b/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java
new file mode 100644
index 0000000..3ad3e1c
--- /dev/null
+++ b/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java
@@ -0,0 +1,47 @@
+package org.bouncycastle.crypto.agreement;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.math.ec.ECPoint;
+
+import org.bouncycastle.crypto.BasicAgreement;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+
+/**
+ * P1363 7.2.1 ECSVDP-DH
+ *
+ * ECSVDP-DH is Elliptic Curve Secret Value Derivation Primitive,
+ * Diffie-Hellman version. It is based on the work of [DH76], [Mil86],
+ * and [Kob87]. This primitive derives a shared secret value from one
+ * party's private key and another party's public key, where both have
+ * the same set of EC domain parameters. If two parties correctly
+ * execute this primitive, they will produce the same output. This
+ * primitive can be invoked by a scheme to derive a shared secret key;
+ * specifically, it may be used with the schemes ECKAS-DH1 and
+ * DL/ECKAS-DH2. It assumes that the input keys are valid (see also
+ * Section 7.2.2).
+ */
+public class ECDHBasicAgreement
+    implements BasicAgreement
+{
+    private ECPrivateKeyParameters key;
+
+    public void init(
+        CipherParameters key)
+    {
+        this.key = (ECPrivateKeyParameters)key;
+    }
+
+    public BigInteger calculateAgreement(
+        CipherParameters pubKey)
+    {
+        ECPublicKeyParameters pub = (ECPublicKeyParameters)pubKey;
+        ECPoint P = pub.getQ().multiply(key.getD());
+
+        // if (p.isInfinity()) throw new RuntimeException("d*Q == infinity");
+
+        return P.getX().toBigInteger();
+    }
+}
diff --git a/src/main/java/org/bouncycastle/crypto/digests/OpenSSLDigest.java b/src/main/java/org/bouncycastle/crypto/digests/OpenSSLDigest.java
index ba76577..d2f9f25 100644
--- a/src/main/java/org/bouncycastle/crypto/digests/OpenSSLDigest.java
+++ b/src/main/java/org/bouncycastle/crypto/digests/OpenSSLDigest.java
@@ -30,12 +30,24 @@
     private final String algorithm;
 
     /**
-     * Holds the OpenSSL name of the hashing algorithm, e.g. "sha1";
+     * Holds the EVP_MD for the hashing algorithm, e.g. EVP_get_digestbyname("sha1");
      */
-    private final String openssl;
+    private final int evp_md;
 
     /**
-     * Holds a pointer to the native message digest context.
+     * Holds the output size of the message digest.
+     */
+    private final int size;
+
+    /**
+     * Holds the block size of the message digest.
+     */
+    private final int blockSize;
+
+    /**
+     * Holds a pointer to the native message digest context. It is
+     * lazily initialized to avoid having to reallocate on reset when
+     * its unlikely to be reused.
      */
     private int ctx;
 
@@ -47,25 +59,12 @@
     /**
      * Creates a new OpenSSLMessageDigest instance for the given algorithm
      * name.
-     *
-     * @param algorithm The standard name of the algorithm, e.g. "SHA-1".
-     * @param algorithm The name of the openssl algorithm, e.g. "sha1".
      */
-    private OpenSSLDigest(String algorithm, String openssl) {
+    private OpenSSLDigest(String algorithm, int evp_md, int size, int blockSize) {
         this.algorithm = algorithm;
-        this.openssl = openssl;
-        ctx = NativeCrypto.EVP_MD_CTX_create();
-        try {
-            NativeCrypto.EVP_DigestInit(ctx, openssl);
-        } catch (Exception ex) {
-            throw new RuntimeException(ex.getMessage() + " (" + algorithm + ")");
-        }
-    }
-
-    public int doFinal(byte[] out, int outOff) {
-        int i = NativeCrypto.EVP_DigestFinal(ctx, out, outOff);
-        reset();
-        return i;
+        this.evp_md = evp_md;
+        this.size = size;
+        this.blockSize = blockSize;
     }
 
     public String getAlgorithmName() {
@@ -73,50 +72,88 @@
     }
 
     public int getDigestSize() {
-        return NativeCrypto.EVP_MD_CTX_size(ctx);
+        return size;
     }
 
     public int getByteLength() {
-        return NativeCrypto.EVP_MD_CTX_block_size(ctx);
+        return blockSize;
     }
 
     public void reset() {
-        NativeCrypto.EVP_DigestInit(ctx, openssl);
+        free();
     }
 
     public void update(byte in) {
         singleByte[0] = in;
-        NativeCrypto.EVP_DigestUpdate(ctx, singleByte, 0, 1);
+        update(singleByte, 0, 1);
     }
 
     public void update(byte[] in, int inOff, int len) {
-        NativeCrypto.EVP_DigestUpdate(ctx, in, inOff, len);
+        NativeCrypto.EVP_DigestUpdate(getCtx(), in, inOff, len);
+    }
+
+    public int doFinal(byte[] out, int outOff) {
+        int i = NativeCrypto.EVP_DigestFinal(getCtx(), out, outOff);
+        ctx = 0; // EVP_DigestFinal frees the context as a side effect
+        reset();
+        return i;
+    }
+
+    private int getCtx() {
+        if (ctx == 0) {
+            ctx = NativeCrypto.EVP_DigestInit(evp_md);
+        }
+        return ctx;
+    }
+
+    private void free() {
+        if (ctx != 0) {
+            NativeCrypto.EVP_MD_CTX_destroy(ctx);
+            ctx = 0;
+        }
     }
 
     @Override
     protected void finalize() throws Throwable {
-        super.finalize();
-        NativeCrypto.EVP_MD_CTX_destroy(ctx);
-        ctx = 0;
+        try {
+            free();
+        } finally {
+            super.finalize();
+        }
     }
 
     public static class MD5 extends OpenSSLDigest {
-        public MD5() { super("MD5", "md5"); }
+        private static final int EVP_MD = NativeCrypto.EVP_get_digestbyname("md5");
+        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
+        private static final int BLOCK_SIZE = NativeCrypto.EVP_MD_block_size(EVP_MD);
+        public MD5() { super("MD5", EVP_MD, SIZE, BLOCK_SIZE); }
     }
 
     public static class SHA1 extends OpenSSLDigest {
-        public SHA1() { super("SHA-1", "sha1"); }
+        private static final int EVP_MD = NativeCrypto.EVP_get_digestbyname("sha1");
+        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
+        private static final int BLOCK_SIZE = NativeCrypto.EVP_MD_block_size(EVP_MD);
+        public SHA1() { super("SHA-1", EVP_MD, SIZE, BLOCK_SIZE); }
     }
 
     public static class SHA256 extends OpenSSLDigest {
-        public SHA256() { super("SHA-256", "sha256"); }
+        private static final int EVP_MD = NativeCrypto.EVP_get_digestbyname("sha256");
+        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
+        private static final int BLOCK_SIZE = NativeCrypto.EVP_MD_block_size(EVP_MD);
+        public SHA256() { super("SHA-256", EVP_MD, SIZE, BLOCK_SIZE); }
     }
 
     public static class SHA384 extends OpenSSLDigest {
-        public SHA384() { super("SHA-384", "sha384"); }
+        private static final int EVP_MD = NativeCrypto.EVP_get_digestbyname("sha384");
+        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
+        private static final int BLOCK_SIZE = NativeCrypto.EVP_MD_block_size(EVP_MD);
+        public SHA384() { super("SHA-384", EVP_MD, SIZE, BLOCK_SIZE); }
     }
 
     public static class SHA512 extends OpenSSLDigest {
-        public SHA512() { super("SHA-512", "sha512"); }
+        private static final int EVP_MD = NativeCrypto.EVP_get_digestbyname("sha512");
+        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
+        private static final int BLOCK_SIZE = NativeCrypto.EVP_MD_block_size(EVP_MD);
+        public SHA512() { super("SHA-512", EVP_MD, SIZE, BLOCK_SIZE); }
     }
 }
diff --git a/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java b/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java
new file mode 100644
index 0000000..d77bd74
--- /dev/null
+++ b/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java
@@ -0,0 +1,53 @@
+package org.bouncycastle.crypto.generators;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import org.bouncycastle.math.ec.ECConstants;
+import org.bouncycastle.math.ec.ECPoint;
+
+public class ECKeyPairGenerator
+    implements AsymmetricCipherKeyPairGenerator, ECConstants
+{
+    ECDomainParameters  params;
+    SecureRandom        random;
+
+    public void init(
+        KeyGenerationParameters param)
+    {
+        ECKeyGenerationParameters  ecP = (ECKeyGenerationParameters)param;
+
+        this.random = ecP.getRandom();
+        this.params = ecP.getDomainParameters();
+    }
+
+    /**
+     * Given the domain parameters this routine generates an EC key
+     * pair in accordance with X9.62 section 5.2.1 pages 26, 27.
+     */
+    public AsymmetricCipherKeyPair generateKeyPair()
+    {
+        BigInteger n = params.getN();
+        int        nBitLength = n.bitLength();
+        BigInteger d;
+
+        do
+        {
+            d = new BigInteger(nBitLength, random);
+        }
+        while (d.equals(ZERO)  || (d.compareTo(n) >= 0));
+
+        ECPoint Q = params.getG().multiply(d);
+
+        return new AsymmetricCipherKeyPair(
+            new ECPublicKeyParameters(Q, params),
+            new ECPrivateKeyParameters(d, params));
+    }
+}
diff --git a/src/main/java/org/bouncycastle/crypto/params/ECDomainParameters.java b/src/main/java/org/bouncycastle/crypto/params/ECDomainParameters.java
new file mode 100644
index 0000000..95a3ec9
--- /dev/null
+++ b/src/main/java/org/bouncycastle/crypto/params/ECDomainParameters.java
@@ -0,0 +1,81 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.math.ec.ECConstants;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+
+public class ECDomainParameters
+    implements ECConstants
+{
+    ECCurve     curve;
+    byte[]      seed;
+    ECPoint     G;
+    BigInteger  n;
+    BigInteger  h;
+
+    public ECDomainParameters(
+        ECCurve     curve,
+        ECPoint     G,
+        BigInteger  n)
+    {
+        this.curve = curve;
+        this.G = G;
+        this.n = n;
+        this.h = ONE;
+        this.seed = null;
+    }
+
+    public ECDomainParameters(
+        ECCurve     curve,
+        ECPoint     G,
+        BigInteger  n,
+        BigInteger  h)
+    {
+        this.curve = curve;
+        this.G = G;
+        this.n = n;
+        this.h = h;
+        this.seed = null;
+    }
+
+    public ECDomainParameters(
+        ECCurve     curve,
+        ECPoint     G,
+        BigInteger  n,
+        BigInteger  h,
+        byte[]      seed)
+    {
+        this.curve = curve;
+        this.G = G;
+        this.n = n;
+        this.h = h;
+        this.seed = seed;
+    }
+
+    public ECCurve getCurve()
+    {
+        return curve;
+    }
+
+    public ECPoint getG()
+    {
+        return G;
+    }
+
+    public BigInteger getN()
+    {
+        return n;
+    }
+
+    public BigInteger getH()
+    {
+        return h;
+    }
+
+    public byte[] getSeed()
+    {
+        return seed;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/crypto/params/ECKeyGenerationParameters.java b/src/main/java/org/bouncycastle/crypto/params/ECKeyGenerationParameters.java
new file mode 100644
index 0000000..be3f20f
--- /dev/null
+++ b/src/main/java/org/bouncycastle/crypto/params/ECKeyGenerationParameters.java
@@ -0,0 +1,25 @@
+package org.bouncycastle.crypto.params;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.KeyGenerationParameters;
+
+public class ECKeyGenerationParameters
+    extends KeyGenerationParameters
+{
+    private ECDomainParameters  domainParams;
+
+    public ECKeyGenerationParameters(
+        ECDomainParameters      domainParams,
+        SecureRandom            random)
+    {
+        super(random, domainParams.getN().bitLength());
+
+        this.domainParams = domainParams;
+    }
+
+    public ECDomainParameters getDomainParameters()
+    {
+        return domainParams;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/crypto/params/ECKeyParameters.java b/src/main/java/org/bouncycastle/crypto/params/ECKeyParameters.java
new file mode 100644
index 0000000..19825c5
--- /dev/null
+++ b/src/main/java/org/bouncycastle/crypto/params/ECKeyParameters.java
@@ -0,0 +1,21 @@
+package org.bouncycastle.crypto.params;
+
+public class ECKeyParameters
+    extends AsymmetricKeyParameter
+{
+    ECDomainParameters params;
+
+    protected ECKeyParameters(
+        boolean             isPrivate,
+        ECDomainParameters  params)
+    {
+        super(isPrivate);
+
+        this.params = params;
+    }
+
+    public ECDomainParameters getParameters()
+    {
+        return params;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/crypto/params/ECPrivateKeyParameters.java b/src/main/java/org/bouncycastle/crypto/params/ECPrivateKeyParameters.java
new file mode 100644
index 0000000..3e49983
--- /dev/null
+++ b/src/main/java/org/bouncycastle/crypto/params/ECPrivateKeyParameters.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+public class ECPrivateKeyParameters
+    extends ECKeyParameters
+{
+    BigInteger d;
+
+    public ECPrivateKeyParameters(
+        BigInteger          d,
+        ECDomainParameters  params)
+    {
+        super(true, params);
+        this.d = d;
+    }
+
+    public BigInteger getD()
+    {
+        return d;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java b/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java
new file mode 100644
index 0000000..5fbea19
--- /dev/null
+++ b/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.crypto.params;
+
+import org.bouncycastle.math.ec.ECPoint;
+
+public class ECPublicKeyParameters
+    extends ECKeyParameters
+{
+    ECPoint Q;
+
+    public ECPublicKeyParameters(
+        ECPoint             Q,
+        ECDomainParameters  params)
+    {
+        super(false, params);
+        this.Q = Q;
+    }
+
+    public ECPoint getQ()
+    {
+        return Q;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java b/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java
new file mode 100644
index 0000000..0341227
--- /dev/null
+++ b/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java
@@ -0,0 +1,164 @@
+package org.bouncycastle.crypto.signers;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DSA;
+import org.bouncycastle.crypto.params.ECKeyParameters;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.math.ec.ECAlgorithms;
+import org.bouncycastle.math.ec.ECConstants;
+import org.bouncycastle.math.ec.ECPoint;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * EC-DSA as described in X9.62
+ */
+public class ECDSASigner
+    implements ECConstants, DSA
+{
+    ECKeyParameters key;
+
+    SecureRandom    random;
+
+    public void init(
+        boolean                 forSigning,
+        CipherParameters        param)
+    {
+        if (forSigning)
+        {
+            if (param instanceof ParametersWithRandom)
+            {
+                ParametersWithRandom    rParam = (ParametersWithRandom)param;
+
+                this.random = rParam.getRandom();
+                this.key = (ECPrivateKeyParameters)rParam.getParameters();
+            }
+            else
+            {
+                this.random = new SecureRandom();
+                this.key = (ECPrivateKeyParameters)param;
+            }
+        }
+        else
+        {
+            this.key = (ECPublicKeyParameters)param;
+        }
+    }
+
+    // 5.3 pg 28
+    /**
+     * generate a signature for the given message using the key we were
+     * initialised with. For conventional DSA the message should be a SHA-1
+     * hash of the message of interest.
+     *
+     * @param message the message that will be verified later.
+     */
+    public BigInteger[] generateSignature(
+        byte[] message)
+    {
+        BigInteger n = key.getParameters().getN();
+        BigInteger e = calculateE(n, message);
+        BigInteger r = null;
+        BigInteger s = null;
+
+        // 5.3.2
+        do // generate s
+        {
+            BigInteger k = null;
+            int        nBitLength = n.bitLength();
+
+            do // generate r
+            {
+                do
+                {
+                    k = new BigInteger(nBitLength, random);
+                }
+                while (k.equals(ZERO));
+
+                ECPoint p = key.getParameters().getG().multiply(k);
+
+                // 5.3.3
+                BigInteger x = p.getX().toBigInteger();
+
+                r = x.mod(n);
+            }
+            while (r.equals(ZERO));
+
+            BigInteger d = ((ECPrivateKeyParameters)key).getD();
+
+            s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n);
+        }
+        while (s.equals(ZERO));
+
+        BigInteger[]  res = new BigInteger[2];
+
+        res[0] = r;
+        res[1] = s;
+
+        return res;
+    }
+
+    // 5.4 pg 29
+    /**
+     * return true if the value r and s represent a DSA signature for
+     * the passed in message (for standard DSA the message should be
+     * a SHA-1 hash of the real message to be verified).
+     */
+    public boolean verifySignature(
+        byte[]      message,
+        BigInteger  r,
+        BigInteger  s)
+    {
+        BigInteger n = key.getParameters().getN();
+        BigInteger e = calculateE(n, message);
+
+        // r in the range [1,n-1]
+        if (r.compareTo(ONE) < 0 || r.compareTo(n) >= 0)
+        {
+            return false;
+        }
+
+        // s in the range [1,n-1]
+        if (s.compareTo(ONE) < 0 || s.compareTo(n) >= 0)
+        {
+            return false;
+        }
+
+        BigInteger c = s.modInverse(n);
+
+        BigInteger u1 = e.multiply(c).mod(n);
+        BigInteger u2 = r.multiply(c).mod(n);
+
+        ECPoint G = key.getParameters().getG();
+        ECPoint Q = ((ECPublicKeyParameters)key).getQ();
+
+        ECPoint point = ECAlgorithms.sumOfTwoMultiplies(G, u1, Q, u2);
+
+        BigInteger v = point.getX().toBigInteger().mod(n);
+
+        return v.equals(r);
+    }
+
+    private BigInteger calculateE(BigInteger n, byte[] message)
+    {  
+        if (n.bitLength() > message.length * 8)
+        {
+            return new BigInteger(1, message);
+        }
+        else
+        {
+            int messageBitLength = message.length * 8;
+            BigInteger trunc = new BigInteger(1, message);
+
+            if (messageBitLength - n.bitLength() > 0)
+            {
+                trunc = trunc.shiftRight(messageBitLength - n.bitLength());
+            }
+
+            return trunc;
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java b/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
index 8f78e08..94c8208 100644
--- a/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
+++ b/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
@@ -7,8 +7,8 @@
 import org.bouncycastle.asn1.DERInteger;
 import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.nist.NISTNamedCurves;
 // BEGIN android-removed
-// import org.bouncycastle.asn1.nist.NISTNamedCurves;
 // import org.bouncycastle.asn1.oiw.ElGamalParameter;
 // END android-removed
 import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
@@ -16,27 +16,25 @@
 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
 import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
 import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure;
+import org.bouncycastle.asn1.sec.ECPrivateKeyStructure;
+import org.bouncycastle.asn1.sec.SECNamedCurves;
 // BEGIN android-removed
-// import org.bouncycastle.asn1.sec.ECPrivateKeyStructure;
-// import org.bouncycastle.asn1.sec.SECNamedCurves;
 // import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
 // END android-removed
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 import org.bouncycastle.asn1.x509.DSAParameter;
-// BEGIN android-removed
-// import org.bouncycastle.asn1.x9.X962NamedCurves;
-// import org.bouncycastle.asn1.x9.X962Parameters;
-// import org.bouncycastle.asn1.x9.X9ECParameters;
-// import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
-// END android-removed
+import org.bouncycastle.asn1.x9.X962NamedCurves;
+import org.bouncycastle.asn1.x9.X962Parameters;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
 import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
 import org.bouncycastle.crypto.params.DHParameters;
 import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
 import org.bouncycastle.crypto.params.DSAParameters;
 import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
 // BEGIN android-removed
-// import org.bouncycastle.crypto.params.ECDomainParameters;
-// import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
 // import org.bouncycastle.crypto.params.ElGamalParameters;
 // import org.bouncycastle.crypto.params.ElGamalPrivateKeyParameters;
 // END android-removed
@@ -129,69 +127,71 @@
         //
         //     return new ElGamalPrivateKeyParameters(derX.getValue(), new ElGamalParameters(params.getP(), params.getG()));
         // }
-        // else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_dsa))
-        // {
-        //     DERInteger derX = (DERInteger)keyInfo.getPrivateKey();
-        //     DEREncodable de = keyInfo.getAlgorithmId().getParameters();
-        //
-        //     DSAParameters parameters = null;
-        //     if (de != null)
-        //     {
-        //         DSAParameter params = DSAParameter.getInstance(de.getDERObject());
-        //         parameters = new DSAParameters(params.getP(), params.getQ(), params.getG());
-        //     }
-        //
-        //     return new DSAPrivateKeyParameters(derX.getValue(), parameters);
-        // }
-        // else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_ecPublicKey))
-        // {
-        //     X962Parameters      params = new X962Parameters((DERObject)keyInfo.getAlgorithmId().getParameters());
-        //     ECDomainParameters  dParams = null;
-        //
-        //     if (params.isNamedCurve())
-        //     {
-        //         DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters();
-        //         X9ECParameters      ecP = X962NamedCurves.getByOID(oid);
-        //
-        //         if (ecP == null)
-        //         {
-        //             ecP = SECNamedCurves.getByOID(oid);
-        //
-        //             if (ecP == null)
-        //             {
-        //                 ecP = NISTNamedCurves.getByOID(oid);
-        //
-        //                 if (ecP == null)
-        //                 {
-        //                     ecP = TeleTrusTNamedCurves.getByOID(oid);
-        //                 }
-        //             }
-        //         }
-        //
-        //         dParams = new ECDomainParameters(
-        //                                     ecP.getCurve(),
-        //                                     ecP.getG(),
-        //                                     ecP.getN(),
-        //                                     ecP.getH(),
-        //                                     ecP.getSeed());
-        //     }
-        //     else
-        //     {
-        //         X9ECParameters ecP = new X9ECParameters(
-        //                     (ASN1Sequence)params.getParameters());
-        //         dParams = new ECDomainParameters(
-        //                                     ecP.getCurve(),
-        //                                     ecP.getG(),
-        //                                     ecP.getN(),
-        //                                     ecP.getH(),
-        //                                     ecP.getSeed());
-        //     }
-        //
-        //     ECPrivateKeyStructure   ec = new ECPrivateKeyStructure((ASN1Sequence)keyInfo.getPrivateKey());
-        //
-        //     return new ECPrivateKeyParameters(ec.getKey(), dParams);
-        // }
         // END android-removed
+        else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_dsa))
+        {
+            DERInteger derX = (DERInteger)keyInfo.getPrivateKey();
+            DEREncodable de = keyInfo.getAlgorithmId().getParameters();
+        
+            DSAParameters parameters = null;
+            if (de != null)
+            {
+                DSAParameter params = DSAParameter.getInstance(de.getDERObject());
+                parameters = new DSAParameters(params.getP(), params.getQ(), params.getG());
+            }
+        
+            return new DSAPrivateKeyParameters(derX.getValue(), parameters);
+        }
+        else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_ecPublicKey))
+        {
+            X962Parameters      params = new X962Parameters((DERObject)keyInfo.getAlgorithmId().getParameters());
+            ECDomainParameters  dParams = null;
+        
+            if (params.isNamedCurve())
+            {
+                DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters();
+                X9ECParameters      ecP = X962NamedCurves.getByOID(oid);
+        
+                if (ecP == null)
+                {
+                    ecP = SECNamedCurves.getByOID(oid);
+        
+                    if (ecP == null)
+                    {
+                        ecP = NISTNamedCurves.getByOID(oid);
+        
+                        // BEGIN android-removed
+                        // if (ecP == null)
+                        // {
+                        //     ecP = TeleTrusTNamedCurves.getByOID(oid);
+                        // }
+                        // END android-removed
+                    }
+                }
+        
+                dParams = new ECDomainParameters(
+                                            ecP.getCurve(),
+                                            ecP.getG(),
+                                            ecP.getN(),
+                                            ecP.getH(),
+                                            ecP.getSeed());
+            }
+            else
+            {
+                X9ECParameters ecP = new X9ECParameters(
+                            (ASN1Sequence)params.getParameters());
+                dParams = new ECDomainParameters(
+                                            ecP.getCurve(),
+                                            ecP.getG(),
+                                            ecP.getN(),
+                                            ecP.getH(),
+                                            ecP.getSeed());
+            }
+        
+            ECPrivateKeyStructure   ec = new ECPrivateKeyStructure((ASN1Sequence)keyInfo.getPrivateKey());
+        
+            return new ECPrivateKeyParameters(ec.getKey(), dParams);
+        }
         else
         {
             throw new RuntimeException("algorithm identifier in key not recognised");
diff --git a/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java b/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
index c0672b5..f28c964 100644
--- a/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
+++ b/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
@@ -10,15 +10,15 @@
 import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.nist.NISTNamedCurves;
 // BEGIN android-removed
-// import org.bouncycastle.asn1.nist.NISTNamedCurves;
 // import org.bouncycastle.asn1.oiw.ElGamalParameter;
 // END android-removed
 import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
 import org.bouncycastle.asn1.pkcs.DHParameter;
 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.sec.SECNamedCurves;
 // BEGIN android-removed
-// import org.bouncycastle.asn1.sec.SECNamedCurves;
 // import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
 // END android-removed
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
@@ -26,21 +26,19 @@
 import org.bouncycastle.asn1.x509.RSAPublicKeyStructure;
 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
 import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
-// BEGIN android-removed
-// import org.bouncycastle.asn1.x9.X962NamedCurves;
-// import org.bouncycastle.asn1.x9.X962Parameters;
-// import org.bouncycastle.asn1.x9.X9ECParameters;
-// import org.bouncycastle.asn1.x9.X9ECPoint;
-// END android-removed
+import org.bouncycastle.asn1.x9.X962NamedCurves;
+import org.bouncycastle.asn1.x9.X962Parameters;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.asn1.x9.X9ECPoint;
 import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
 import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
 import org.bouncycastle.crypto.params.DHParameters;
 import org.bouncycastle.crypto.params.DHPublicKeyParameters;
 import org.bouncycastle.crypto.params.DSAParameters;
 import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
 // BEGIN android-removed
-// import org.bouncycastle.crypto.params.ECDomainParameters;
-// import org.bouncycastle.crypto.params.ECPublicKeyParameters;
 // import org.bouncycastle.crypto.params.ElGamalParameters;
 // import org.bouncycastle.crypto.params.ElGamalPublicKeyParameters;
 // END android-removed
@@ -144,60 +142,60 @@
 
             return new DSAPublicKeyParameters(derY.getValue(), parameters);
         }
-        // BEGIN android-removed
-        // else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_ecPublicKey))
-        // {
-        //     X962Parameters      params = new X962Parameters((DERObject)keyInfo.getAlgorithmId().getParameters());
-        //     ECDomainParameters  dParams = null;
-        //
-        //     if (params.isNamedCurve())
-        //     {
-        //         DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters();
-        //         X9ECParameters      ecP = X962NamedCurves.getByOID(oid);
-        //
-        //         if (ecP == null)
-        //         {
-        //             ecP = SECNamedCurves.getByOID(oid);
-        //
-        //             if (ecP == null)
-        //             {
-        //                 ecP = NISTNamedCurves.getByOID(oid);
-        //
-        //                 if (ecP == null)
-        //                 {
-        //                     ecP = TeleTrusTNamedCurves.getByOID(oid);
-        //                 }
-        //             }
-        //         }
-        //
-        //         dParams = new ECDomainParameters(
-        //                                     ecP.getCurve(),
-        //                                     ecP.getG(),
-        //                                     ecP.getN(),
-        //                                     ecP.getH(),
-        //                                     ecP.getSeed());
-        //     }
-        //     else
-        //     {
-        //         X9ECParameters ecP = new X9ECParameters(
-        //                     (ASN1Sequence)params.getParameters());
-        //         dParams = new ECDomainParameters(
-        //                                     ecP.getCurve(),
-        //                                     ecP.getG(),
-        //                                     ecP.getN(),
-        //                                     ecP.getH(),
-        //                                     ecP.getSeed());
-        //     }
-        //
-        //     DERBitString    bits = keyInfo.getPublicKeyData();
-        //     byte[]          data = bits.getBytes();
-        //     ASN1OctetString key = new DEROctetString(data);
-        //
-        //     X9ECPoint       derQ = new X9ECPoint(dParams.getCurve(), key);
-        //
-        //     return new ECPublicKeyParameters(derQ.getPoint(), dParams);
-        // }
-        // END android-removed
+        else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_ecPublicKey))
+        {
+            X962Parameters      params = new X962Parameters((DERObject)keyInfo.getAlgorithmId().getParameters());
+            ECDomainParameters  dParams = null;
+        
+            if (params.isNamedCurve())
+            {
+                DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters();
+                X9ECParameters      ecP = X962NamedCurves.getByOID(oid);
+        
+                if (ecP == null)
+                {
+                    ecP = SECNamedCurves.getByOID(oid);
+        
+                    if (ecP == null)
+                    {
+                        ecP = NISTNamedCurves.getByOID(oid);
+        
+                        // BEGIN android-removed
+                        // if (ecP == null)
+                        // {
+                        //     ecP = TeleTrusTNamedCurves.getByOID(oid);
+                        // }
+                        // END android-removed
+                    }
+                }
+        
+                dParams = new ECDomainParameters(
+                                            ecP.getCurve(),
+                                            ecP.getG(),
+                                            ecP.getN(),
+                                            ecP.getH(),
+                                            ecP.getSeed());
+            }
+            else
+            {
+                X9ECParameters ecP = new X9ECParameters(
+                            (ASN1Sequence)params.getParameters());
+                dParams = new ECDomainParameters(
+                                            ecP.getCurve(),
+                                            ecP.getG(),
+                                            ecP.getN(),
+                                            ecP.getH(),
+                                            ecP.getSeed());
+            }
+        
+            DERBitString    bits = keyInfo.getPublicKeyData();
+            byte[]          data = bits.getBytes();
+            ASN1OctetString key = new DEROctetString(data);
+        
+            X9ECPoint       derQ = new X9ECPoint(dParams.getCurve(), key);
+        
+            return new ECPublicKeyParameters(derQ.getPoint(), dParams);
+        }
         else
         {
             throw new RuntimeException("algorithm identifier in key not recognised");
diff --git a/src/main/java/org/bouncycastle/jce/interfaces/ECKey.java b/src/main/java/org/bouncycastle/jce/interfaces/ECKey.java
new file mode 100644
index 0000000..0812c12
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/interfaces/ECKey.java
@@ -0,0 +1,15 @@
+package org.bouncycastle.jce.interfaces;
+
+import org.bouncycastle.jce.spec.ECParameterSpec;
+
+/**
+ * generic interface for an Elliptic Curve Key.
+ */
+public interface ECKey
+{
+    /**
+     * return a parameter specification representing the EC domain parameters
+     * for the key.
+     */
+    public ECParameterSpec getParameters();
+}
diff --git a/src/main/java/org/bouncycastle/jce/interfaces/ECPointEncoder.java b/src/main/java/org/bouncycastle/jce/interfaces/ECPointEncoder.java
new file mode 100644
index 0000000..001dab3
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/interfaces/ECPointEncoder.java
@@ -0,0 +1,20 @@
+package org.bouncycastle.jce.interfaces;
+
+/**
+ * All BC elliptic curve keys implement this interface. You need to
+ * cast the key to get access to it.
+ * <p>
+ * By default BC keys produce encodings without point compression,
+ * to turn this on call setPointFormat() with "COMPRESSED".
+ */
+public interface ECPointEncoder
+{
+    /**
+     * Set the formatting for encoding of points. If the String "UNCOMPRESSED" is passed
+     * in point compression will not be used. If the String "COMPRESSED" is passed point
+     * compression will be used. The default is "UNCOMPRESSED".
+     * 
+     * @param style the style to use.
+     */
+    public void setPointFormat(String style);
+}
diff --git a/src/main/java/org/bouncycastle/jce/interfaces/ECPrivateKey.java b/src/main/java/org/bouncycastle/jce/interfaces/ECPrivateKey.java
new file mode 100644
index 0000000..39d80c3
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/interfaces/ECPrivateKey.java
@@ -0,0 +1,16 @@
+package org.bouncycastle.jce.interfaces;
+
+import java.math.BigInteger;
+import java.security.PrivateKey;
+
+/**
+ * interface for Elliptic Curve Private keys.
+ */
+public interface ECPrivateKey
+    extends ECKey, PrivateKey
+{
+    /**
+     * return the private value D.
+     */
+    public BigInteger getD();
+}
diff --git a/src/main/java/org/bouncycastle/jce/interfaces/ECPublicKey.java b/src/main/java/org/bouncycastle/jce/interfaces/ECPublicKey.java
new file mode 100644
index 0000000..db2ecdc
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/interfaces/ECPublicKey.java
@@ -0,0 +1,17 @@
+package org.bouncycastle.jce.interfaces;
+
+import java.security.PublicKey;
+
+import org.bouncycastle.math.ec.ECPoint;
+
+/**
+ * interface for elliptic curve public keys.
+ */
+public interface ECPublicKey
+    extends ECKey, PublicKey
+{
+    /**
+     * return the public point Q
+     */
+    public ECPoint getQ();
+}
diff --git a/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java b/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
index f839a59..b014312 100644
--- a/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
+++ b/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
@@ -45,7 +45,10 @@
 {
     private static String info = "BouncyCastle Security Provider v1.45";
 
-    public static String PROVIDER_NAME = "BC";
+    // BEGIN android-changed
+    //     this constant should be final
+    public static final String PROVIDER_NAME = "BC";
+    // END android-changed
 
     /*
      * Configurable symmetric ciphers
@@ -67,9 +70,7 @@
     private static final String ASYMMETRIC_CIPHER_PACKAGE = "org.bouncycastle.jce.provider.asymmetric.";
     private static final String[] ASYMMETRIC_CIPHERS =
     {
-        // BEGIN android-removed
-        // "EC"
-        // END android-removed
+        "EC"
     };
 
     /**
diff --git a/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java b/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java
index d675024..338680a 100644
--- a/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java
+++ b/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java
@@ -147,9 +147,7 @@
     // BEGIN android-changed
     /**
      * Search the given Set of TrustAnchor's for one that is the
-     * issuer of the given X509 certificate. Uses the specified
-     * provider for signature verification, or the default provider
-     * if null.
+     * issuer of the given X509 certificate.
      *
      * @param cert the X509 certificate
      * @param params used to find the trust anchors and signature provider
@@ -197,46 +195,20 @@
         // BEGIN android-changed
         Iterator iter = params.getTrustAnchors().iterator();
         // END android-changed
-        // BEGIN android-added
-        byte[] certBytes = null;
-        try {
-            certBytes = cert.getEncoded();
-        } catch (Exception e) {
-            // ignore, just continue
-        }
-        // END android-added
         while (iter.hasNext() && trust == null)
         {
             trust = (TrustAnchor) iter.next();
-            // BEGIN android-changed
-            X509Certificate trustCert = trust.getTrustedCert();
-            // END android-changed
-            // BEGIN android-added
-            // If the trust anchor is identical to the certificate we're
-            // done. Just return the anchor.
-            // There is similar code in PKIXCertPathValidatorSpi.
-            try {
-                byte[] trustBytes = trustCert.getEncoded();
-                if (certBytes != null && Arrays.equals(trustBytes, certBytes)) {
-                    return trust;
-                }
-            } catch (Exception e) {
-                // ignore, continue and verify the certificate
-            }
-            // END android-added
-            // BEGIN android-changed
-            if (trustCert != null)
+            if (trust.getTrustedCert() != null)
             {
-                if (certSelectX509.match(trustCert))
+                if (certSelectX509.match(trust.getTrustedCert()))
                 {
-                    trustPublicKey = trustCert.getPublicKey();
+                    trustPublicKey = trust.getTrustedCert().getPublicKey();
                 }
                 else
                 {
                     trust = null;
                 }
             }
-            // END android-changed
             else if (trust.getCAName() != null
                     && trust.getCAPublicKey() != null)
             {
diff --git a/src/main/java/org/bouncycastle/jce/provider/DSABase.java b/src/main/java/org/bouncycastle/jce/provider/DSABase.java
new file mode 100644
index 0000000..b30c11e
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/provider/DSABase.java
@@ -0,0 +1,121 @@
+package org.bouncycastle.jce.provider;
+
+import java.math.BigInteger;
+import java.security.SignatureException;
+import java.security.SignatureSpi;
+import java.security.PrivateKey;
+import java.security.InvalidKeyException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import org.bouncycastle.crypto.DSA;
+import org.bouncycastle.crypto.Digest;
+
+public abstract class DSABase
+    extends SignatureSpi
+    implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+    protected Digest                  digest;
+    protected DSA                     signer;
+    protected DSAEncoder              encoder;
+
+    protected DSABase(
+        Digest                  digest,
+        DSA                     signer,
+        DSAEncoder              encoder)
+    {
+        this.digest = digest;
+        this.signer = signer;
+        this.encoder = encoder;
+    }
+
+    protected void engineInitSign(
+        PrivateKey privateKey)
+    throws InvalidKeyException
+    {
+        engineInitSign(privateKey, null);
+    }
+
+    protected void engineUpdate(
+        byte    b)
+        throws SignatureException
+    {
+        digest.update(b);
+    }
+
+    protected void engineUpdate(
+        byte[]  b,
+        int     off,
+        int     len) 
+        throws SignatureException
+    {
+        digest.update(b, off, len);
+    }
+
+    protected byte[] engineSign()
+        throws SignatureException
+    {
+        byte[]  hash = new byte[digest.getDigestSize()];
+
+        digest.doFinal(hash, 0);
+
+        try
+        {
+            BigInteger[]    sig = signer.generateSignature(hash);
+
+            return encoder.encode(sig[0], sig[1]);
+        }
+        catch (Exception e)
+        {
+            throw new SignatureException(e.toString());
+        }
+    }
+
+    protected boolean engineVerify(
+        byte[]  sigBytes) 
+        throws SignatureException
+    {
+        byte[]  hash = new byte[digest.getDigestSize()];
+
+        digest.doFinal(hash, 0);
+
+        BigInteger[]    sig;
+
+        try
+        {
+            sig = encoder.decode(sigBytes);
+        }
+        catch (Exception e)
+        {
+            throw new SignatureException("error decoding signature bytes.");
+        }
+
+        return signer.verifySignature(hash, sig[0], sig[1]);
+    }
+
+    protected void engineSetParameter(
+        AlgorithmParameterSpec params)
+    {
+        throw new UnsupportedOperationException("engineSetParameter unsupported");
+    }
+
+    /**
+     * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+     */
+    protected void engineSetParameter(
+        String  param,
+        Object  value)
+    {
+        throw new UnsupportedOperationException("engineSetParameter unsupported");
+    }
+
+    /**
+     * @deprecated
+     */
+    protected Object engineGetParameter(
+        String      param)
+    {
+        throw new UnsupportedOperationException("engineSetParameter unsupported");
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/provider/DSAEncoder.java b/src/main/java/org/bouncycastle/jce/provider/DSAEncoder.java
new file mode 100644
index 0000000..e0dc92b
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/provider/DSAEncoder.java
@@ -0,0 +1,13 @@
+package org.bouncycastle.jce.provider;
+
+import java.math.BigInteger;
+import java.io.IOException;
+
+public interface DSAEncoder
+{
+    byte[] encode(BigInteger r, BigInteger s)
+        throws IOException;
+
+    BigInteger[] decode(byte[] sig)
+        throws IOException;
+}
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java b/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java
new file mode 100644
index 0000000..4a12124
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java
@@ -0,0 +1,469 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.ECPrivateKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPrivateKeySpec;
+import java.security.spec.EllipticCurve;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+// END android-removed
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.sec.ECPrivateKeyStructure;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x9.X962Parameters;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import org.bouncycastle.jce.interfaces.ECPointEncoder;
+import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.bouncycastle.jce.provider.asymmetric.ec.EC5Util;
+import org.bouncycastle.jce.provider.asymmetric.ec.ECUtil;
+import org.bouncycastle.jce.spec.ECNamedCurveSpec;
+import org.bouncycastle.math.ec.ECCurve;
+
+public class JCEECPrivateKey
+    implements ECPrivateKey, org.bouncycastle.jce.interfaces.ECPrivateKey, PKCS12BagAttributeCarrier, ECPointEncoder
+{
+    private String          algorithm = "EC";
+    private BigInteger      d;
+    private ECParameterSpec ecSpec;
+    private boolean         withCompression;
+
+    private DERBitString publicKey;
+
+    private PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+    protected JCEECPrivateKey()
+    {
+    }
+
+    public JCEECPrivateKey(
+        ECPrivateKey    key)
+    {
+        this.d = key.getS();
+        this.algorithm = key.getAlgorithm();
+        this.ecSpec = key.getParams();
+    }
+
+    public JCEECPrivateKey(
+        String              algorithm,
+        org.bouncycastle.jce.spec.ECPrivateKeySpec     spec)
+    {
+        this.algorithm = algorithm;
+        this.d = spec.getD();
+
+        if (spec.getParams() != null) // can be null if implicitlyCA
+        {
+            ECCurve curve = spec.getParams().getCurve();
+            EllipticCurve ellipticCurve;
+
+            ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
+
+            this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
+        }
+        else
+        {
+            this.ecSpec = null;
+        }
+    }
+
+
+    public JCEECPrivateKey(
+        String              algorithm,
+        ECPrivateKeySpec    spec)
+    {
+        this.algorithm = algorithm;
+        this.d = spec.getS();
+        this.ecSpec = spec.getParams();
+    }
+
+    public JCEECPrivateKey(
+        String             algorithm,
+        JCEECPrivateKey    key)
+    {
+        this.algorithm = algorithm;
+        this.d = key.d;
+        this.ecSpec = key.ecSpec;
+        this.withCompression = key.withCompression;
+        this.attrCarrier = key.attrCarrier;
+        this.publicKey = key.publicKey;
+    }
+
+    public JCEECPrivateKey(
+        String                  algorithm,
+        ECPrivateKeyParameters  params,
+        JCEECPublicKey          pubKey,
+        ECParameterSpec         spec)
+    {
+        ECDomainParameters      dp = params.getParameters();
+
+        this.algorithm = algorithm;
+        this.d = params.getD();
+
+        if (spec == null)
+        {
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+            this.ecSpec = new ECParameterSpec(
+                            ellipticCurve,
+                            new ECPoint(
+                                    dp.getG().getX().toBigInteger(),
+                                    dp.getG().getY().toBigInteger()),
+                            dp.getN(),
+                            dp.getH().intValue());
+        }
+        else
+        {
+            this.ecSpec = spec;
+        }
+
+        publicKey = getPublicKeyDetails(pubKey);
+    }
+
+    public JCEECPrivateKey(
+        String                  algorithm,
+        ECPrivateKeyParameters  params,
+        JCEECPublicKey          pubKey,
+        org.bouncycastle.jce.spec.ECParameterSpec         spec)
+    {
+        ECDomainParameters      dp = params.getParameters();
+
+        this.algorithm = algorithm;
+        this.d = params.getD();
+
+        if (spec == null)
+        {
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+            this.ecSpec = new ECParameterSpec(
+                            ellipticCurve,
+                            new ECPoint(
+                                    dp.getG().getX().toBigInteger(),
+                                    dp.getG().getY().toBigInteger()),
+                            dp.getN(),
+                            dp.getH().intValue());
+        }
+        else
+        {
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed());
+            
+            this.ecSpec = new ECParameterSpec(
+                                ellipticCurve,
+                                new ECPoint(
+                                        spec.getG().getX().toBigInteger(),
+                                        spec.getG().getY().toBigInteger()),
+                                spec.getN(),
+                                spec.getH().intValue());
+        }
+
+        publicKey = getPublicKeyDetails(pubKey);
+    }
+
+    public JCEECPrivateKey(
+        String                  algorithm,
+        ECPrivateKeyParameters  params)
+    {
+        this.algorithm = algorithm;
+        this.d = params.getD();
+        this.ecSpec = null;
+    }
+
+    JCEECPrivateKey(
+        PrivateKeyInfo      info)
+    {
+        populateFromPrivKeyInfo(info);
+    }
+
+    private void populateFromPrivKeyInfo(PrivateKeyInfo info)
+    {
+        X962Parameters params = new X962Parameters((DERObject)info.getAlgorithmId().getParameters());
+
+        if (params.isNamedCurve())
+        {
+            DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters();
+            X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+
+            // BEGIN android-removed
+            // if (ecP == null) // GOST Curve
+            // {
+            //     ECDomainParameters gParam = ECGOST3410NamedCurves.getByOID(oid);
+            //     EllipticCurve ellipticCurve = EC5Util.convertCurve(gParam.getCurve(), gParam.getSeed());
+            //
+            //     ecSpec = new ECNamedCurveSpec(
+            //             ECGOST3410NamedCurves.getName(oid),
+            //             ellipticCurve,
+            //             new ECPoint(
+            //                     gParam.getG().getX().toBigInteger(),
+            //                     gParam.getG().getY().toBigInteger()),
+            //             gParam.getN(),
+            //             gParam.getH());
+            // }
+            // else
+            // END android-removed
+            {
+                EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
+
+                ecSpec = new ECNamedCurveSpec(
+                        ECUtil.getCurveName(oid),
+                        ellipticCurve,
+                        new ECPoint(
+                                ecP.getG().getX().toBigInteger(),
+                                ecP.getG().getY().toBigInteger()),
+                        ecP.getN(),
+                        ecP.getH());
+            }
+        }
+        else if (params.isImplicitlyCA())
+        {
+            ecSpec = null;
+        }
+        else
+        {
+            X9ECParameters      ecP = new X9ECParameters((ASN1Sequence)params.getParameters());
+            EllipticCurve       ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
+
+            this.ecSpec = new ECParameterSpec(
+                ellipticCurve,
+                new ECPoint(
+                        ecP.getG().getX().toBigInteger(),
+                        ecP.getG().getY().toBigInteger()),
+                ecP.getN(),
+                ecP.getH().intValue());
+        }
+
+        if (info.getPrivateKey() instanceof DERInteger)
+        {
+            DERInteger          derD = (DERInteger)info.getPrivateKey();
+
+            this.d = derD.getValue();
+        }
+        else
+        {
+            ECPrivateKeyStructure ec = new ECPrivateKeyStructure((ASN1Sequence)info.getPrivateKey());
+
+            this.d = ec.getKey();
+            this.publicKey = ec.getPublicKey();
+        }
+    }
+
+    public String getAlgorithm()
+    {
+        return algorithm;
+    }
+
+    /**
+     * return the encoding format we produce in getEncoded().
+     *
+     * @return the string "PKCS#8"
+     */
+    public String getFormat()
+    {
+        return "PKCS#8";
+    }
+
+    /**
+     * Return a PKCS8 representation of the key. The sequence returned
+     * represents a full PrivateKeyInfo object.
+     *
+     * @return a PKCS8 representation of the key.
+     */
+    public byte[] getEncoded()
+    {
+        X962Parameters          params;
+
+        if (ecSpec instanceof ECNamedCurveSpec)
+        {
+            DERObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
+            
+            params = new X962Parameters(curveOid);
+        }
+        else if (ecSpec == null)
+        {
+            params = new X962Parameters(DERNull.INSTANCE);
+        }
+        else
+        {
+            ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
+
+            X9ECParameters ecP = new X9ECParameters(
+                curve,
+                EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
+                ecSpec.getOrder(),
+                BigInteger.valueOf(ecSpec.getCofactor()),
+                ecSpec.getCurve().getSeed());
+
+            params = new X962Parameters(ecP);
+        }
+        
+        PrivateKeyInfo          info;
+        ECPrivateKeyStructure keyStructure;
+
+        if (publicKey != null)
+        {
+            keyStructure = new ECPrivateKeyStructure(this.getS(), publicKey, params);
+        }
+        else
+        {
+            keyStructure = new ECPrivateKeyStructure(this.getS(), params);
+        }
+
+        // BEGIN android-removed
+        // if (algorithm.equals("ECGOST3410"))
+        // {
+        //     info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params.getDERObject()), keyStructure.getDERObject());
+        // }
+        // else
+        // END android-removed
+        {
+
+            info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params.getDERObject()), keyStructure.getDERObject());
+        }
+
+        return info.getDEREncoded();
+    }
+
+    public ECParameterSpec getParams()
+    {
+        return ecSpec;
+    }
+
+    public org.bouncycastle.jce.spec.ECParameterSpec getParameters()
+    {
+        if (ecSpec == null)
+        {
+            return null;
+        }
+        
+        return EC5Util.convertSpec(ecSpec, withCompression);
+    }
+
+    org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec()
+    {
+        if (ecSpec != null)
+        {
+            return EC5Util.convertSpec(ecSpec, withCompression);
+        }
+
+        return ProviderUtil.getEcImplicitlyCa();
+    }
+
+    public BigInteger getS()
+    {
+        return d;
+    }
+
+    public BigInteger getD()
+    {
+        return d;
+    }
+    
+    public void setBagAttribute(
+        DERObjectIdentifier oid,
+        DEREncodable        attribute)
+    {
+        attrCarrier.setBagAttribute(oid, attribute);
+    }
+
+    public DEREncodable getBagAttribute(
+        DERObjectIdentifier oid)
+    {
+        return attrCarrier.getBagAttribute(oid);
+    }
+
+    public Enumeration getBagAttributeKeys()
+    {
+        return attrCarrier.getBagAttributeKeys();
+    }
+
+    public void setPointFormat(String style)
+    {
+       withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+    }
+
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof JCEECPrivateKey))
+        {
+            return false;
+        }
+
+        JCEECPrivateKey other = (JCEECPrivateKey)o;
+
+        return getD().equals(other.getD()) && (engineGetSpec().equals(other.engineGetSpec()));
+    }
+
+    public int hashCode()
+    {
+        return getD().hashCode() ^ engineGetSpec().hashCode();
+    }
+
+    public String toString()
+    {
+        StringBuffer    buf = new StringBuffer();
+        String          nl = System.getProperty("line.separator");
+
+        buf.append("EC Private Key").append(nl);
+        buf.append("             S: ").append(this.d.toString(16)).append(nl);
+
+        return buf.toString();
+
+    }
+
+    private DERBitString getPublicKeyDetails(JCEECPublicKey   pub)
+    {
+        try
+        {
+            SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Object.fromByteArray(pub.getEncoded()));
+
+            return info.getPublicKeyData();
+        }
+        catch (IOException e)
+        {   // should never happen
+            return null;
+        }
+    }
+
+    private void readObject(
+        ObjectInputStream in)
+        throws IOException, ClassNotFoundException
+    {
+        byte[] enc = (byte[])in.readObject();
+
+        populateFromPrivKeyInfo(PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(enc)));
+
+        this.algorithm = (String)in.readObject();
+        this.withCompression = in.readBoolean();
+        this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+        attrCarrier.readObject(in);
+    }
+
+    private void writeObject(
+        ObjectOutputStream out)
+        throws IOException
+    {
+        out.writeObject(this.getEncoded());
+        out.writeObject(algorithm);
+        out.writeBoolean(withCompression);
+
+        attrCarrier.writeObject(out);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java b/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java
new file mode 100644
index 0000000..92b478a
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java
@@ -0,0 +1,528 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPublicKeySpec;
+import java.security.spec.EllipticCurve;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+// import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
+// END android-removed
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x9.X962Parameters;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.asn1.x9.X9ECPoint;
+import org.bouncycastle.asn1.x9.X9IntegerConverter;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+// BEGIN android-removed
+// import org.bouncycastle.jce.ECGOST3410NamedCurveTable;
+// END android-removed
+import org.bouncycastle.jce.interfaces.ECPointEncoder;
+import org.bouncycastle.jce.provider.asymmetric.ec.EC5Util;
+import org.bouncycastle.jce.provider.asymmetric.ec.ECUtil;
+// BEGIN android-removed
+// import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
+// END android-removed
+import org.bouncycastle.jce.spec.ECNamedCurveSpec;
+import org.bouncycastle.math.ec.ECCurve;
+
+public class JCEECPublicKey
+    implements ECPublicKey, org.bouncycastle.jce.interfaces.ECPublicKey, ECPointEncoder
+{
+    private String                  algorithm = "EC";
+    private org.bouncycastle.math.ec.ECPoint q;
+    private ECParameterSpec         ecSpec;
+    private boolean                 withCompression;
+    // BEGIN android-removed
+    // private GOST3410PublicKeyAlgParameters       gostParams;
+    // END android-removed
+
+    public JCEECPublicKey(
+        String              algorithm,
+        JCEECPublicKey      key)
+    {
+        this.algorithm = algorithm;
+        this.q = key.q;
+        this.ecSpec = key.ecSpec;
+        this.withCompression = key.withCompression;
+        // BEGIN android-removed
+        // this.gostParams = key.gostParams;
+        // END android-removed
+    }
+    
+    public JCEECPublicKey(
+        String              algorithm,
+        ECPublicKeySpec     spec)
+    {
+        this.algorithm = algorithm;
+        this.ecSpec = spec.getParams();
+        this.q = EC5Util.convertPoint(ecSpec, spec.getW(), false);
+    }
+
+    public JCEECPublicKey(
+        String              algorithm,
+        org.bouncycastle.jce.spec.ECPublicKeySpec     spec)
+    {
+        this.algorithm = algorithm;
+        this.q = spec.getQ();
+
+        if (spec.getParams() != null) // can be null if implictlyCa
+        {
+            ECCurve curve = spec.getParams().getCurve();
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
+
+            this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
+        }
+        else
+        {
+            if (q.getCurve() == null)
+            {
+                org.bouncycastle.jce.spec.ECParameterSpec s = ProviderUtil.getEcImplicitlyCa();
+
+                q = s.getCurve().createPoint(q.getX().toBigInteger(), q.getY().toBigInteger(), false);
+            }               
+            this.ecSpec = null;
+        }
+    }
+    
+    public JCEECPublicKey(
+        String                  algorithm,
+        ECPublicKeyParameters   params,
+        ECParameterSpec         spec)
+    {
+        ECDomainParameters      dp = params.getParameters();
+
+        this.algorithm = algorithm;
+        this.q = params.getQ();
+
+        if (spec == null)
+        {
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+            this.ecSpec = createSpec(ellipticCurve, dp);
+        }
+        else
+        {
+            this.ecSpec = spec;
+        }
+    }
+
+    public JCEECPublicKey(
+        String                  algorithm,
+        ECPublicKeyParameters   params,
+        org.bouncycastle.jce.spec.ECParameterSpec         spec)
+    {
+        ECDomainParameters      dp = params.getParameters();
+
+        this.algorithm = algorithm;
+        this.q = params.getQ();
+
+        if (spec == null)
+        {
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+            this.ecSpec = createSpec(ellipticCurve, dp);
+        }
+        else
+        {
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed());
+
+            this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec);
+        }
+    }
+
+    /*
+     * called for implicitCA
+     */
+    public JCEECPublicKey(
+        String                  algorithm,
+        ECPublicKeyParameters   params)
+    {
+        this.algorithm = algorithm;
+        this.q = params.getQ();
+        this.ecSpec = null;
+    }
+
+    private ECParameterSpec createSpec(EllipticCurve ellipticCurve, ECDomainParameters dp)
+    {
+        return new ECParameterSpec(
+                ellipticCurve,
+                new ECPoint(
+                        dp.getG().getX().toBigInteger(),
+                        dp.getG().getY().toBigInteger()),
+                        dp.getN(),
+                        dp.getH().intValue());
+    }
+    
+    public JCEECPublicKey(
+        ECPublicKey     key)
+    {
+        this.algorithm = key.getAlgorithm();
+        this.ecSpec = key.getParams();
+        this.q = EC5Util.convertPoint(this.ecSpec, key.getW(), false);
+    }
+
+    JCEECPublicKey(
+        SubjectPublicKeyInfo    info)
+    {
+        populateFromPubKeyInfo(info);
+    }
+
+    private void populateFromPubKeyInfo(SubjectPublicKeyInfo info)
+    {
+        // BEGIN android-removed
+        // if (info.getAlgorithmId().getObjectId().equals(CryptoProObjectIdentifiers.gostR3410_2001))
+        // {
+        //     DERBitString bits = info.getPublicKeyData();
+        //     ASN1OctetString key;
+        //     this.algorithm = "ECGOST3410";
+        //
+        //     try
+        //     {
+        //         key = (ASN1OctetString) ASN1Object.fromByteArray(bits.getBytes());
+        //     }
+        //     catch (IOException ex)
+        //     {
+        //         throw new IllegalArgumentException("error recovering public key");
+        //     }
+        //
+        //     byte[]          keyEnc = key.getOctets();
+        //     byte[]          x = new byte[32];
+        //     byte[]          y = new byte[32];
+        //
+        //     for (int i = 0; i != x.length; i++)
+        //     {
+        //         x[i] = keyEnc[32 - 1 - i];
+        //     }
+        //
+        //     for (int i = 0; i != y.length; i++)
+        //     {
+        //         y[i] = keyEnc[64 - 1 - i];
+        //     }
+        //
+        //     gostParams = new GOST3410PublicKeyAlgParameters((ASN1Sequence)info.getAlgorithmId().getParameters());
+        //
+        //     ECNamedCurveParameterSpec spec = ECGOST3410NamedCurveTable.getParameterSpec(ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()));
+        //
+        //     ECCurve curve = spec.getCurve();
+        //     EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getSeed());
+        //
+        //     this.q = curve.createPoint(new BigInteger(1, x), new BigInteger(1, y), false);
+        //
+        //     ecSpec = new ECNamedCurveSpec(
+        //             ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()),
+        //             ellipticCurve,
+        //             new ECPoint(
+        //                     spec.getG().getX().toBigInteger(),
+        //                     spec.getG().getY().toBigInteger()),
+        //                     spec.getN(), spec.getH());
+        //
+        // }
+        // else
+        // END android-removed
+        {
+            X962Parameters params = new X962Parameters((DERObject)info.getAlgorithmId().getParameters());
+            ECCurve                 curve;
+            EllipticCurve           ellipticCurve;
+
+            if (params.isNamedCurve())
+            {
+                DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters();
+                X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+
+                curve = ecP.getCurve();
+                ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed());
+
+                ecSpec = new ECNamedCurveSpec(
+                        ECUtil.getCurveName(oid),
+                        ellipticCurve,
+                        new ECPoint(
+                                ecP.getG().getX().toBigInteger(),
+                                ecP.getG().getY().toBigInteger()),
+                        ecP.getN(),
+                        ecP.getH());
+            }
+            else if (params.isImplicitlyCA())
+            {
+                ecSpec = null;
+                curve = ProviderUtil.getEcImplicitlyCa().getCurve();
+            }
+            else
+            {
+                X9ECParameters          ecP = new X9ECParameters((ASN1Sequence)params.getParameters());
+
+                curve = ecP.getCurve();
+                ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed());
+
+                this.ecSpec = new ECParameterSpec(
+                        ellipticCurve,
+                        new ECPoint(
+                                ecP.getG().getX().toBigInteger(),
+                                ecP.getG().getY().toBigInteger()),
+                        ecP.getN(),
+                        ecP.getH().intValue());
+            }
+
+            DERBitString    bits = info.getPublicKeyData();
+            byte[]          data = bits.getBytes();
+            ASN1OctetString key = new DEROctetString(data);
+
+            //
+            // extra octet string - one of our old certs...
+            //
+            if (data[0] == 0x04 && data[1] == data.length - 2
+                && (data[2] == 0x02 || data[2] == 0x03))
+            {
+                int qLength = new X9IntegerConverter().getByteLength(curve);
+
+                if (qLength >= data.length - 3)
+                {
+                    try
+                    {
+                        key = (ASN1OctetString) ASN1Object.fromByteArray(data);
+                    }
+                    catch (IOException ex)
+                    {
+                        throw new IllegalArgumentException("error recovering public key");
+                    }
+                }
+            }
+            X9ECPoint derQ = new X9ECPoint(curve, key);
+
+            this.q = derQ.getPoint();
+        }
+    }
+
+    public String getAlgorithm()
+    {
+        return algorithm;
+    }
+
+    public String getFormat()
+    {
+        return "X.509";
+    }
+
+    public byte[] getEncoded()
+    {
+        ASN1Encodable        params;
+        SubjectPublicKeyInfo info;
+
+        // BEGIN android-removed
+        // if (algorithm.equals("ECGOST3410"))
+        // {
+        //     if (gostParams != null)
+        //     {
+        //         params = gostParams;
+        //     }
+        //     else
+        //     {
+        //         if (ecSpec instanceof ECNamedCurveSpec)
+        //         {
+        //             params = new GOST3410PublicKeyAlgParameters(
+        //                            ECGOST3410NamedCurves.getOID(((ECNamedCurveSpec)ecSpec).getName()),
+        //                            CryptoProObjectIdentifiers.gostR3411_94_CryptoProParamSet);
+        //         }
+        //         else
+        //         {   // strictly speaking this may not be applicable...
+        //             ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
+        //
+        //             X9ECParameters ecP = new X9ECParameters(
+        //                 curve,
+        //                 EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
+        //                 ecSpec.getOrder(),
+        //                 BigInteger.valueOf(ecSpec.getCofactor()),
+        //                 ecSpec.getCurve().getSeed());
+        //
+        //             params = new X962Parameters(ecP);
+        //         }
+        //     }
+        //
+        //     BigInteger      bX = this.q.getX().toBigInteger();
+        //     BigInteger      bY = this.q.getY().toBigInteger();
+        //     byte[]          encKey = new byte[64];
+        //
+        //     extractBytes(encKey, 0, bX);
+        //     extractBytes(encKey, 32, bY);
+        //
+        //     info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params.getDERObject()), new DEROctetString(encKey));
+        // }
+        // else
+        // END android-removed
+        {
+            if (ecSpec instanceof ECNamedCurveSpec)
+            {
+                DERObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
+                
+                params = new X962Parameters(curveOid);
+            }
+            else if (ecSpec == null)
+            {
+                params = new X962Parameters(DERNull.INSTANCE);
+            }
+            else
+            {
+                ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
+
+                X9ECParameters ecP = new X9ECParameters(
+                    curve,
+                    EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
+                    ecSpec.getOrder(),
+                    BigInteger.valueOf(ecSpec.getCofactor()),
+                    ecSpec.getCurve().getSeed());
+
+                params = new X962Parameters(ecP);
+            }
+
+            ECCurve curve = this.engineGetQ().getCurve();
+            ASN1OctetString p = (ASN1OctetString)
+                new X9ECPoint(curve.createPoint(this.getQ().getX().toBigInteger(), this.getQ().getY().toBigInteger(), withCompression)).getDERObject();
+
+            info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params.getDERObject()), p.getOctets());
+        }
+
+        return info.getDEREncoded();
+    }
+
+    private void extractBytes(byte[] encKey, int offSet, BigInteger bI)
+    {
+        byte[] val = bI.toByteArray();
+        if (val.length < 32)
+        {
+            byte[] tmp = new byte[32];
+            System.arraycopy(val, 0, tmp, tmp.length - val.length, val.length);
+        }
+
+        for (int i = 0; i != 32; i++)
+        {
+            encKey[offSet + i] = val[val.length - 1 - i];
+        }
+    }
+
+    public ECParameterSpec getParams()
+    {
+        return ecSpec;
+    }
+
+    public org.bouncycastle.jce.spec.ECParameterSpec getParameters()
+    {
+        if (ecSpec == null)     // implictlyCA
+        {
+            return null;
+        }
+
+        return EC5Util.convertSpec(ecSpec, withCompression);
+    }
+
+    public ECPoint getW()
+    {
+        return new ECPoint(q.getX().toBigInteger(), q.getY().toBigInteger());
+    }
+
+    public org.bouncycastle.math.ec.ECPoint getQ()
+    {
+        if (ecSpec == null)
+        {
+            if (q instanceof org.bouncycastle.math.ec.ECPoint.Fp)
+            {
+                return new org.bouncycastle.math.ec.ECPoint.Fp(null, q.getX(), q.getY());
+            }
+            else
+            {
+                return new org.bouncycastle.math.ec.ECPoint.F2m(null, q.getX(), q.getY());
+            }
+        }
+
+        return q;
+    }
+
+    public org.bouncycastle.math.ec.ECPoint engineGetQ()
+    {
+        return q;
+    }
+
+    org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec()
+    {
+        if (ecSpec != null)
+        {
+            return EC5Util.convertSpec(ecSpec, withCompression);
+        }
+
+        return ProviderUtil.getEcImplicitlyCa();
+    }
+
+    public String toString()
+    {
+        StringBuffer    buf = new StringBuffer();
+        String          nl = System.getProperty("line.separator");
+
+        buf.append("EC Public Key").append(nl);
+        buf.append("            X: ").append(this.q.getX().toBigInteger().toString(16)).append(nl);
+        buf.append("            Y: ").append(this.q.getY().toBigInteger().toString(16)).append(nl);
+
+        return buf.toString();
+
+    }
+    
+    public void setPointFormat(String style)
+    {
+       withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+    }
+
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof JCEECPublicKey))
+        {
+            return false;
+        }
+
+        JCEECPublicKey other = (JCEECPublicKey)o;
+
+        return engineGetQ().equals(other.engineGetQ()) && (engineGetSpec().equals(other.engineGetSpec()));
+    }
+
+    public int hashCode()
+    {
+        return engineGetQ().hashCode() ^ engineGetSpec().hashCode();
+    }
+
+    private void readObject(
+        ObjectInputStream in)
+        throws IOException, ClassNotFoundException
+    {
+        byte[] enc = (byte[])in.readObject();
+
+        populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(ASN1Object.fromByteArray(enc)));
+
+        this.algorithm = (String)in.readObject();
+        this.withCompression = in.readBoolean();
+    }
+
+    private void writeObject(
+        ObjectOutputStream out)
+        throws IOException
+    {
+        out.writeObject(this.getEncoded());
+        out.writeObject(algorithm);
+        out.writeBoolean(withCompression);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCEKeyGenerator.java b/src/main/java/org/bouncycastle/jce/provider/JCEKeyGenerator.java
index 8108f4e..7515013 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCEKeyGenerator.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JCEKeyGenerator.java
@@ -57,6 +57,11 @@
     {
         try
         {
+            // BEGIN android-added
+            if (random == null) {
+                random = new SecureRandom();
+            }
+            // END android-added
             engine.init(new KeyGenerationParameters(random, keySize));
             uninitialised = false;
         }
diff --git a/src/main/java/org/bouncycastle/jce/provider/JDKKeyFactory.java b/src/main/java/org/bouncycastle/jce/provider/JDKKeyFactory.java
index 8ee9a64..b9aca26 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JDKKeyFactory.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JDKKeyFactory.java
@@ -144,6 +144,20 @@
            
            return new DHPublicKeySpec(k.getY(), k.getParams().getP(), k.getParams().getG());
        }
+       // BEGIN android-added
+       else if (spec.isAssignableFrom(DSAPublicKeySpec.class) && key instanceof DSAPublicKey)
+       {
+            DSAPublicKey    k = (DSAPublicKey)key;
+
+            return new DSAPublicKeySpec(k.getY(), k.getParams().getP(), k.getParams().getQ(), k.getParams().getG());
+       }
+       else if (spec.isAssignableFrom(DSAPrivateKeySpec.class) && key instanceof DSAPrivateKey)
+       {
+            DSAPrivateKey    k = (DSAPrivateKey)key;
+
+            return new DSAPrivateKeySpec(k.getX(), k.getParams().getP(), k.getParams().getQ(), k.getParams().getG());
+       }
+       // END android-added
 
        throw new RuntimeException("not implemented yet " + key + " " + spec);
     }
@@ -261,11 +275,11 @@
         {
             return new JDKDSAPublicKey(info);
         }
+        else if (algOid.equals(X9ObjectIdentifiers.id_ecPublicKey))
+        {
+            return new JCEECPublicKey(info);
+        }
         // BEGIN android-removed
-        // else if (algOid.equals(X9ObjectIdentifiers.id_ecPublicKey))
-        // {
-        //     return new JCEECPublicKey(info);
-        // }
         // else if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_94))
         // {
         //     return new JDKGOST3410PublicKey(info);
@@ -317,11 +331,11 @@
         {
               return new JDKDSAPrivateKey(info);
         }
+        else if (algOid.equals(X9ObjectIdentifiers.id_ecPublicKey))
+        {
+              return new JCEECPrivateKey(info);
+        }
         // BEGIN android-removed
-        // else if (algOid.equals(X9ObjectIdentifiers.id_ecPublicKey))
-        // {
-        //       return new JCEECPrivateKey(info);
-        // }
         // else if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_94))
         // {
         //       return new JDKGOST3410PrivateKey(info);
diff --git a/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java b/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java
index bc3e193..f6148cd 100644
--- a/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java
+++ b/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java
@@ -187,13 +187,10 @@
         // (d)
         // 
         TrustAnchor trust;
-        // BEGIN android-added
-        X509Certificate lastCert = (X509Certificate) certs.get(certs.size() - 1);
-        // END android-added
         try
         {
             // BEGIN android-changed
-            trust = CertPathValidatorUtilities.findTrustAnchor(lastCert,
+            trust = CertPathValidatorUtilities.findTrustAnchor((X509Certificate) certs.get(certs.size() - 1),
                     indexedParams != null ? indexedParams : paramsPKIX);
             // END android-changed
         }
@@ -291,25 +288,12 @@
         X500Principal workingIssuerName;
 
         X509Certificate sign = trust.getTrustedCert();
-        // BEGIN android-added
-        boolean trustAnchorInChain = false;
-        // END android-added
         try
         {
             if (sign != null)
             {
                 workingIssuerName = CertPathValidatorUtilities.getSubjectPrincipal(sign);
                 workingPublicKey = sign.getPublicKey();
-                // BEGIN android-added
-                // There is similar code in CertPathValidatorUtilities.
-                try {
-                    byte[] trustBytes = sign.getEncoded();
-                    byte[] certBytes = lastCert.getEncoded();
-                    trustAnchorInChain = Arrays.equals(trustBytes, certBytes);
-                } catch(Exception e) {
-                    // ignore, continue with trustAnchorInChain being false
-                }
-                // END android-added
             }
             else
             {
@@ -395,10 +379,8 @@
             // 6.1.3
             //
 
-            // BEGIN android-changed
             RFC3280CertPathUtilities.processCertA(certPath, paramsPKIX, index, workingPublicKey,
-                verificationAlreadyPerformed, workingIssuerName, sign, i, trustAnchorInChain);
-            // END android-changed
+                verificationAlreadyPerformed, workingIssuerName, sign);
 
             RFC3280CertPathUtilities.processCertBC(certPath, index, nameConstraintValidator);
 
@@ -415,18 +397,11 @@
 
             if (i != n)
             {
-                // BEGIN android-added
-                if (!(i == 1 && trustAnchorInChain)) // if not at the root certificate
-                {
-                // END android-added
                 if (cert != null && cert.getVersion() == 1)
                 {
                     throw new CertPathValidatorException("Version 1 certificates can't be used as CA ones.", null,
                             certPath, index);
                 }
-                // BEGIN android-added
-                }
-                // END android-added
 
                 RFC3280CertPathUtilities.prepareNextCertA(certPath, index);
 
@@ -450,9 +425,7 @@
                 inhibitAnyPolicy = RFC3280CertPathUtilities.prepareNextCertJ(certPath, index, inhibitAnyPolicy);
 
                 // (k)
-                // BEGIN android-changed
-                RFC3280CertPathUtilities.prepareNextCertK(certPath, index, i, trustAnchorInChain);
-                // END android-changed
+                RFC3280CertPathUtilities.prepareNextCertK(certPath, index);
 
                 // (l)
                 maxPathLength = RFC3280CertPathUtilities.prepareNextCertL(certPath, index, maxPathLength);
diff --git a/src/main/java/org/bouncycastle/jce/provider/ProviderUtil.java b/src/main/java/org/bouncycastle/jce/provider/ProviderUtil.java
index b4f700d..880437d 100644
--- a/src/main/java/org/bouncycastle/jce/provider/ProviderUtil.java
+++ b/src/main/java/org/bouncycastle/jce/provider/ProviderUtil.java
@@ -1,13 +1,9 @@
 package org.bouncycastle.jce.provider;
 
 import org.bouncycastle.jce.ProviderConfigurationPermission;
-// BEGIN android-removed
-// import org.bouncycastle.jce.provider.asymmetric.ec.EC5Util;
-// END android-removed
+import org.bouncycastle.jce.provider.asymmetric.ec.EC5Util;
 import org.bouncycastle.jce.interfaces.ConfigurableProvider;
-// BEGIN android-removed
-// import org.bouncycastle.jce.spec.ECParameterSpec;
-// END android-removed
+import org.bouncycastle.jce.spec.ECParameterSpec;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
@@ -24,74 +20,68 @@
                                                    "BC", ConfigurableProvider.EC_IMPLICITLY_CA);
 
     private static ThreadLocal threadSpec = new ThreadLocal();
-    // BEGIN android-removed
-    // private static volatile ECParameterSpec ecImplicitCaParams;
-    // END android-removed
+    private static volatile ECParameterSpec ecImplicitCaParams;
 
     static void setParameter(String parameterName, Object parameter)
     {
         SecurityManager securityManager = System.getSecurityManager();
 
-        // BEGIN android-removed
-        // if (parameterName.equals(ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA))
-        // {
-        //     ECParameterSpec curveSpec;
-        //
-        //     if (securityManager != null)
-        //     {
-        //         securityManager.checkPermission(BC_EC_LOCAL_PERMISSION);
-        //     }
-        //
-        //     if (parameter instanceof ECParameterSpec || parameter == null)
-        //     {
-        //         curveSpec = (ECParameterSpec)parameter;
-        //     }
-        //     else  // assume java.security.spec
-        //     {
-        //         curveSpec = EC5Util.convertSpec((java.security.spec.ECParameterSpec)parameter, false);
-        //     }
-        //
-        //     if (curveSpec == null)
-        //     {
-        //         threadSpec.remove();
-        //     }
-        //     else
-        //     {
-        //         threadSpec.set(curveSpec);
-        //     }
-        // }
-        // else if (parameterName.equals(ConfigurableProvider.EC_IMPLICITLY_CA))
-        // {
-        //     if (securityManager != null)
-        //     {
-        //         securityManager.checkPermission(BC_EC_PERMISSION);
-        //     }
-        //
-        //     if (parameter instanceof ECParameterSpec || parameter == null)
-        //     {
-        //         ecImplicitCaParams = (ECParameterSpec)parameter;
-        //     }
-        //     else  // assume java.security.spec
-        //     {
-        //         ecImplicitCaParams = EC5Util.convertSpec((java.security.spec.ECParameterSpec)parameter, false);
-        //     }
-        // }
-        // END android-removed
+        if (parameterName.equals(ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA))
+        {
+            ECParameterSpec curveSpec;
+
+            if (securityManager != null)
+            {
+                securityManager.checkPermission(BC_EC_LOCAL_PERMISSION);
+            }
+
+            if (parameter instanceof ECParameterSpec || parameter == null)
+            {
+                curveSpec = (ECParameterSpec)parameter;
+            }
+            else  // assume java.security.spec
+            {
+                curveSpec = EC5Util.convertSpec((java.security.spec.ECParameterSpec)parameter, false);
+            }
+
+            if (curveSpec == null)
+            {
+                threadSpec.remove();
+            }
+            else
+            {
+                threadSpec.set(curveSpec);
+            }
+        }
+        else if (parameterName.equals(ConfigurableProvider.EC_IMPLICITLY_CA))
+        {
+            if (securityManager != null)
+            {
+                securityManager.checkPermission(BC_EC_PERMISSION);
+            }
+
+            if (parameter instanceof ECParameterSpec || parameter == null)
+            {
+                ecImplicitCaParams = (ECParameterSpec)parameter;
+            }
+            else  // assume java.security.spec
+            {
+                ecImplicitCaParams = EC5Util.convertSpec((java.security.spec.ECParameterSpec)parameter, false);
+            }
+        }
     }
 
-    // BEGIN android-removed
-    // public static ECParameterSpec getEcImplicitlyCa()
-    // {
-    //     ECParameterSpec spec = (ECParameterSpec)threadSpec.get();
-    //
-    //     if (spec != null)
-    //     {
-    //         return spec;
-    //     }
-    //
-    //     return ecImplicitCaParams;
-    // }
-    // END android-removed
+    public static ECParameterSpec getEcImplicitlyCa()
+    {
+        ECParameterSpec spec = (ECParameterSpec)threadSpec.get();
+
+        if (spec != null)
+        {
+            return spec;
+        }
+
+        return ecImplicitCaParams;
+    }
 
     static int getReadLimit(InputStream in)
         throws IOException
diff --git a/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java b/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java
index 921ed3b..269f295 100644
--- a/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java
+++ b/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java
@@ -1471,11 +1471,7 @@
         PublicKey workingPublicKey,
         boolean verificationAlreadyPerformed,
         X500Principal workingIssuerName,
-        X509Certificate sign,
-        // BEGIN android-added
-        int i, 
-        boolean trustAnchorInChain)
-        // END android-added
+        X509Certificate sign)
         throws ExtCertPathValidatorException
     {
         List certs = certPath.getCertificates();
@@ -1489,15 +1485,8 @@
             {
                 // (a) (1)
                 //
-                // BEGIN android-added
-                if (!(i == 1 && trustAnchorInChain)) // if not at the root certificate
-                {
-                // END android-added
                 CertPathValidatorUtilities.verifyX509Certificate(cert, workingPublicKey,
                     paramsPKIX.getSigProvider());
-                // BEGIN android-added
-                }
-                // END android-added
             }
             catch (GeneralSecurityException e)
             {
@@ -2088,11 +2077,7 @@
 
     protected static void prepareNextCertK(
         CertPath certPath,
-        int index,
-        // BEGIN android-added
-        int i, 
-        boolean trustAnchorInChain)
-        // END android-added
+        int index)
         throws CertPathValidatorException
     {
         List certs = certPath.getCertificates();
@@ -2120,14 +2105,7 @@
         }
         else
         {
-            // BEGIN android-added
-            if (!(i == 1 && trustAnchorInChain)) // if not at the root certificate
-            {
-            // END android-added
             throw new CertPathValidatorException("Intermediate certificate lacks BasicConstraints");
-            // BEGIN android-added
-            }
-            // END android-added
         }
     }
 
diff --git a/src/main/java/org/bouncycastle/jce/provider/WrapCipherSpi.java b/src/main/java/org/bouncycastle/jce/provider/WrapCipherSpi.java
index aa50406..7b78f82 100644
--- a/src/main/java/org/bouncycastle/jce/provider/WrapCipherSpi.java
+++ b/src/main/java/org/bouncycastle/jce/provider/WrapCipherSpi.java
@@ -368,20 +368,17 @@
 
                 DERObjectIdentifier  oid = in.getAlgorithmId().getObjectId();
 
+                if (oid.equals(X9ObjectIdentifiers.id_ecPublicKey))
+                {
+                    privKey = new JCEECPrivateKey(in);
+                }
                 // BEGIN android-removed
-                // if (oid.equals(X9ObjectIdentifiers.id_ecPublicKey))
-                // {
-                //     privKey = new JCEECPrivateKey(in);
-                // }
                 // else if (oid.equals(CryptoProObjectIdentifiers.gostR3410_94))
                 // {
                 //     privKey = new JDKGOST3410PrivateKey(in);
                 // }
-                // else if (oid.equals(X9ObjectIdentifiers.id_dsa))
                 // END android-removed
-                // BEGIN android-added
-                if (oid.equals(X9ObjectIdentifiers.id_dsa))
-                // END android-added
+                else if (oid.equals(X9ObjectIdentifiers.id_dsa))
                 {
                     privKey = new JDKDSAPrivateKey(in);
                 }
diff --git a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ECMappings.java b/src/main/java/org/bouncycastle/jce/provider/asymmetric/ECMappings.java
new file mode 100644
index 0000000..4294d14
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/provider/asymmetric/ECMappings.java
@@ -0,0 +1,114 @@
+package org.bouncycastle.jce.provider.asymmetric;
+
+import java.util.HashMap;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.eac.EACObjectIdentifiers;
+// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+// END android-removed
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+
+public class ECMappings
+    extends HashMap
+{
+    public ECMappings()
+    {
+        put("KeyAgreement.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DH");
+        // BEGIN android-removed
+        // put("KeyAgreement.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DHC");
+        // put("KeyAgreement.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$MQV");
+        // put("KeyAgreement." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DHwithSHA1KDF");
+        // put("KeyAgreement." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$MQVwithSHA1KDF");
+        // END android-removed
+
+        put("KeyFactory.EC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$EC");
+        // BEGIN android-removed
+        // put("KeyFactory.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDSA");
+        // put("KeyFactory.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDH");
+        // put("KeyFactory.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDHC");
+        // put("KeyFactory.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECMQV");
+        // END android-removed
+        put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.id_ecPublicKey, "EC");
+        // TODO Should this be an alias for ECDH?
+        put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC");
+        // BEGIN android-removed
+        // put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV");
+
+        // put("KeyFactory.ECGOST3410", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECGOST3410");
+        // put("Alg.Alias.KeyFactory.GOST-3410-2001", "ECGOST3410");
+        // put("Alg.Alias.KeyFactory.ECGOST-3410", "ECGOST3410");
+        // put("Alg.Alias.KeyFactory." + CryptoProObjectIdentifiers.gostR3410_2001, "ECGOST3410");
+        // END android-removed
+
+        put("KeyPairGenerator.EC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$EC");
+        // BEGIN android-removed
+        // put("KeyPairGenerator.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDSA");
+        // put("KeyPairGenerator.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDH");
+        // put("KeyPairGenerator.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDHC");
+        // put("KeyPairGenerator.ECIES", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDH");
+        // put("KeyPairGenerator.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECMQV");
+        // END android-removed
+        // TODO Should this be an alias for ECDH?
+        put("Alg.Alias.KeyPairGenerator." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC");
+        // BEGIN android-removed
+        // put("Alg.Alias.KeyPairGenerator." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV");
+
+        // put("KeyPairGenerator.ECGOST3410", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECGOST3410");
+        // put("Alg.Alias.KeyPairGenerator.ECGOST-3410", "ECGOST3410");
+        // put("Alg.Alias.KeyPairGenerator.GOST-3410-2001", "ECGOST3410");
+        // END android-removed
+
+        put("Signature.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA");
+        put("Signature.NONEwithECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSAnone");
+
+        put("Alg.Alias.Signature.SHA1withECDSA", "ECDSA");
+        put("Alg.Alias.Signature.ECDSAwithSHA1", "ECDSA");
+        put("Alg.Alias.Signature.SHA1WITHECDSA", "ECDSA");
+        put("Alg.Alias.Signature.ECDSAWITHSHA1", "ECDSA");
+        put("Alg.Alias.Signature.SHA1WithECDSA", "ECDSA");
+        put("Alg.Alias.Signature.ECDSAWithSHA1", "ECDSA");
+        put("Alg.Alias.Signature.1.2.840.10045.4.1", "ECDSA");
+        // BEGIN android-removed
+        // put("Alg.Alias.Signature." + TeleTrusTObjectIdentifiers.ecSignWithSha1, "ECDSA");
+
+        // addSignatureAlgorithm("SHA224", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA224", X9ObjectIdentifiers.ecdsa_with_SHA224);
+        // END android-removed
+        addSignatureAlgorithm("SHA256", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA256", X9ObjectIdentifiers.ecdsa_with_SHA256);
+        addSignatureAlgorithm("SHA384", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA384", X9ObjectIdentifiers.ecdsa_with_SHA384);
+        addSignatureAlgorithm("SHA512", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA512", X9ObjectIdentifiers.ecdsa_with_SHA512);
+        // BEGIN android-removed
+        // addSignatureAlgorithm("RIPEMD160", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSARipeMD160",TeleTrusTObjectIdentifiers.ecSignWithRipemd160);
+
+        // put("Signature.SHA1WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR");
+        // put("Signature.SHA224WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR224");
+        // put("Signature.SHA256WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR256");
+        // put("Signature.SHA384WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR384");
+        // put("Signature.SHA512WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR512");
+
+        // addSignatureAlgorithm("SHA1", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1);
+        // addSignatureAlgorithm("SHA224", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA224", EACObjectIdentifiers.id_TA_ECDSA_SHA_224);
+        // addSignatureAlgorithm("SHA256", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA256", EACObjectIdentifiers.id_TA_ECDSA_SHA_256);
+        // END android-removed
+    }
+
+    private void addSignatureAlgorithm(
+        String digest,
+        String algorithm,
+        String className,
+        DERObjectIdentifier oid)
+    {
+        String mainName = digest + "WITH" + algorithm;
+        String jdk11Variation1 = digest + "with" + algorithm;
+        String jdk11Variation2 = digest + "With" + algorithm;
+        String alias = digest + "/" + algorithm;
+
+        put("Signature." + mainName, className);
+        put("Alg.Alias.Signature." + jdk11Variation1, mainName);
+        put("Alg.Alias.Signature." + jdk11Variation2, mainName);
+        put("Alg.Alias.Signature." + alias, mainName);
+        put("Alg.Alias.Signature." + oid, mainName);
+        put("Alg.Alias.Signature.OID." + oid, mainName);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/EC5Util.java b/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/EC5Util.java
new file mode 100644
index 0000000..b693613
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/EC5Util.java
@@ -0,0 +1,123 @@
+package org.bouncycastle.jce.provider.asymmetric.ec;
+
+import java.math.BigInteger;
+import java.security.spec.ECField;
+import java.security.spec.ECFieldF2m;
+import java.security.spec.ECFieldFp;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.EllipticCurve;
+
+import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
+import org.bouncycastle.jce.spec.ECNamedCurveSpec;
+import org.bouncycastle.math.ec.ECCurve;
+
+public class EC5Util
+{
+    public static EllipticCurve convertCurve(
+        ECCurve curve, 
+        byte[]  seed)
+    {
+        // TODO: the Sun EC implementation doesn't currently handle the seed properly
+        // so at the moment it's set to null. Should probably look at making this configurable
+        if (curve instanceof ECCurve.Fp)
+        {
+            return new EllipticCurve(new ECFieldFp(((ECCurve.Fp)curve).getQ()), curve.getA().toBigInteger(), curve.getB().toBigInteger(), null);
+        }
+        else
+        {
+            ECCurve.F2m curveF2m = (ECCurve.F2m)curve;
+            int ks[];
+            
+            if (curveF2m.isTrinomial())
+            {
+                ks = new int[] { curveF2m.getK1() };
+                
+                return new EllipticCurve(new ECFieldF2m(curveF2m.getM(), ks), curve.getA().toBigInteger(), curve.getB().toBigInteger(), null);
+            }
+            else
+            {
+                ks = new int[] { curveF2m.getK3(), curveF2m.getK2(), curveF2m.getK1() };
+                
+                return new EllipticCurve(new ECFieldF2m(curveF2m.getM(), ks), curve.getA().toBigInteger(), curve.getB().toBigInteger(), null);
+            } 
+        }
+    }
+
+    public static ECCurve convertCurve(
+        EllipticCurve ec)
+    {
+        ECField field = ec.getField();
+        BigInteger a = ec.getA();
+        BigInteger b = ec.getB();
+
+        if (field instanceof ECFieldFp)
+        {
+            return new ECCurve.Fp(((ECFieldFp)field).getP(), a, b);
+        }
+        else
+        {
+            ECFieldF2m fieldF2m = (ECFieldF2m)field;
+            int m = fieldF2m.getM();
+            int ks[] = ECUtil.convertMidTerms(fieldF2m.getMidTermsOfReductionPolynomial());
+            return new ECCurve.F2m(m, ks[0], ks[1], ks[2], a, b); 
+        }
+    }
+
+    public static ECParameterSpec convertSpec(
+        EllipticCurve ellipticCurve,
+        org.bouncycastle.jce.spec.ECParameterSpec spec)
+    {
+        if (spec instanceof ECNamedCurveParameterSpec)
+        {
+            return new ECNamedCurveSpec(
+                ((ECNamedCurveParameterSpec)spec).getName(),
+                ellipticCurve,
+                new ECPoint(
+                    spec.getG().getX().toBigInteger(),
+                    spec.getG().getY().toBigInteger()),
+                spec.getN(),
+                spec.getH());
+        }
+        else
+        {
+            return new ECParameterSpec(
+                ellipticCurve,
+                new ECPoint(
+                    spec.getG().getX().toBigInteger(),
+                    spec.getG().getY().toBigInteger()),
+                spec.getN(),
+                spec.getH().intValue());
+        }
+    }
+
+    public static org.bouncycastle.jce.spec.ECParameterSpec convertSpec(
+        ECParameterSpec ecSpec,
+        boolean withCompression)
+    {
+        ECCurve curve = convertCurve(ecSpec.getCurve());
+
+        return new org.bouncycastle.jce.spec.ECParameterSpec(
+            curve,
+            convertPoint(curve, ecSpec.getGenerator(), withCompression),
+            ecSpec.getOrder(),
+            BigInteger.valueOf(ecSpec.getCofactor()),
+            ecSpec.getCurve().getSeed());
+    }
+
+    public static org.bouncycastle.math.ec.ECPoint convertPoint(
+        ECParameterSpec ecSpec,
+        ECPoint point,
+        boolean withCompression)
+    {
+        return convertPoint(convertCurve(ecSpec.getCurve()), point, withCompression);
+    }
+
+    public static org.bouncycastle.math.ec.ECPoint convertPoint(
+        ECCurve curve,
+        ECPoint point,
+        boolean withCompression)
+    {
+        return curve.createPoint(point.getAffineX(), point.getAffineY(), withCompression);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/ECUtil.java b/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/ECUtil.java
new file mode 100644
index 0000000..088dfad
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/ECUtil.java
@@ -0,0 +1,238 @@
+package org.bouncycastle.jce.provider.asymmetric.ec;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+// END android-removed
+import org.bouncycastle.asn1.nist.NISTNamedCurves;
+import org.bouncycastle.asn1.sec.SECNamedCurves;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
+// END android-removed
+import org.bouncycastle.asn1.x9.X962NamedCurves;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import org.bouncycastle.jce.interfaces.ECPrivateKey;
+import org.bouncycastle.jce.interfaces.ECPublicKey;
+import org.bouncycastle.jce.spec.ECParameterSpec;
+import org.bouncycastle.jce.provider.ProviderUtil;
+import org.bouncycastle.jce.provider.JCEECPublicKey;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * utility class for converting jce/jca ECDSA, ECDH, and ECDHC
+ * objects into their org.bouncycastle.crypto counterparts.
+ */
+public class ECUtil
+{
+    /**
+     * Returns a sorted array of middle terms of the reduction polynomial.
+     * @param k The unsorted array of middle terms of the reduction polynomial
+     * of length 1 or 3.
+     * @return the sorted array of middle terms of the reduction polynomial.
+     * This array always has length 3.
+     */
+    static int[] convertMidTerms(
+        int[] k)
+    {
+        int[] res = new int[3];
+        
+        if (k.length == 1)
+        {
+            res[0] = k[0];
+        }
+        else
+        {
+            if (k.length != 3)
+            {
+                throw new IllegalArgumentException("Only Trinomials and pentanomials supported");
+            }
+
+            if (k[0] < k[1] && k[0] < k[2])
+            {
+                res[0] = k[0];
+                if (k[1] < k[2])
+                {
+                    res[1] = k[1];
+                    res[2] = k[2];
+                }
+                else
+                {
+                    res[1] = k[2];
+                    res[2] = k[1];
+                }
+            }
+            else if (k[1] < k[2])
+            {
+                res[0] = k[1];
+                if (k[0] < k[2])
+                {
+                    res[1] = k[0];
+                    res[2] = k[2];
+                }
+                else
+                {
+                    res[1] = k[2];
+                    res[2] = k[0];
+                }
+            }
+            else
+            {
+                res[0] = k[2];
+                if (k[0] < k[1])
+                {
+                    res[1] = k[0];
+                    res[2] = k[1];
+                }
+                else
+                {
+                    res[1] = k[1];
+                    res[2] = k[0];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static AsymmetricKeyParameter generatePublicKeyParameter(
+        PublicKey    key)
+        throws InvalidKeyException
+    {
+        if (key instanceof ECPublicKey)
+        {
+            ECPublicKey    k = (ECPublicKey)key;
+            ECParameterSpec s = k.getParameters();
+
+            if (s == null)
+            {
+                s = ProviderUtil.getEcImplicitlyCa();
+
+                return new ECPublicKeyParameters(
+                            ((JCEECPublicKey)k).engineGetQ(),
+                            new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
+            }
+            else
+            {
+                return new ECPublicKeyParameters(
+                            k.getQ(),
+                            new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
+            }
+        }
+        else if (key instanceof java.security.interfaces.ECPublicKey)
+        {
+            java.security.interfaces.ECPublicKey pubKey = (java.security.interfaces.ECPublicKey)key;
+            ECParameterSpec s = EC5Util.convertSpec(pubKey.getParams(), false);
+            return new ECPublicKeyParameters(
+                EC5Util.convertPoint(pubKey.getParams(), pubKey.getW(), false),
+                            new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
+        }
+
+        throw new InvalidKeyException("cannot identify EC public key.");
+    }
+
+    public static AsymmetricKeyParameter generatePrivateKeyParameter(
+        PrivateKey    key)
+        throws InvalidKeyException
+    {
+        if (key instanceof ECPrivateKey)
+        {
+            ECPrivateKey  k = (ECPrivateKey)key;
+            ECParameterSpec s = k.getParameters();
+
+            if (s == null)
+            {
+                s = ProviderUtil.getEcImplicitlyCa();
+            }
+
+            return new ECPrivateKeyParameters(
+                            k.getD(),
+                            new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
+        }
+                        
+        throw new InvalidKeyException("can't identify EC private key.");
+    }
+
+    public static DERObjectIdentifier getNamedCurveOid(
+        String name)
+    {
+        DERObjectIdentifier oid = X962NamedCurves.getOID(name);
+        
+        if (oid == null)
+        {
+            oid = SECNamedCurves.getOID(name);
+            if (oid == null)
+            {
+                oid = NISTNamedCurves.getOID(name);
+            }
+            // BEGIN android-removed
+            // if (oid == null)
+            // {
+            //     oid = TeleTrusTNamedCurves.getOID(name);
+            // }
+            // if (oid == null)
+            // {
+            //     oid = ECGOST3410NamedCurves.getOID(name);
+            // }
+            // END android-removed
+        }
+
+        return oid;
+    }
+    
+    public static X9ECParameters getNamedCurveByOid(
+        DERObjectIdentifier oid)
+    {
+        X9ECParameters params = X962NamedCurves.getByOID(oid);
+        
+        if (params == null)
+        {
+            params = SECNamedCurves.getByOID(oid);
+            if (params == null)
+            {
+                params = NISTNamedCurves.getByOID(oid);
+            }
+            // BEGIN android-removed
+            // if (params == null)
+            // {
+            //     params = TeleTrusTNamedCurves.getByOID(oid);
+            // }
+            // END android-removed
+        }
+
+        return params;
+    }
+
+    public static String getCurveName(
+        DERObjectIdentifier oid)
+    {
+        String name = X962NamedCurves.getName(oid);
+        
+        if (name == null)
+        {
+            name = SECNamedCurves.getName(oid);
+            if (name == null)
+            {
+                name = NISTNamedCurves.getName(oid);
+            }
+            // BEGIN android-removed
+            // if (name == null)
+            // {
+            //     name = TeleTrusTNamedCurves.getName(oid);
+            // }
+            // if (name == null)
+            // {
+            //     name = ECGOST3410NamedCurves.getName(oid);
+            // }
+            // END android-removed
+        }
+
+        return name;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java b/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java
new file mode 100644
index 0000000..d2fa69e
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java
@@ -0,0 +1,336 @@
+package org.bouncycastle.jce.provider.asymmetric.ec;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Hashtable;
+
+import javax.crypto.KeyAgreementSpi;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x9.X9IntegerConverter;
+import org.bouncycastle.crypto.BasicAgreement;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DerivationFunction;
+import org.bouncycastle.crypto.agreement.ECDHBasicAgreement;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.agreement.ECDHCBasicAgreement;
+// import org.bouncycastle.crypto.agreement.ECMQVBasicAgreement;
+// import org.bouncycastle.crypto.agreement.kdf.DHKDFParameters;
+// import org.bouncycastle.crypto.agreement.kdf.ECDHKEKGenerator;
+// END android-removed
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.params.MQVPrivateParameters;
+// import org.bouncycastle.crypto.params.MQVPublicParameters;
+// END android-removed
+import org.bouncycastle.jce.interfaces.ECPrivateKey;
+import org.bouncycastle.jce.interfaces.ECPublicKey;
+// BEGIN android-removed
+// import org.bouncycastle.jce.interfaces.MQVPrivateKey;
+// import org.bouncycastle.jce.interfaces.MQVPublicKey;
+// END android-removed
+
+/**
+ * Diffie-Hellman key agreement using elliptic curve keys, ala IEEE P1363
+ * both the simple one, and the simple one with cofactors are supported.
+ *
+ * Also, MQV key agreement per SEC-1
+ */
+public class KeyAgreement
+    extends KeyAgreementSpi
+{
+    private static final X9IntegerConverter converter = new X9IntegerConverter();
+    private static final Hashtable algorithms = new Hashtable();
+
+    static
+    {
+        Integer i128 = new Integer(128);
+        Integer i192 = new Integer(192);
+        Integer i256 = new Integer(256);
+
+        algorithms.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), i128);
+        algorithms.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), i192);
+        algorithms.put(NISTObjectIdentifiers.id_aes256_CBC.getId(), i256);
+        algorithms.put(NISTObjectIdentifiers.id_aes128_wrap.getId(), i128);
+        algorithms.put(NISTObjectIdentifiers.id_aes192_wrap.getId(), i192);
+        algorithms.put(NISTObjectIdentifiers.id_aes256_wrap.getId(), i256);
+        algorithms.put(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId(), i192);
+    }
+
+    private String                 kaAlgorithm;
+    private BigInteger             result;
+    private ECDomainParameters     parameters;
+    private BasicAgreement         agreement;
+    // BEGIN android-removed
+    // private DerivationFunction     kdf;
+    // END android-removed
+
+    private byte[] bigIntToBytes(
+        BigInteger    r)
+    {
+        return converter.integerToBytes(r, converter.getByteLength(parameters.getG().getX()));
+    }
+
+    protected KeyAgreement(
+        String              kaAlgorithm,
+        BasicAgreement      agreement,
+        DerivationFunction  kdf)
+    {
+        this.kaAlgorithm = kaAlgorithm;
+        this.agreement = agreement;
+        // BEGIN android-removed
+        // this.kdf = kdf;
+        // END android-removed
+    }
+
+    protected Key engineDoPhase(
+        Key     key,
+        boolean lastPhase) 
+        throws InvalidKeyException, IllegalStateException
+    {
+        if (parameters == null)
+        {
+            throw new IllegalStateException(kaAlgorithm + " not initialised.");
+        }
+
+        if (!lastPhase)
+        {
+            throw new IllegalStateException(kaAlgorithm + " can only be between two parties.");
+        }
+
+        CipherParameters pubKey;        
+        // BEGIN android-removed
+        // if (agreement instanceof ECMQVBasicAgreement)
+        // {
+        //     if (!(key instanceof MQVPublicKey))
+        //     {
+        //         throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+        //             + getSimpleName(MQVPublicKey.class) + " for doPhase");
+        //     }
+        //
+        //     MQVPublicKey mqvPubKey = (MQVPublicKey)key;
+        //     ECPublicKeyParameters staticKey = (ECPublicKeyParameters)
+        //         ECUtil.generatePublicKeyParameter(mqvPubKey.getStaticKey());
+        //     ECPublicKeyParameters ephemKey = (ECPublicKeyParameters)
+        //         ECUtil.generatePublicKeyParameter(mqvPubKey.getEphemeralKey());
+        //
+        //     pubKey = new MQVPublicParameters(staticKey, ephemKey);
+        //
+        //     // TODO Validate that all the keys are using the same parameters?
+        // }
+        // else
+        // END android-removed
+        {
+            if (!(key instanceof ECPublicKey))
+            {
+                throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+                    + getSimpleName(ECPublicKey.class) + " for doPhase");
+            }
+
+            pubKey = ECUtil.generatePublicKeyParameter((PublicKey)key);
+
+            // TODO Validate that all the keys are using the same parameters?
+        }
+
+        result = agreement.calculateAgreement(pubKey);
+
+        return null;
+    }
+
+    protected byte[] engineGenerateSecret()
+        throws IllegalStateException
+    {
+        // BEGIN android-removed
+        // if (kdf != null)
+        // {
+        //     throw new UnsupportedOperationException(
+        //         "KDF can only be used when algorithm is known");
+        // }
+        // END android-removed
+
+        return bigIntToBytes(result);
+    }
+
+    protected int engineGenerateSecret(
+        byte[]  sharedSecret,
+        int     offset) 
+        throws IllegalStateException, ShortBufferException
+    {
+        byte[] secret = engineGenerateSecret();
+
+        if (sharedSecret.length - offset < secret.length)
+        {
+            throw new ShortBufferException(kaAlgorithm + " key agreement: need " + secret.length + " bytes");
+        }
+
+        System.arraycopy(secret, 0, sharedSecret, offset, secret.length);
+        
+        return secret.length;
+    }
+
+    protected SecretKey engineGenerateSecret(
+        String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        byte[] secret = bigIntToBytes(result);
+
+        // BEGIN android-removed
+        // if (kdf != null)
+        // {
+        //     if (!algorithms.containsKey(algorithm))
+        //     {
+        //         throw new NoSuchAlgorithmException("unknown algorithm encountered: " + algorithm);
+        //     }
+        //  
+        //     int    keySize = ((Integer)algorithms.get(algorithm)).intValue();
+        //
+        //     DHKDFParameters params = new DHKDFParameters(new DERObjectIdentifier(algorithm), keySize, secret);
+        //
+        //     byte[] keyBytes = new byte[keySize / 8];
+        //     kdf.init(params);
+        //     kdf.generateBytes(keyBytes, 0, keyBytes.length);
+        //     secret = keyBytes;
+        // }
+        // else
+        // END android-removed
+        {
+            // TODO Should we be ensuring the key is the right length?
+        }
+
+        return new SecretKeySpec(secret, algorithm);
+    }
+
+    protected void engineInit(
+        Key                     key,
+        AlgorithmParameterSpec  params,
+        SecureRandom            random) 
+        throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        initFromKey(key);
+    }
+
+    protected void engineInit(
+        Key             key,
+        SecureRandom    random) 
+        throws InvalidKeyException
+    {
+        initFromKey(key);
+    }
+
+    private void initFromKey(Key key)
+        throws InvalidKeyException
+    {
+        // BEGIN android-removed
+        // if (agreement instanceof ECMQVBasicAgreement)
+        // {
+        //     if (!(key instanceof MQVPrivateKey))
+        //     {
+        //         throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+        //             + getSimpleName(MQVPrivateKey.class) + " for initialisation");
+        //     }
+        //
+        //     MQVPrivateKey mqvPrivKey = (MQVPrivateKey)key;
+        //     ECPrivateKeyParameters staticPrivKey = (ECPrivateKeyParameters)
+        //         ECUtil.generatePrivateKeyParameter(mqvPrivKey.getStaticPrivateKey());
+        //     ECPrivateKeyParameters ephemPrivKey = (ECPrivateKeyParameters)
+        //         ECUtil.generatePrivateKeyParameter(mqvPrivKey.getEphemeralPrivateKey());
+        //
+        //     ECPublicKeyParameters ephemPubKey = null;
+        //     if (mqvPrivKey.getEphemeralPublicKey() != null)
+        //     {
+        //         ephemPubKey = (ECPublicKeyParameters)
+        //             ECUtil.generatePublicKeyParameter(mqvPrivKey.getEphemeralPublicKey());
+        //     }
+        //
+        //     MQVPrivateParameters localParams = new MQVPrivateParameters(staticPrivKey, ephemPrivKey, ephemPubKey);
+        //     this.parameters = staticPrivKey.getParameters();
+        //
+        //     // TODO Validate that all the keys are using the same parameters?
+        //
+        //     agreement.init(localParams);
+        // }
+        // else
+        // END android-removed
+        {
+            if (!(key instanceof ECPrivateKey))
+            {
+                throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+                    + getSimpleName(ECPrivateKey.class) + " for initialisation");
+            }
+
+            ECPrivateKeyParameters privKey = (ECPrivateKeyParameters)ECUtil.generatePrivateKeyParameter((PrivateKey)key);
+            this.parameters = privKey.getParameters();
+
+            agreement.init(privKey);
+        }
+    }
+
+    private static String getSimpleName(Class clazz)
+    {
+        String fullName = clazz.getName();
+
+        return fullName.substring(fullName.lastIndexOf('.') + 1);
+    }
+
+    public static class DH
+        extends KeyAgreement
+    {
+        public DH()
+        {
+            super("ECDH", new ECDHBasicAgreement(), null);
+        }
+    }
+
+    // BEGIN android-removed
+    // public static class DHC
+    //     extends KeyAgreement
+    // {
+    //     public DHC()
+    //     {
+    //         super("ECDHC", new ECDHCBasicAgreement(), null);
+    //     }
+    // }
+    //
+    // public static class MQV
+    //     extends KeyAgreement
+    // {
+    //     public MQV()
+    //     {
+    //         super("ECMQV", new ECMQVBasicAgreement(), null);
+    //     }
+    // }
+    //
+    // public static class DHwithSHA1KDF
+    //     extends KeyAgreement
+    // {
+    //     public DHwithSHA1KDF()
+    //     {
+    //         super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
+    //     }
+    // }
+    //
+    // public static class MQVwithSHA1KDF
+    //     extends KeyAgreement
+    // {
+    //     public MQVwithSHA1KDF()
+    //     {
+    //         super("ECMQVwithSHA1KDF", new ECMQVBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
+    //     }
+    // }
+    // END android-removed
+}
diff --git a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyFactory.java b/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyFactory.java
new file mode 100644
index 0000000..630d2c7
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyFactory.java
@@ -0,0 +1,208 @@
+package org.bouncycastle.jce.provider.asymmetric.ec;
+
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import org.bouncycastle.jce.provider.JCEECPrivateKey;
+import org.bouncycastle.jce.provider.JCEECPublicKey;
+import org.bouncycastle.jce.provider.JDKKeyFactory;
+import org.bouncycastle.jce.provider.ProviderUtil;
+import org.bouncycastle.jce.spec.ECPrivateKeySpec;
+import org.bouncycastle.jce.spec.ECPublicKeySpec;
+import org.bouncycastle.jce.spec.ECParameterSpec;
+
+public class KeyFactory
+    extends JDKKeyFactory
+{
+    String algorithm;
+
+    KeyFactory(
+        String algorithm)
+    {
+        this.algorithm = algorithm;
+    }
+
+    protected Key engineTranslateKey(
+        Key    key)
+        throws InvalidKeyException
+    {
+        if (key instanceof ECPublicKey)
+        {
+            return new JCEECPublicKey((ECPublicKey)key);
+        }
+        else if (key instanceof ECPrivateKey)
+        {
+            return new JCEECPrivateKey((ECPrivateKey)key);
+        }
+
+        throw new InvalidKeyException("key type unknown");
+    }
+
+    protected KeySpec engineGetKeySpec(
+        Key    key,
+        Class    spec)
+    throws InvalidKeySpecException
+    {
+       if (spec.isAssignableFrom(PKCS8EncodedKeySpec.class) && key.getFormat().equals("PKCS#8"))
+       {
+               return new PKCS8EncodedKeySpec(key.getEncoded());
+       }
+       else if (spec.isAssignableFrom(X509EncodedKeySpec.class) && key.getFormat().equals("X.509"))
+       {
+               return new X509EncodedKeySpec(key.getEncoded());
+       }
+       else if (spec.isAssignableFrom(java.security.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey)
+       {
+           ECPublicKey k = (ECPublicKey)key;
+           if (k.getParams() != null)
+           {
+               return new java.security.spec.ECPublicKeySpec(k.getW(), k.getParams());
+           }
+           else
+           {
+               ECParameterSpec implicitSpec = ProviderUtil.getEcImplicitlyCa();
+
+               return new java.security.spec.ECPublicKeySpec(k.getW(), EC5Util.convertSpec(EC5Util.convertCurve(implicitSpec.getCurve(), implicitSpec.getSeed()), implicitSpec));
+           }
+       }
+       else if (spec.isAssignableFrom(java.security.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey)
+       {
+           ECPrivateKey k = (ECPrivateKey)key;
+
+           if (k.getParams() != null)
+           {
+               return new java.security.spec.ECPrivateKeySpec(k.getS(), k.getParams());
+           }
+           else
+           {
+               ECParameterSpec implicitSpec = ProviderUtil.getEcImplicitlyCa();
+
+               return new java.security.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(EC5Util.convertCurve(implicitSpec.getCurve(), implicitSpec.getSeed()), implicitSpec)); 
+           }
+       }
+
+       throw new RuntimeException("not implemented yet " + key + " " + spec);
+    }
+
+    protected PrivateKey engineGeneratePrivate(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof PKCS8EncodedKeySpec)
+        {
+            try
+            {
+                JCEECPrivateKey key = (JCEECPrivateKey)JDKKeyFactory.createPrivateKeyFromDERStream(
+                    ((PKCS8EncodedKeySpec)keySpec).getEncoded());
+
+                return new JCEECPrivateKey(algorithm, key);
+            }
+            catch (Exception e)
+            {
+                throw new InvalidKeySpecException(e.toString());
+            }
+        }
+        else if (keySpec instanceof ECPrivateKeySpec)
+        {
+            return new JCEECPrivateKey(algorithm, (ECPrivateKeySpec)keySpec);
+        }
+        else if (keySpec instanceof java.security.spec.ECPrivateKeySpec)
+        {
+            return new JCEECPrivateKey(algorithm, (java.security.spec.ECPrivateKeySpec)keySpec);
+        }
+
+        throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+    }
+
+    protected PublicKey engineGeneratePublic(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof X509EncodedKeySpec)
+        {
+            try
+            {
+                JCEECPublicKey key = (JCEECPublicKey)JDKKeyFactory.createPublicKeyFromDERStream(
+                    ((X509EncodedKeySpec)keySpec).getEncoded());
+
+                return new JCEECPublicKey(algorithm, key);
+            }
+            catch (Exception e)
+            {
+                throw new InvalidKeySpecException(e.toString());
+            }
+        }
+        else if (keySpec instanceof ECPublicKeySpec)
+        {
+            return new JCEECPublicKey(algorithm, (ECPublicKeySpec)keySpec);
+        }
+        else if (keySpec instanceof java.security.spec.ECPublicKeySpec)
+        {
+            return new JCEECPublicKey(algorithm, (java.security.spec.ECPublicKeySpec)keySpec);
+        }
+
+        throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+    }
+
+    public static class EC
+        extends KeyFactory
+    {
+        public EC()
+        {
+            super("EC");
+        }
+    }
+
+    public static class ECDSA
+        extends KeyFactory
+    {
+        public ECDSA()
+        {
+            super("ECDSA");
+        }
+    }
+
+    public static class ECGOST3410
+        extends KeyFactory
+    {
+        public ECGOST3410()
+        {
+            super("ECGOST3410");
+        }
+    }
+
+    public static class ECDH
+        extends KeyFactory
+    {
+        public ECDH()
+        {
+            super("ECDH");
+        }
+    }
+
+    public static class ECDHC
+        extends KeyFactory
+    {
+        public ECDHC()
+        {
+            super("ECDHC");
+        }
+    }
+
+    public static class ECMQV
+        extends KeyFactory
+    {
+        public ECMQV()
+        {
+            super("ECMQV");
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java b/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java
new file mode 100644
index 0000000..88228d5
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java
@@ -0,0 +1,348 @@
+package org.bouncycastle.jce.provider.asymmetric.ec;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.ECGenParameterSpec;
+import java.util.Hashtable;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+// END android-removed
+import org.bouncycastle.asn1.nist.NISTNamedCurves;
+import org.bouncycastle.asn1.sec.SECNamedCurves;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
+// END android-removed
+import org.bouncycastle.asn1.x9.X962NamedCurves;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import org.bouncycastle.jce.provider.JCEECPrivateKey;
+import org.bouncycastle.jce.provider.JCEECPublicKey;
+import org.bouncycastle.jce.provider.JDKKeyPairGenerator;
+import org.bouncycastle.jce.provider.ProviderUtil;
+import org.bouncycastle.jce.spec.ECNamedCurveSpec;
+import org.bouncycastle.jce.spec.ECParameterSpec;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+
+public abstract class KeyPairGenerator
+    extends JDKKeyPairGenerator
+{
+    public KeyPairGenerator(String algorithmName)
+    {
+        super(algorithmName);
+    }
+
+    public static class EC
+        extends KeyPairGenerator
+    {
+        ECKeyGenerationParameters   param;
+        ECKeyPairGenerator          engine = new ECKeyPairGenerator();
+        Object                      ecParams = null;
+        int                         strength = 239;
+        int                         certainty = 50;
+        SecureRandom                random = new SecureRandom();
+        boolean                     initialised = false;
+        String                      algorithm;
+
+        static private Hashtable    ecParameters;
+
+        static {
+            ecParameters = new Hashtable();
+
+            ecParameters.put(new Integer(192), new ECGenParameterSpec("prime192v1")); // a.k.a P-192
+            ecParameters.put(new Integer(239), new ECGenParameterSpec("prime239v1"));
+            ecParameters.put(new Integer(256), new ECGenParameterSpec("prime256v1")); // a.k.a P-256
+
+            ecParameters.put(new Integer(224), new ECGenParameterSpec("P-224"));
+            ecParameters.put(new Integer(384), new ECGenParameterSpec("P-384"));
+            ecParameters.put(new Integer(521), new ECGenParameterSpec("P-521"));
+        }
+
+        public EC()
+        {
+            super("EC");
+            this.algorithm = "EC";
+        }
+
+        public EC(
+            String  algorithm)
+        {
+            super(algorithm);
+            this.algorithm = algorithm;
+        }
+
+        public void initialize(
+            int             strength,
+            SecureRandom    random)
+        {
+            this.strength = strength;
+            // BEGIN android-added
+            if (random != null) {
+            // END android-added
+            this.random = random;
+            // BEGIN android-added
+            }
+            // END android-added
+            this.ecParams = ecParameters.get(new Integer(strength));
+
+            if (ecParams != null)
+            {
+                try
+                {
+                    initialize((ECGenParameterSpec)ecParams, random);
+                }
+                catch (InvalidAlgorithmParameterException e)
+                {
+                    throw new InvalidParameterException("key size not configurable.");
+                }
+            }
+            else
+            {
+                throw new InvalidParameterException("unknown key size.");
+            }
+        }
+
+        public void initialize(
+            AlgorithmParameterSpec  params,
+            SecureRandom            random)
+            throws InvalidAlgorithmParameterException
+        {
+            // BEGIN android-added
+            if (random == null) {
+                random = this.random;
+            }
+            // END android-added
+            if (params instanceof ECParameterSpec)
+            {
+                ECParameterSpec p = (ECParameterSpec)params;
+                this.ecParams = params;
+
+                param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
+
+                engine.init(param);
+                initialised = true;
+            }
+            else if (params instanceof java.security.spec.ECParameterSpec)
+            {
+                java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)params;
+                this.ecParams = params;
+
+                ECCurve curve = EC5Util.convertCurve(p.getCurve());
+                ECPoint g = EC5Util.convertPoint(curve, p.getGenerator(), false);
+
+                param = new ECKeyGenerationParameters(new ECDomainParameters(curve, g, p.getOrder(), BigInteger.valueOf(p.getCofactor())), random);
+
+                engine.init(param);
+                initialised = true;
+            }
+            else if (params instanceof ECGenParameterSpec)
+            {
+                final String curveName = ((ECGenParameterSpec)params).getName();
+
+                // BEGIN android-removed
+                // if (this.algorithm.equals("ECGOST3410"))
+                // {
+                //     ECDomainParameters  ecP = ECGOST3410NamedCurves.getByName(curveName);
+                //     if (ecP == null)
+                //     {
+                //         throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName);
+                //     }
+                //
+                //     this.ecParams = new ECNamedCurveSpec(
+                //                                     curveName,
+                //                                     ecP.getCurve(),
+                //                                     ecP.getG(),
+                //                                     ecP.getN(),
+                //                                     ecP.getH(),
+                //                                     ecP.getSeed());
+                // }
+                // else
+                // END android-removed
+                {
+                    X9ECParameters  ecP = X962NamedCurves.getByName(curveName);
+                    if (ecP == null)
+                    {
+                        ecP = SECNamedCurves.getByName(curveName);
+                        if (ecP == null)
+                        {
+                            ecP = NISTNamedCurves.getByName(curveName);
+                        }
+                        // BEGIN android-removed
+                        // if (ecP == null)
+                        // {
+                        //     ecP = TeleTrusTNamedCurves.getByName(curveName);
+                        // }
+                        // END android-removed
+                        if (ecP == null)
+                        {
+                            // See if it's actually an OID string (SunJSSE ServerHandshaker setupEphemeralECDHKeys bug)
+                            try
+                            {
+                                DERObjectIdentifier oid = new DERObjectIdentifier(curveName);
+                                ecP = X962NamedCurves.getByOID(oid);
+                                if (ecP == null)
+                                {
+                                    ecP = SECNamedCurves.getByOID(oid);
+                                }
+                                if (ecP == null)
+                                {
+                                    ecP = NISTNamedCurves.getByOID(oid);
+                                }
+                                // BEGIN android-removed
+                                // if (ecP == null)
+                                // {
+                                //     ecP = TeleTrusTNamedCurves.getByOID(oid);
+                                // }
+                                // END android-removed
+                                if (ecP == null)
+                                {
+                                    throw new InvalidAlgorithmParameterException("unknown curve OID: " + curveName);
+                                }
+                            }
+                            catch (IllegalArgumentException ex)
+                            {
+                                throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName);
+                            }
+                        }
+                    }
+
+                    this.ecParams = new ECNamedCurveSpec(
+                            curveName,
+                            ecP.getCurve(),
+                            ecP.getG(),
+                            ecP.getN(),
+                            ecP.getH(),
+                            null); // ecP.getSeed());   Work-around JDK bug -- it won't look up named curves properly if seed is present 
+                }
+
+                java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)ecParams;
+
+                ECCurve curve = EC5Util.convertCurve(p.getCurve());
+                ECPoint g = EC5Util.convertPoint(curve, p.getGenerator(), false);
+
+                param = new ECKeyGenerationParameters(new ECDomainParameters(curve, g, p.getOrder(), BigInteger.valueOf(p.getCofactor())), random);
+
+                engine.init(param);
+                initialised = true;
+            }
+            else if (params == null && ProviderUtil.getEcImplicitlyCa() != null)
+            {
+                ECParameterSpec p = ProviderUtil.getEcImplicitlyCa();
+                this.ecParams = params;
+
+                param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
+
+                engine.init(param);
+                initialised = true;
+            }
+            else if (params == null && ProviderUtil.getEcImplicitlyCa() == null)
+            {
+                throw new InvalidAlgorithmParameterException("null parameter passed but no implicitCA set");
+            }
+            else
+            {
+                throw new InvalidAlgorithmParameterException("parameter object not a ECParameterSpec");
+            }
+        }
+
+        public KeyPair generateKeyPair()
+        {
+            if (!initialised)
+            {
+                // BEGIN android-removed
+                // throw new IllegalStateException("EC Key Pair Generator not initialised");
+                // END android-removed
+                // BEGIN android-added
+                /*
+                 * KeyPairGenerator documentation says that a default initialization must be provided
+                 */
+                initialize(192, random);
+                // END android-added
+            }
+
+            AsymmetricCipherKeyPair     pair = engine.generateKeyPair();
+            ECPublicKeyParameters       pub = (ECPublicKeyParameters)pair.getPublic();
+            ECPrivateKeyParameters      priv = (ECPrivateKeyParameters)pair.getPrivate();
+
+            if (ecParams instanceof ECParameterSpec)
+            {
+                ECParameterSpec p = (ECParameterSpec)ecParams;
+
+                JCEECPublicKey pubKey = new JCEECPublicKey(algorithm, pub, p);
+                return new KeyPair(pubKey,
+                                   new JCEECPrivateKey(algorithm, priv, pubKey, p));
+            }
+            else if (ecParams == null)
+            {
+               return new KeyPair(new JCEECPublicKey(algorithm, pub),
+                                   new JCEECPrivateKey(algorithm, priv));
+            }
+            else
+            {
+                java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)ecParams;
+
+                JCEECPublicKey pubKey = new JCEECPublicKey(algorithm, pub, p);
+                
+                return new KeyPair(pubKey, new JCEECPrivateKey(algorithm, priv, pubKey, p));
+            }
+        }
+    }
+
+    public static class ECDSA
+        extends EC
+    {
+        public ECDSA()
+        {
+            super("ECDSA");
+        }
+    }
+
+    // BEGIN android-removed
+    // public static class ECGOST3410
+    //     extends EC
+    // {
+    //     public ECGOST3410()
+    //     {
+    //         super("ECGOST3410");
+    //     }
+    // }
+    // END android-removed
+
+    public static class ECDH
+        extends EC
+    {
+        public ECDH()
+        {
+            super("ECDH");
+        }
+    }
+
+    public static class ECDHC
+        extends EC
+    {
+        public ECDHC()
+        {
+            super("ECDHC");
+        }
+    }
+
+    public static class ECMQV
+        extends EC
+    {
+        public ECMQV()
+        {
+            super("ECMQV");
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java b/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java
new file mode 100644
index 0000000..13a868c
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java
@@ -0,0 +1,345 @@
+package org.bouncycastle.jce.provider.asymmetric.ec;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.interfaces.ECPublicKey;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DSA;
+import org.bouncycastle.crypto.Digest;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
+// END android-removed
+import org.bouncycastle.crypto.digests.SHA1Digest;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.SHA224Digest;
+// END android-removed
+import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.digests.SHA384Digest;
+import org.bouncycastle.crypto.digests.SHA512Digest;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.crypto.signers.ECDSASigner;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.signers.ECNRSigner;
+// END android-removed
+import org.bouncycastle.jce.interfaces.ECKey;
+import org.bouncycastle.jce.provider.DSABase;
+import org.bouncycastle.jce.provider.DSAEncoder;
+import org.bouncycastle.jce.provider.JDKKeyFactory;
+import org.bouncycastle.jce.provider.util.NullDigest;
+
+public class Signature
+    extends DSABase
+{
+    Signature(Digest digest, DSA signer, DSAEncoder encoder)
+    {
+        super(digest, signer, encoder);
+    }
+
+    protected void engineInitVerify(PublicKey publicKey)
+        throws InvalidKeyException
+    {
+        CipherParameters param;
+
+        if (publicKey instanceof ECPublicKey)
+        {
+            param = ECUtil.generatePublicKeyParameter(publicKey);
+        }
+        else
+        {
+            try
+            {
+                byte[] bytes = publicKey.getEncoded();
+
+                publicKey = JDKKeyFactory.createPublicKeyFromDERStream(bytes);
+
+                if (publicKey instanceof ECPublicKey)
+                {
+                    param = ECUtil.generatePublicKeyParameter(publicKey);
+                }
+                else
+                {
+                    throw new InvalidKeyException("can't recognise key type in ECDSA based signer");
+                }
+            }
+            catch (Exception e)
+            {
+                throw new InvalidKeyException("can't recognise key type in ECDSA based signer");
+            }
+        }
+
+        digest.reset();
+        signer.init(false, param);
+    }
+
+    protected void engineInitSign(
+        PrivateKey privateKey,
+        SecureRandom random)
+        throws InvalidKeyException
+    {
+        CipherParameters param;
+
+        if (privateKey instanceof ECKey)
+        {
+            param = ECUtil.generatePrivateKeyParameter(privateKey);
+        }
+        else
+        {
+            throw new InvalidKeyException("can't recognise key type in ECDSA based signer");
+        }
+
+        digest.reset();
+
+        if (random != null)
+        {
+            signer.init(true, new ParametersWithRandom(param, random));
+        }
+        else
+        {
+            signer.init(true, param);
+        }
+    }
+
+    static public class ecDSA
+        extends Signature
+    {
+        public ecDSA()
+        {
+            super(new SHA1Digest(), new ECDSASigner(), new StdDSAEncoder());
+        }
+    }
+
+    static public class ecDSAnone
+        extends Signature
+    {
+        public ecDSAnone()
+        {
+            super(new NullDigest(), new ECDSASigner(), new StdDSAEncoder());
+        }
+    }
+
+    // BEGIN android-removed
+    // static public class ecDSA224
+    //     extends Signature
+    // {
+    //     public ecDSA224()
+    //     {
+    //         super(new SHA224Digest(), new ECDSASigner(), new StdDSAEncoder());
+    //     }
+    // }
+    // END android-removed
+
+    static public class ecDSA256
+        extends Signature
+    {
+        public ecDSA256()
+        {
+            super(new SHA256Digest(), new ECDSASigner(), new StdDSAEncoder());
+        }
+    }
+
+    static public class ecDSA384
+        extends Signature
+    {
+        public ecDSA384()
+        {
+            super(new SHA384Digest(), new ECDSASigner(), new StdDSAEncoder());
+        }
+    }
+
+    static public class ecDSA512
+        extends Signature
+    {
+        public ecDSA512()
+        {
+            super(new SHA512Digest(), new ECDSASigner(), new StdDSAEncoder());
+        }
+    }
+
+    // BEGIN android-removed
+    // static public class ecDSARipeMD160
+    //     extends Signature
+    // {
+    //     public ecDSARipeMD160()
+    //     {
+    //         super(new RIPEMD160Digest(), new ECDSASigner(), new StdDSAEncoder());
+    //     }
+    // }
+    //
+    // static public class ecNR
+    //     extends Signature
+    // {
+    //     public ecNR()
+    //     {
+    //         super(new SHA1Digest(), new ECNRSigner(), new StdDSAEncoder());
+    //     }
+    // }
+    //
+    // static public class ecNR224
+    //     extends Signature
+    // {
+    //     public ecNR224()
+    //     {
+    //         super(new SHA224Digest(), new ECNRSigner(), new StdDSAEncoder());
+    //     }
+    // }
+    //
+    // static public class ecNR256
+    //     extends Signature
+    // {
+    //     public ecNR256()
+    //     {
+    //         super(new SHA256Digest(), new ECNRSigner(), new StdDSAEncoder());
+    //     }
+    // }
+    //
+    // static public class ecNR384
+    //     extends Signature
+    // {
+    //     public ecNR384()
+    //     {
+    //         super(new SHA384Digest(), new ECNRSigner(), new StdDSAEncoder());
+    //     }
+    // }
+    //
+    // static public class ecNR512
+    //     extends Signature
+    // {
+    //     public ecNR512()
+    //     {
+    //         super(new SHA512Digest(), new ECNRSigner(), new StdDSAEncoder());
+    //     }
+    // }
+    //
+    // static public class ecCVCDSA
+    //     extends Signature
+    // {
+    //     public ecCVCDSA()
+    //     {
+    //         super(new SHA1Digest(), new ECDSASigner(), new CVCDSAEncoder());
+    //     }
+    // }
+    //
+    // static public class ecCVCDSA224
+    //     extends Signature
+    // {
+    //     public ecCVCDSA224()
+    //     {
+    //         super(new SHA224Digest(), new ECDSASigner(), new CVCDSAEncoder());
+    //     }
+    // }
+    //
+    // static public class ecCVCDSA256
+    //     extends Signature
+    // {
+    //     public ecCVCDSA256()
+    //     {
+    //         super(new SHA256Digest(), new ECDSASigner(), new CVCDSAEncoder());
+    //     }
+    // }
+    // END android-removed
+
+    private static class StdDSAEncoder
+        implements DSAEncoder
+    {
+        public byte[] encode(
+            BigInteger r,
+            BigInteger s)
+            throws IOException
+        {
+            ASN1EncodableVector v = new ASN1EncodableVector();
+
+            v.add(new DERInteger(r));
+            v.add(new DERInteger(s));
+
+            return new DERSequence(v).getEncoded(ASN1Encodable.DER);
+        }
+
+        public BigInteger[] decode(
+            byte[] encoding)
+            throws IOException
+        {
+            ASN1Sequence s = (ASN1Sequence)ASN1Object.fromByteArray(encoding);
+            BigInteger[] sig = new BigInteger[2];
+
+            sig[0] = ((DERInteger)s.getObjectAt(0)).getValue();
+            sig[1] = ((DERInteger)s.getObjectAt(1)).getValue();
+
+            return sig;
+        }
+    }
+
+    private static class CVCDSAEncoder
+        implements DSAEncoder
+    {
+        public byte[] encode(
+            BigInteger r,
+            BigInteger s)
+            throws IOException
+        {
+            byte[] first = makeUnsigned(r);
+            byte[] second = makeUnsigned(s);
+            byte[] res;
+
+            if (first.length > second.length)
+            {
+                res = new byte[first.length * 2];
+            }
+            else
+            {
+                res = new byte[second.length * 2];
+            }
+
+            System.arraycopy(first, 0, res, res.length / 2 - first.length, first.length);
+            System.arraycopy(second, 0, res, res.length - second.length, second.length);
+
+            return res;
+        }
+
+
+        private byte[] makeUnsigned(BigInteger val)
+        {
+            byte[] res = val.toByteArray();
+
+            if (res[0] == 0)
+            {
+                byte[] tmp = new byte[res.length - 1];
+
+                System.arraycopy(res, 1, tmp, 0, tmp.length);
+
+                return tmp;
+            }
+
+            return res;
+        }
+
+        public BigInteger[] decode(
+            byte[] encoding)
+            throws IOException
+        {
+            BigInteger[] sig = new BigInteger[2];
+
+            byte[] first = new byte[encoding.length / 2];
+            byte[] second = new byte[encoding.length / 2];
+
+            System.arraycopy(encoding, 0, first, 0, first.length);
+            System.arraycopy(encoding, first.length, second, 0, second.length);
+
+            sig[0] = new BigInteger(1, first);
+            sig[1] = new BigInteger(1, second);
+
+            return sig;
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/spec/ECKeySpec.java b/src/main/java/org/bouncycastle/jce/spec/ECKeySpec.java
new file mode 100644
index 0000000..1215784
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/spec/ECKeySpec.java
@@ -0,0 +1,26 @@
+package org.bouncycastle.jce.spec;
+
+import java.security.spec.KeySpec;
+
+/**
+ * base class for an Elliptic Curve Key Spec
+ */
+public class ECKeySpec
+    implements KeySpec
+{
+    private ECParameterSpec     spec;
+
+    protected ECKeySpec(
+        ECParameterSpec spec)
+    {
+        this.spec = spec;
+    }
+
+    /**
+     * return the domain parameters for the curve
+     */
+    public ECParameterSpec getParams()
+    {
+        return spec;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveParameterSpec.java b/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveParameterSpec.java
new file mode 100644
index 0000000..47416a2
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveParameterSpec.java
@@ -0,0 +1,62 @@
+package org.bouncycastle.jce.spec;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+
+/**
+ * specification signifying that the curve parameters can also be
+ * refered to by name.
+ * <p>
+ * If you are using JDK 1.5 you should be looking at ECNamedCurveSpec.
+ */
+public class ECNamedCurveParameterSpec
+    extends ECParameterSpec
+{
+    private String  name;
+
+    public ECNamedCurveParameterSpec(
+        String      name,
+        ECCurve     curve,
+        ECPoint     G,
+        BigInteger  n)
+    {
+        super(curve, G, n);
+
+        this.name = name;
+    }
+
+    public ECNamedCurveParameterSpec(
+        String      name,
+        ECCurve     curve,
+        ECPoint     G,
+        BigInteger  n,
+        BigInteger  h)
+    {
+        super(curve, G, n, h);
+
+        this.name = name;
+    }
+
+    public ECNamedCurveParameterSpec(
+        String      name,
+        ECCurve     curve,
+        ECPoint     G,
+        BigInteger  n,
+        BigInteger  h,
+        byte[]      seed)
+    {
+        super(curve, G, n, h, seed);
+
+        this.name = name;
+    }
+
+    /**
+     * return the name of the curve the EC domain parameters belong to.
+     */
+    public String getName()
+    {
+        return name;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveSpec.java b/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveSpec.java
new file mode 100644
index 0000000..84ebf70
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveSpec.java
@@ -0,0 +1,121 @@
+package org.bouncycastle.jce.spec;
+
+import java.math.BigInteger;
+import java.security.spec.ECFieldF2m;
+import java.security.spec.ECFieldFp;
+import java.security.spec.ECPoint;
+import java.security.spec.EllipticCurve;
+
+import org.bouncycastle.math.ec.ECCurve;
+
+/**
+ * specification signifying that the curve parameters can also be
+ * referred to by name.
+ */
+public class ECNamedCurveSpec
+    extends java.security.spec.ECParameterSpec
+{
+    private String  name;
+
+    private static EllipticCurve convertCurve(
+        ECCurve  curve,
+        byte[]   seed)
+    {
+        if (curve instanceof ECCurve.Fp)
+        {
+            return new EllipticCurve(new ECFieldFp(((ECCurve.Fp)curve).getQ()), curve.getA().toBigInteger(), curve.getB().toBigInteger(), seed);
+        }
+        else
+        {
+            ECCurve.F2m curveF2m = (ECCurve.F2m)curve;
+            int ks[];
+            
+            if (curveF2m.isTrinomial())
+            {
+                ks = new int[] { curveF2m.getK1() };
+                
+                return new EllipticCurve(new ECFieldF2m(curveF2m.getM(), ks), curve.getA().toBigInteger(), curve.getB().toBigInteger(), seed);
+            }
+            else
+            {
+                ks = new int[] { curveF2m.getK3(), curveF2m.getK2(), curveF2m.getK1() };
+
+                return new EllipticCurve(new ECFieldF2m(curveF2m.getM(), ks), curve.getA().toBigInteger(), curve.getB().toBigInteger(), seed);
+            } 
+        }
+
+    }
+    
+    private static ECPoint convertPoint(
+        org.bouncycastle.math.ec.ECPoint  g)
+    {
+        return new ECPoint(g.getX().toBigInteger(), g.getY().toBigInteger());
+    }
+    
+    public ECNamedCurveSpec(
+        String                              name,
+        ECCurve                             curve,
+        org.bouncycastle.math.ec.ECPoint    g,
+        BigInteger                          n)
+    {
+        super(convertCurve(curve, null), convertPoint(g), n, 1);
+
+        this.name = name;
+    }
+
+    public ECNamedCurveSpec(
+        String          name,
+        EllipticCurve   curve,
+        ECPoint         g,
+        BigInteger      n)
+    {
+        super(curve, g, n, 1);
+
+        this.name = name;
+    }
+    
+    public ECNamedCurveSpec(
+        String                              name,
+        ECCurve                             curve,
+        org.bouncycastle.math.ec.ECPoint    g,
+        BigInteger                          n,
+        BigInteger                          h)
+    {
+        super(convertCurve(curve, null), convertPoint(g), n, h.intValue());
+
+        this.name = name;
+    }
+
+    public ECNamedCurveSpec(
+        String          name,
+        EllipticCurve   curve,
+        ECPoint         g,
+        BigInteger      n,
+        BigInteger      h)
+    {
+        super(curve, g, n, h.intValue());
+
+        this.name = name;
+    }
+    
+    public ECNamedCurveSpec(
+        String                              name,
+        ECCurve                             curve,
+        org.bouncycastle.math.ec.ECPoint    g,
+        BigInteger                          n,
+        BigInteger                          h,
+        byte[]                              seed)
+    {
+        super(convertCurve(curve, seed), convertPoint(g), n, h.intValue());
+        
+        this.name = name;
+    }
+
+    /**
+     * return the name of the curve the EC domain parameters belong to.
+     */
+    public String getName()
+    {
+        return name;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/spec/ECParameterSpec.java b/src/main/java/org/bouncycastle/jce/spec/ECParameterSpec.java
new file mode 100644
index 0000000..e774a11
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/spec/ECParameterSpec.java
@@ -0,0 +1,121 @@
+package org.bouncycastle.jce.spec;
+
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+
+import java.math.BigInteger;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * basic domain parameters for an Elliptic Curve public or private key.
+ */
+public class ECParameterSpec
+    implements AlgorithmParameterSpec
+{
+    private ECCurve     curve;
+    private byte[]      seed;
+    private ECPoint     G;
+    private BigInteger  n;
+    private BigInteger  h;
+
+    public ECParameterSpec(
+        ECCurve     curve,
+        ECPoint     G,
+        BigInteger  n)
+    {
+        this.curve = curve;
+        this.G = G;
+        this.n = n;
+        this.h = BigInteger.valueOf(1);
+        this.seed = null;
+    }
+
+    public ECParameterSpec(
+        ECCurve     curve,
+        ECPoint     G,
+        BigInteger  n,
+        BigInteger  h)
+    {
+        this.curve = curve;
+        this.G = G;
+        this.n = n;
+        this.h = h;
+        this.seed = null;
+    }
+
+    public ECParameterSpec(
+        ECCurve     curve,
+        ECPoint     G,
+        BigInteger  n,
+        BigInteger  h,
+        byte[]      seed)
+    {
+        this.curve = curve;
+        this.G = G;
+        this.n = n;
+        this.h = h;
+        this.seed = seed;
+    }
+
+    /**
+     * return the curve along which the base point lies.
+     * @return the curve
+     */
+    public ECCurve getCurve()
+    {
+        return curve;
+    }
+
+    /**
+     * return the base point we are using for these domain parameters.
+     * @return the base point.
+     */
+    public ECPoint getG()
+    {
+        return G;
+    }
+
+    /**
+     * return the order N of G
+     * @return the order
+     */
+    public BigInteger getN()
+    {
+        return n;
+    }
+
+    /**
+     * return the cofactor H to the order of G.
+     * @return the cofactor
+     */
+    public BigInteger getH()
+    {
+        return h;
+    }
+
+    /**
+     * return the seed used to generate this curve (if available).
+     * @return the random seed
+     */
+    public byte[] getSeed()
+    {
+        return seed;
+    }
+
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof ECParameterSpec))
+        {
+            return false;
+        }
+
+        ECParameterSpec other = (ECParameterSpec)o;
+
+        return this.getCurve().equals(other.getCurve()) && this.getG().equals(other.getG());
+    }
+
+    public int hashCode()
+    {
+        return this.getCurve().hashCode() ^ this.getG().hashCode();
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/spec/ECPrivateKeySpec.java b/src/main/java/org/bouncycastle/jce/spec/ECPrivateKeySpec.java
new file mode 100644
index 0000000..27885c4
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/spec/ECPrivateKeySpec.java
@@ -0,0 +1,35 @@
+package org.bouncycastle.jce.spec;
+
+import java.math.BigInteger;
+
+/**
+ * Elliptic Curve private key specification.
+ */
+public class ECPrivateKeySpec
+    extends ECKeySpec
+{
+    private BigInteger    d;
+
+    /**
+     * base constructor
+     *
+     * @param d the private number for the key.
+     * @param spec the domain parameters for the curve being used.
+     */
+    public ECPrivateKeySpec(
+        BigInteger      d,
+        ECParameterSpec spec)
+    {
+        super(spec);
+
+        this.d = d;
+    }
+
+    /**
+     * return the private number D
+     */
+    public BigInteger getD()
+    {
+        return d;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/spec/ECPublicKeySpec.java b/src/main/java/org/bouncycastle/jce/spec/ECPublicKeySpec.java
new file mode 100644
index 0000000..debab00
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/spec/ECPublicKeySpec.java
@@ -0,0 +1,35 @@
+package org.bouncycastle.jce.spec;
+
+import org.bouncycastle.math.ec.ECPoint;
+
+/**
+ * Elliptic Curve public key specification
+ */
+public class ECPublicKeySpec
+    extends ECKeySpec
+{
+    private ECPoint    q;
+
+    /**
+     * base constructor
+     *
+     * @param q the public point on the curve.
+     * @param spec the domain parameters for the curve.
+     */
+    public ECPublicKeySpec(
+        ECPoint         q,
+        ECParameterSpec spec)
+    {
+        super(spec);
+
+        this.q = q;
+    }
+
+    /**
+     * return the public point q
+     */
+    public ECPoint getQ()
+    {
+        return q;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java b/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java
new file mode 100644
index 0000000..a5b268e
--- /dev/null
+++ b/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java
@@ -0,0 +1,93 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+public class ECAlgorithms
+{
+    public static ECPoint sumOfTwoMultiplies(ECPoint P, BigInteger a,
+        ECPoint Q, BigInteger b)
+    {
+        ECCurve c = P.getCurve();
+        if (!c.equals(Q.getCurve()))
+        {
+            throw new IllegalArgumentException("P and Q must be on same curve");
+        }
+
+        // TODO Add special case back in when WTNAF is enabled
+//        // Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick
+//        if (c instanceof ECCurve.F2m)
+//        {
+//            ECCurve.F2m f2mCurve = (ECCurve.F2m) c;
+//            if (f2mCurve.isKoblitz())
+//            {
+//                return P.multiply(a).add(Q.multiply(b));
+//            }
+//        }
+
+        return implShamirsTrick(P, a, Q, b);
+    }
+
+    /*
+     * "Shamir's Trick", originally due to E. G. Straus
+     * (Addition chains of vectors. American Mathematical Monthly,
+     * 71(7):806-808, Aug./Sept. 1964)
+     * <pre>
+     * Input: The points P, Q, scalar k = (km?, ... , k1, k0)
+     * and scalar l = (lm?, ... , l1, l0).
+     * Output: R = k * P + l * Q.
+     * 1: Z <- P + Q
+     * 2: R <- O
+     * 3: for i from m-1 down to 0 do
+     * 4:        R <- R + R        {point doubling}
+     * 5:        if (ki = 1) and (li = 0) then R <- R + P end if
+     * 6:        if (ki = 0) and (li = 1) then R <- R + Q end if
+     * 7:        if (ki = 1) and (li = 1) then R <- R + Z end if
+     * 8: end for
+     * 9: return R
+     * </pre>
+     */
+    public static ECPoint shamirsTrick(ECPoint P, BigInteger k,
+        ECPoint Q, BigInteger l)
+    {
+        if (!P.getCurve().equals(Q.getCurve()))
+        {
+            throw new IllegalArgumentException("P and Q must be on same curve");
+        }
+
+        return implShamirsTrick(P, k, Q, l);
+    }
+
+    private static ECPoint implShamirsTrick(ECPoint P, BigInteger k,
+        ECPoint Q, BigInteger l)
+    {
+        int m = Math.max(k.bitLength(), l.bitLength());
+        ECPoint Z = P.add(Q);
+        ECPoint R = P.getCurve().getInfinity();
+
+        for (int i = m - 1; i >= 0; --i)
+        {
+            R = R.twice();
+
+            if (k.testBit(i))
+            {
+                if (l.testBit(i))
+                {
+                    R = R.add(Z);
+                }
+                else
+                {
+                    R = R.add(P);
+                }
+            }
+            else
+            {
+                if (l.testBit(i))
+                {
+                    R = R.add(Q);
+                }
+            }
+        }
+
+        return R;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/math/ec/ECConstants.java b/src/main/java/org/bouncycastle/math/ec/ECConstants.java
new file mode 100644
index 0000000..864f746
--- /dev/null
+++ b/src/main/java/org/bouncycastle/math/ec/ECConstants.java
@@ -0,0 +1,12 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+public interface ECConstants
+{
+    public static final BigInteger ZERO = BigInteger.valueOf(0);
+    public static final BigInteger ONE = BigInteger.valueOf(1);
+    public static final BigInteger TWO = BigInteger.valueOf(2);
+    public static final BigInteger THREE = BigInteger.valueOf(3);
+    public static final BigInteger FOUR = BigInteger.valueOf(4);
+}
diff --git a/src/main/java/org/bouncycastle/math/ec/ECCurve.java b/src/main/java/org/bouncycastle/math/ec/ECCurve.java
new file mode 100644
index 0000000..4db07d5
--- /dev/null
+++ b/src/main/java/org/bouncycastle/math/ec/ECCurve.java
@@ -0,0 +1,660 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+import java.util.Random;
+
+/**
+ * base class for an elliptic curve
+ */
+public abstract class ECCurve
+{
+    ECFieldElement a, b;
+
+    public abstract int getFieldSize();
+
+    public abstract ECFieldElement fromBigInteger(BigInteger x);
+
+    public abstract ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression);
+
+    public abstract ECPoint decodePoint(byte[] encoded);
+
+    public abstract ECPoint getInfinity();
+
+    public ECFieldElement getA()
+    {
+        return a;
+    }
+
+    public ECFieldElement getB()
+    {
+        return b;
+    }
+
+    /**
+     * Elliptic curve over Fp
+     */
+    public static class Fp extends ECCurve
+    {
+        BigInteger q;
+        ECPoint.Fp infinity;
+
+        public Fp(BigInteger q, BigInteger a, BigInteger b)
+        {
+            this.q = q;
+            this.a = fromBigInteger(a);
+            this.b = fromBigInteger(b);
+            this.infinity = new ECPoint.Fp(this, null, null);
+        }
+
+        public BigInteger getQ()
+        {
+            return q;
+        }
+
+        public int getFieldSize()
+        {
+            return q.bitLength();
+        }
+
+        public ECFieldElement fromBigInteger(BigInteger x)
+        {
+            return new ECFieldElement.Fp(this.q, x);
+        }
+
+        public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression)
+        {
+            return new ECPoint.Fp(this, fromBigInteger(x), fromBigInteger(y), withCompression);
+        }
+
+        /**
+         * Decode a point on this curve from its ASN.1 encoding. The different
+         * encodings are taken account of, including point compression for
+         * <code>F<sub>p</sub></code> (X9.62 s 4.2.1 pg 17).
+         * @return The decoded point.
+         */
+        public ECPoint decodePoint(byte[] encoded)
+        {
+            ECPoint p = null;
+
+            switch (encoded[0])
+            {
+                // infinity
+            case 0x00:
+                p = getInfinity();
+                break;
+                // compressed
+            case 0x02:
+            case 0x03:
+                int ytilde = encoded[0] & 1;
+                byte[]  i = new byte[encoded.length - 1];
+
+                System.arraycopy(encoded, 1, i, 0, i.length);
+
+                ECFieldElement x = new ECFieldElement.Fp(this.q, new BigInteger(1, i));
+                ECFieldElement alpha = x.multiply(x.square().add(a)).add(b);
+                ECFieldElement beta = alpha.sqrt();
+
+                //
+                // if we can't find a sqrt we haven't got a point on the
+                // curve - run!
+                //
+                if (beta == null)
+                {
+                    throw new RuntimeException("Invalid point compression");
+                }
+
+                int bit0 = (beta.toBigInteger().testBit(0) ? 1 : 0);
+
+                if (bit0 == ytilde)
+                {
+                    p = new ECPoint.Fp(this, x, beta, true);
+                }
+                else
+                {
+                    p = new ECPoint.Fp(this, x,
+                        new ECFieldElement.Fp(this.q, q.subtract(beta.toBigInteger())), true);
+                }
+                break;
+                // uncompressed
+            case 0x04:
+                // hybrid
+            case 0x06:
+            case 0x07:
+                byte[]  xEnc = new byte[(encoded.length - 1) / 2];
+                byte[]  yEnc = new byte[(encoded.length - 1) / 2];
+
+                System.arraycopy(encoded, 1, xEnc, 0, xEnc.length);
+                System.arraycopy(encoded, xEnc.length + 1, yEnc, 0, yEnc.length);
+
+                p = new ECPoint.Fp(this,
+                        new ECFieldElement.Fp(this.q, new BigInteger(1, xEnc)),
+                        new ECFieldElement.Fp(this.q, new BigInteger(1, yEnc)));
+                break;
+            default:
+                throw new RuntimeException("Invalid point encoding 0x" + Integer.toString(encoded[0], 16));
+            }
+
+            return p;
+        }
+
+        public ECPoint getInfinity()
+        {
+            return infinity;
+        }
+
+        public boolean equals(
+            Object anObject) 
+        {
+            if (anObject == this) 
+            {
+                return true;
+            }
+
+            if (!(anObject instanceof ECCurve.Fp)) 
+            {
+                return false;
+            }
+
+            ECCurve.Fp other = (ECCurve.Fp) anObject;
+
+            return this.q.equals(other.q) 
+                    && a.equals(other.a) && b.equals(other.b);
+        }
+
+        public int hashCode() 
+        {
+            return a.hashCode() ^ b.hashCode() ^ q.hashCode();
+        }
+    }
+
+    /**
+     * Elliptic curves over F2m. The Weierstrass equation is given by
+     * <code>y<sup>2</sup> + xy = x<sup>3</sup> + ax<sup>2</sup> + b</code>.
+     */
+    public static class F2m extends ECCurve
+    {
+        /**
+         * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
+         */
+        private int m;  // can't be final - JDK 1.1
+
+        /**
+         * TPB: The integer <code>k</code> where <code>x<sup>m</sup> +
+         * x<sup>k</sup> + 1</code> represents the reduction polynomial
+         * <code>f(z)</code>.<br>
+         * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.<br>
+         */
+        private int k1;  // can't be final - JDK 1.1
+
+        /**
+         * TPB: Always set to <code>0</code><br>
+         * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.<br>
+         */
+        private int k2;  // can't be final - JDK 1.1
+
+        /**
+         * TPB: Always set to <code>0</code><br>
+         * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.<br>
+         */
+        private int k3;  // can't be final - JDK 1.1
+
+        /**
+         * The order of the base point of the curve.
+         */
+        private BigInteger n;  // can't be final - JDK 1.1
+
+        /**
+         * The cofactor of the curve.
+         */
+        private BigInteger h;  // can't be final - JDK 1.1
+        
+         /**
+         * The point at infinity on this curve.
+         */
+        private ECPoint.F2m infinity;  // can't be final - JDK 1.1
+
+        /**
+         * The parameter <code>&mu;</code> of the elliptic curve if this is
+         * a Koblitz curve.
+         */
+        private byte mu = 0;
+
+        /**
+         * The auxiliary values <code>s<sub>0</sub></code> and
+         * <code>s<sub>1</sub></code> used for partial modular reduction for
+         * Koblitz curves.
+         */
+        private BigInteger[] si = null;
+
+        /**
+         * Constructor for Trinomial Polynomial Basis (TPB).
+         * @param m  The exponent <code>m</code> of
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
+         * x<sup>k</sup> + 1</code> represents the reduction
+         * polynomial <code>f(z)</code>.
+         * @param a The coefficient <code>a</code> in the Weierstrass equation
+         * for non-supersingular elliptic curves over
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @param b The coefficient <code>b</code> in the Weierstrass equation
+         * for non-supersingular elliptic curves over
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         */
+        public F2m(
+            int m,
+            int k,
+            BigInteger a,
+            BigInteger b)
+        {
+            this(m, k, 0, 0, a, b, null, null);
+        }
+
+        /**
+         * Constructor for Trinomial Polynomial Basis (TPB).
+         * @param m  The exponent <code>m</code> of
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
+         * x<sup>k</sup> + 1</code> represents the reduction
+         * polynomial <code>f(z)</code>.
+         * @param a The coefficient <code>a</code> in the Weierstrass equation
+         * for non-supersingular elliptic curves over
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @param b The coefficient <code>b</code> in the Weierstrass equation
+         * for non-supersingular elliptic curves over
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @param n The order of the main subgroup of the elliptic curve.
+         * @param h The cofactor of the elliptic curve, i.e.
+         * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
+         */
+        public F2m(
+            int m, 
+            int k, 
+            BigInteger a, 
+            BigInteger b,
+            BigInteger n,
+            BigInteger h)
+        {
+            this(m, k, 0, 0, a, b, n, h);
+        }
+
+        /**
+         * Constructor for Pentanomial Polynomial Basis (PPB).
+         * @param m  The exponent <code>m</code> of
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.
+         * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.
+         * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.
+         * @param a The coefficient <code>a</code> in the Weierstrass equation
+         * for non-supersingular elliptic curves over
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @param b The coefficient <code>b</code> in the Weierstrass equation
+         * for non-supersingular elliptic curves over
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         */
+        public F2m(
+            int m,
+            int k1,
+            int k2,
+            int k3,
+            BigInteger a,
+            BigInteger b)
+        {
+            this(m, k1, k2, k3, a, b, null, null);
+        }
+
+        /**
+         * Constructor for Pentanomial Polynomial Basis (PPB).
+         * @param m  The exponent <code>m</code> of
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.
+         * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.
+         * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.
+         * @param a The coefficient <code>a</code> in the Weierstrass equation
+         * for non-supersingular elliptic curves over
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @param b The coefficient <code>b</code> in the Weierstrass equation
+         * for non-supersingular elliptic curves over
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @param n The order of the main subgroup of the elliptic curve.
+         * @param h The cofactor of the elliptic curve, i.e.
+         * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
+         */
+        public F2m(
+            int m, 
+            int k1, 
+            int k2, 
+            int k3,
+            BigInteger a, 
+            BigInteger b,
+            BigInteger n,
+            BigInteger h)
+        {
+            this.m = m;
+            this.k1 = k1;
+            this.k2 = k2;
+            this.k3 = k3;
+            this.n = n;
+            this.h = h;
+
+            if (k1 == 0)
+            {
+                throw new IllegalArgumentException("k1 must be > 0");
+            }
+
+            if (k2 == 0)
+            {
+                if (k3 != 0)
+                {
+                    throw new IllegalArgumentException("k3 must be 0 if k2 == 0");
+                }
+            }
+            else
+            {
+                if (k2 <= k1)
+                {
+                    throw new IllegalArgumentException("k2 must be > k1");
+                }
+
+                if (k3 <= k2)
+                {
+                    throw new IllegalArgumentException("k3 must be > k2");
+                }
+            }
+
+            this.a = fromBigInteger(a);
+            this.b = fromBigInteger(b);
+            this.infinity = new ECPoint.F2m(this, null, null);
+        }
+
+        public int getFieldSize()
+        {
+            return m;
+        }
+
+        public ECFieldElement fromBigInteger(BigInteger x)
+        {
+            return new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3, x);
+        }
+
+        public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression)
+        {
+            return new ECPoint.F2m(this, fromBigInteger(x), fromBigInteger(y), withCompression);
+        }
+
+        /* (non-Javadoc)
+         * @see org.bouncycastle.math.ec.ECCurve#decodePoint(byte[])
+         */
+        public ECPoint decodePoint(byte[] encoded)
+        {
+            ECPoint p = null;
+
+            switch (encoded[0])
+            {
+                // infinity
+            case 0x00:
+                p = getInfinity();
+                break;
+                // compressed
+            case 0x02:
+            case 0x03:
+                byte[] enc = new byte[encoded.length - 1];
+                System.arraycopy(encoded, 1, enc, 0, enc.length);
+                if (encoded[0] == 0x02) 
+                {
+                        p = decompressPoint(enc, 0);
+                }
+                else 
+                {
+                        p = decompressPoint(enc, 1);
+                }
+                break;
+                // uncompressed
+            case 0x04:
+                // hybrid
+            case 0x06:
+            case 0x07:
+                byte[] xEnc = new byte[(encoded.length - 1) / 2];
+                byte[] yEnc = new byte[(encoded.length - 1) / 2];
+
+                System.arraycopy(encoded, 1, xEnc, 0, xEnc.length);
+                System.arraycopy(encoded, xEnc.length + 1, yEnc, 0, yEnc.length);
+
+                p = new ECPoint.F2m(this,
+                    new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3,
+                        new BigInteger(1, xEnc)),
+                    new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3,
+                        new BigInteger(1, yEnc)), false);
+                break;
+
+            default:
+                throw new RuntimeException("Invalid point encoding 0x" + Integer.toString(encoded[0], 16));
+            }
+
+            return p;
+        }
+
+        public ECPoint getInfinity()
+        {
+            return infinity;
+        }
+
+        /**
+         * Returns true if this is a Koblitz curve (ABC curve).
+         * @return true if this is a Koblitz curve (ABC curve), false otherwise
+         */
+        public boolean isKoblitz()
+        {
+            return ((n != null) && (h != null) &&
+                    ((a.toBigInteger().equals(ECConstants.ZERO)) ||
+                    (a.toBigInteger().equals(ECConstants.ONE))) &&
+                    (b.toBigInteger().equals(ECConstants.ONE)));
+        }
+
+        /**
+         * Returns the parameter <code>&mu;</code> of the elliptic curve.
+         * @return <code>&mu;</code> of the elliptic curve.
+         * @throws IllegalArgumentException if the given ECCurve is not a
+         * Koblitz curve.
+         */
+        synchronized byte getMu()
+        {
+            if (mu == 0)
+            {
+                mu = Tnaf.getMu(this);
+            }
+            return mu;
+        }
+
+        /**
+         * @return the auxiliary values <code>s<sub>0</sub></code> and
+         * <code>s<sub>1</sub></code> used for partial modular reduction for
+         * Koblitz curves.
+         */
+        synchronized BigInteger[] getSi()
+        {
+            if (si == null)
+            {
+                si = Tnaf.getSi(this);
+            }
+            return si;
+        }
+
+        /**
+         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+         * 
+         * @param xEnc
+         *            The encoding of field element xp.
+         * @param ypBit
+         *            ~yp, an indication bit for the decompression of yp.
+         * @return the decompressed point.
+         */
+        private ECPoint decompressPoint(
+            byte[] xEnc, 
+            int ypBit)
+        {
+            ECFieldElement xp = new ECFieldElement.F2m(
+                    this.m, this.k1, this.k2, this.k3, new BigInteger(1, xEnc));
+            ECFieldElement yp = null;
+            if (xp.toBigInteger().equals(ECConstants.ZERO))
+            {
+                yp = (ECFieldElement.F2m)b;
+                for (int i = 0; i < m - 1; i++)
+                {
+                    yp = yp.square();
+                }
+            }
+            else
+            {
+                ECFieldElement beta = xp.add(a).add(
+                        b.multiply(xp.square().invert()));
+                ECFieldElement z = solveQuadradicEquation(beta);
+                if (z == null)
+                {
+                    throw new RuntimeException("Invalid point compression");
+                }
+                int zBit = 0;
+                if (z.toBigInteger().testBit(0))
+                {
+                    zBit = 1;
+                }
+                if (zBit != ypBit)
+                {
+                    z = z.add(new ECFieldElement.F2m(this.m, this.k1, this.k2,
+                            this.k3, ECConstants.ONE));
+                }
+                yp = xp.multiply(z);
+            }
+            
+            return new ECPoint.F2m(this, xp, yp);
+        }
+        
+        /**
+         * 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)
+        {
+            ECFieldElement zeroElement = new ECFieldElement.F2m(
+                    this.m, this.k1, this.k2, this.k3, ECConstants.ZERO);
+
+            if (beta.toBigInteger().equals(ECConstants.ZERO))
+            {
+                return zeroElement;
+            }
+
+            ECFieldElement z = null;
+            ECFieldElement gamma = zeroElement;
+
+            Random rand = new Random();
+            do
+            {
+                ECFieldElement t = new ECFieldElement.F2m(this.m, this.k1,
+                        this.k2, this.k3, new BigInteger(m, rand));
+                z = zeroElement;
+                ECFieldElement w = beta;
+                for (int i = 1; i <= m - 1; i++)
+                {
+                    ECFieldElement w2 = w.square();
+                    z = z.square().add(w2.multiply(t));
+                    w = w2.add(beta);
+                }
+                if (!w.toBigInteger().equals(ECConstants.ZERO))
+                {
+                    return null;
+                }
+                gamma = z.square().add(z);
+            }
+            while (gamma.toBigInteger().equals(ECConstants.ZERO));
+
+            return z;
+        }
+        
+        public boolean equals(
+            Object anObject)
+        {
+            if (anObject == this) 
+            {
+                return true;
+            }
+
+            if (!(anObject instanceof ECCurve.F2m)) 
+            {
+                return false;
+            }
+
+            ECCurve.F2m other = (ECCurve.F2m)anObject;
+            
+            return (this.m == other.m) && (this.k1 == other.k1)
+                && (this.k2 == other.k2) && (this.k3 == other.k3)
+                && a.equals(other.a) && b.equals(other.b);
+        }
+
+        public int hashCode()
+        {
+            return this.a.hashCode() ^ this.b.hashCode() ^ m ^ k1 ^ k2 ^ k3;
+        }
+
+        public int getM()
+        {
+            return m;
+        }
+
+        /**
+         * Return true if curve uses a Trinomial basis.
+         * 
+         * @return true if curve Trinomial, false otherwise.
+         */
+        public boolean isTrinomial()
+        {
+            return k2 == 0 && k3 == 0;
+        }
+        
+        public int getK1()
+        {
+            return k1;
+        }
+
+        public int getK2()
+        {
+            return k2;
+        }
+
+        public int getK3()
+        {
+            return k3;
+        }
+
+        public BigInteger getN()
+        {
+            return n;
+        }
+
+        public BigInteger getH()
+        {
+            return h;
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java b/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java
new file mode 100644
index 0000000..b5e9aa5
--- /dev/null
+++ b/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java
@@ -0,0 +1,1196 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+import java.util.Random;
+
+public abstract class ECFieldElement
+    implements ECConstants
+{
+
+    public abstract BigInteger     toBigInteger();
+    public abstract String         getFieldName();
+    public abstract int            getFieldSize();
+    public abstract ECFieldElement add(ECFieldElement b);
+    public abstract ECFieldElement subtract(ECFieldElement b);
+    public abstract ECFieldElement multiply(ECFieldElement b);
+    public abstract ECFieldElement divide(ECFieldElement b);
+    public abstract ECFieldElement negate();
+    public abstract ECFieldElement square();
+    public abstract ECFieldElement invert();
+    public abstract ECFieldElement sqrt();
+
+    public String toString()
+    {
+        return this.toBigInteger().toString(2);
+    }
+
+    public static class Fp extends ECFieldElement
+    {
+        BigInteger x;
+
+        BigInteger q;
+        
+        public Fp(BigInteger q, BigInteger x)
+        {
+            this.x = x;
+            
+            if (x.compareTo(q) >= 0)
+            {
+                throw new IllegalArgumentException("x value too large in field element");
+            }
+
+            this.q = q;
+        }
+
+        public BigInteger toBigInteger()
+        {
+            return x;
+        }
+
+        /**
+         * return the field name for this field.
+         *
+         * @return the string "Fp".
+         */
+        public String getFieldName()
+        {
+            return "Fp";
+        }
+
+        public int getFieldSize()
+        {
+            return q.bitLength();
+        }
+
+        public BigInteger getQ()
+        {
+            return q;
+        }
+        
+        public ECFieldElement add(ECFieldElement b)
+        {
+            return new Fp(q, x.add(b.toBigInteger()).mod(q));
+        }
+
+        public ECFieldElement subtract(ECFieldElement b)
+        {
+            return new Fp(q, x.subtract(b.toBigInteger()).mod(q));
+        }
+
+        public ECFieldElement multiply(ECFieldElement b)
+        {
+            return new Fp(q, x.multiply(b.toBigInteger()).mod(q));
+        }
+
+        public ECFieldElement divide(ECFieldElement b)
+        {
+            return new Fp(q, x.multiply(b.toBigInteger().modInverse(q)).mod(q));
+        }
+
+        public ECFieldElement negate()
+        {
+            return new Fp(q, x.negate().mod(q));
+        }
+
+        public ECFieldElement square()
+        {
+            return new Fp(q, x.multiply(x).mod(q));
+        }
+
+        public ECFieldElement invert()
+        {
+            return new Fp(q, x.modInverse(q));
+        }
+
+        // D.1.4 91
+        /**
+         * return a sqrt root - the routine verifies that the calculation
+         * returns the right value - if none exists it returns null.
+         */
+        public ECFieldElement sqrt()
+        {
+            if (!q.testBit(0))
+            {
+                throw new RuntimeException("not done yet");
+            }
+
+            // note: even though this class implements ECConstants don't be tempted to
+            // remove the explicit declaration, some J2ME environments don't cope.
+            // p mod 4 == 3
+            if (q.testBit(1))
+            {
+                // z = g^(u+1) + p, p = 4u + 3
+                ECFieldElement z = new Fp(q, x.modPow(q.shiftRight(2).add(ECConstants.ONE), q));
+
+                return z.square().equals(this) ? z : null;
+            }
+
+            // p mod 4 == 1
+            BigInteger qMinusOne = q.subtract(ECConstants.ONE);
+
+            BigInteger legendreExponent = qMinusOne.shiftRight(1);
+            if (!(x.modPow(legendreExponent, q).equals(ECConstants.ONE)))
+            {
+                return null;
+            }
+
+            BigInteger u = qMinusOne.shiftRight(2);
+            BigInteger k = u.shiftLeft(1).add(ECConstants.ONE);
+
+            BigInteger Q = this.x;
+            BigInteger fourQ = Q.shiftLeft(2).mod(q);
+
+            BigInteger U, V;
+            Random rand = new Random();
+            do
+            {
+                BigInteger P;
+                do
+                {
+                    P = new BigInteger(q.bitLength(), rand);
+                }
+                while (P.compareTo(q) >= 0
+                    || !(P.multiply(P).subtract(fourQ).modPow(legendreExponent, q).equals(qMinusOne)));
+
+                BigInteger[] result = lucasSequence(q, P, Q, k);
+                U = result[0];
+                V = result[1];
+
+                if (V.multiply(V).mod(q).equals(fourQ))
+                {
+                    // Integer division by 2, mod q
+                    if (V.testBit(0))
+                    {
+                        V = V.add(q);
+                    }
+
+                    V = V.shiftRight(1);
+
+                    //assert V.multiply(V).mod(q).equals(x);
+
+                    return new ECFieldElement.Fp(q, V);
+                }
+            }
+            while (U.equals(ECConstants.ONE) || U.equals(qMinusOne));
+
+            return null;
+
+//            BigInteger qMinusOne = q.subtract(ECConstants.ONE);
+//            BigInteger legendreExponent = qMinusOne.shiftRight(1); //divide(ECConstants.TWO);
+//            if (!(x.modPow(legendreExponent, q).equals(ECConstants.ONE)))
+//            {
+//                return null;
+//            }
+//
+//            Random rand = new Random();
+//            BigInteger fourX = x.shiftLeft(2);
+//
+//            BigInteger r;
+//            do
+//            {
+//                r = new BigInteger(q.bitLength(), rand);
+//            }
+//            while (r.compareTo(q) >= 0
+//                || !(r.multiply(r).subtract(fourX).modPow(legendreExponent, q).equals(qMinusOne)));
+//
+//            BigInteger n1 = qMinusOne.shiftRight(2); //.divide(ECConstants.FOUR);
+//            BigInteger n2 = n1.add(ECConstants.ONE); //q.add(ECConstants.THREE).divide(ECConstants.FOUR);
+//
+//            BigInteger wOne = WOne(r, x, q);
+//            BigInteger wSum = W(n1, wOne, q).add(W(n2, wOne, q)).mod(q);
+//            BigInteger twoR = r.shiftLeft(1); //ECConstants.TWO.multiply(r);
+//
+//            BigInteger root = twoR.modPow(q.subtract(ECConstants.TWO), q)
+//                .multiply(x).mod(q)
+//                .multiply(wSum).mod(q);
+//
+//            return new Fp(q, root);
+        }
+
+//        private static BigInteger W(BigInteger n, BigInteger wOne, BigInteger p)
+//        {
+//            if (n.equals(ECConstants.ONE))
+//            {
+//                return wOne;
+//            }
+//            boolean isEven = !n.testBit(0);
+//            n = n.shiftRight(1);//divide(ECConstants.TWO);
+//            if (isEven)
+//            {
+//                BigInteger w = W(n, wOne, p);
+//                return w.multiply(w).subtract(ECConstants.TWO).mod(p);
+//            }
+//            BigInteger w1 = W(n.add(ECConstants.ONE), wOne, p);
+//            BigInteger w2 = W(n, wOne, p);
+//            return w1.multiply(w2).subtract(wOne).mod(p);
+//        }
+//
+//        private BigInteger WOne(BigInteger r, BigInteger x, BigInteger p)
+//        {
+//            return r.multiply(r).multiply(x.modPow(q.subtract(ECConstants.TWO), q)).subtract(ECConstants.TWO).mod(p);
+//        }
+
+        private static BigInteger[] lucasSequence(
+            BigInteger  p,
+            BigInteger  P,
+            BigInteger  Q,
+            BigInteger  k)
+        {
+            int n = k.bitLength();
+            int s = k.getLowestSetBit();
+
+            BigInteger Uh = ECConstants.ONE;
+            BigInteger Vl = ECConstants.TWO;
+            BigInteger Vh = P;
+            BigInteger Ql = ECConstants.ONE;
+            BigInteger Qh = ECConstants.ONE;
+
+            for (int j = n - 1; j >= s + 1; --j)
+            {
+                Ql = Ql.multiply(Qh).mod(p);
+
+                if (k.testBit(j))
+                {
+                    Qh = Ql.multiply(Q).mod(p);
+                    Uh = Uh.multiply(Vh).mod(p);
+                    Vl = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);
+                    Vh = Vh.multiply(Vh).subtract(Qh.shiftLeft(1)).mod(p);
+                }
+                else
+                {
+                    Qh = Ql;
+                    Uh = Uh.multiply(Vl).subtract(Ql).mod(p);
+                    Vh = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);
+                    Vl = Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p);
+                }
+            }
+
+            Ql = Ql.multiply(Qh).mod(p);
+            Qh = Ql.multiply(Q).mod(p);
+            Uh = Uh.multiply(Vl).subtract(Ql).mod(p);
+            Vl = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);
+            Ql = Ql.multiply(Qh).mod(p);
+
+            for (int j = 1; j <= s; ++j)
+            {
+                Uh = Uh.multiply(Vl).mod(p);
+                Vl = Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p);
+                Ql = Ql.multiply(Ql).mod(p);
+            }
+
+            return new BigInteger[]{ Uh, Vl };
+        }
+        
+        public boolean equals(Object other)
+        {
+            if (other == this)
+            {
+                return true;
+            }
+
+            if (!(other instanceof ECFieldElement.Fp))
+            {
+                return false;
+            }
+            
+            ECFieldElement.Fp o = (ECFieldElement.Fp)other;
+            return q.equals(o.q) && x.equals(o.x);
+        }
+
+        public int hashCode()
+        {
+            return q.hashCode() ^ x.hashCode();
+        }
+    }
+
+//    /**
+//     * Class representing the Elements of the finite field
+//     * <code>F<sub>2<sup>m</sup></sub></code> in polynomial basis (PB)
+//     * representation. Both trinomial (TPB) and pentanomial (PPB) polynomial
+//     * basis representations are supported. Gaussian normal basis (GNB)
+//     * representation is not supported.
+//     */
+//    public static class F2m extends ECFieldElement
+//    {
+//        BigInteger x;
+//
+//        /**
+//         * Indicates gaussian normal basis representation (GNB). Number chosen
+//         * according to X9.62. GNB is not implemented at present.
+//         */
+//        public static final int GNB = 1;
+//
+//        /**
+//         * Indicates trinomial basis representation (TPB). Number chosen
+//         * according to X9.62.
+//         */
+//        public static final int TPB = 2;
+//
+//        /**
+//         * Indicates pentanomial basis representation (PPB). Number chosen
+//         * according to X9.62.
+//         */
+//        public static final int PPB = 3;
+//
+//        /**
+//         * TPB or PPB.
+//         */
+//        private int representation;
+//
+//        /**
+//         * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
+//         */
+//        private int m;
+//
+//        /**
+//         * TPB: The integer <code>k</code> where <code>x<sup>m</sup> +
+//         * x<sup>k</sup> + 1</code> represents the reduction polynomial
+//         * <code>f(z)</code>.<br>
+//         * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +
+//         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+//         * represents the reduction polynomial <code>f(z)</code>.<br>
+//         */
+//        private int k1;
+//
+//        /**
+//         * TPB: Always set to <code>0</code><br>
+//         * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +
+//         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+//         * represents the reduction polynomial <code>f(z)</code>.<br>
+//         */
+//        private int k2;
+//
+//        /**
+//         * TPB: Always set to <code>0</code><br>
+//         * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +
+//         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+//         * represents the reduction polynomial <code>f(z)</code>.<br>
+//         */
+//        private int k3;
+//        
+//        /**
+//         * Constructor for PPB.
+//         * @param m  The exponent <code>m</code> of
+//         * <code>F<sub>2<sup>m</sup></sub></code>.
+//         * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
+//         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+//         * represents the reduction polynomial <code>f(z)</code>.
+//         * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
+//         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+//         * represents the reduction polynomial <code>f(z)</code>.
+//         * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
+//         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+//         * represents the reduction polynomial <code>f(z)</code>.
+//         * @param x The BigInteger representing the value of the field element.
+//         */
+//        public F2m(
+//            int m, 
+//            int k1, 
+//            int k2, 
+//            int k3,
+//            BigInteger x)
+//        {
+////            super(x);
+//            this.x = x;
+//
+//            if ((k2 == 0) && (k3 == 0))
+//            {
+//                this.representation = TPB;
+//            }
+//            else
+//            {
+//                if (k2 >= k3)
+//                {
+//                    throw new IllegalArgumentException(
+//                            "k2 must be smaller than k3");
+//                }
+//                if (k2 <= 0)
+//                {
+//                    throw new IllegalArgumentException(
+//                            "k2 must be larger than 0");
+//                }
+//                this.representation = PPB;
+//            }
+//
+//            if (x.signum() < 0)
+//            {
+//                throw new IllegalArgumentException("x value cannot be negative");
+//            }
+//
+//            this.m = m;
+//            this.k1 = k1;
+//            this.k2 = k2;
+//            this.k3 = k3;
+//        }
+//
+//        /**
+//         * Constructor for TPB.
+//         * @param m  The exponent <code>m</code> of
+//         * <code>F<sub>2<sup>m</sup></sub></code>.
+//         * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
+//         * x<sup>k</sup> + 1</code> represents the reduction
+//         * polynomial <code>f(z)</code>.
+//         * @param x The BigInteger representing the value of the field element.
+//         */
+//        public F2m(int m, int k, BigInteger x)
+//        {
+//            // Set k1 to k, and set k2 and k3 to 0
+//            this(m, k, 0, 0, x);
+//        }
+//
+//        public BigInteger toBigInteger()
+//        {
+//            return x;
+//        }
+//
+//        public String getFieldName()
+//        {
+//            return "F2m";
+//        }
+//
+//        public int getFieldSize()
+//        {
+//            return m;
+//        }
+//
+//        /**
+//         * Checks, if the ECFieldElements <code>a</code> and <code>b</code>
+//         * are elements of the same field <code>F<sub>2<sup>m</sup></sub></code>
+//         * (having the same representation).
+//         * @param a field element.
+//         * @param b field element to be compared.
+//         * @throws IllegalArgumentException if <code>a</code> and <code>b</code>
+//         * are not elements of the same field
+//         * <code>F<sub>2<sup>m</sup></sub></code> (having the same
+//         * representation). 
+//         */
+//        public static void checkFieldElements(
+//            ECFieldElement a,
+//            ECFieldElement b)
+//        {
+//            if ((!(a instanceof F2m)) || (!(b instanceof F2m)))
+//            {
+//                throw new IllegalArgumentException("Field elements are not "
+//                        + "both instances of ECFieldElement.F2m");
+//            }
+//
+//            if ((a.toBigInteger().signum() < 0) || (b.toBigInteger().signum() < 0))
+//            {
+//                throw new IllegalArgumentException(
+//                        "x value may not be negative");
+//            }
+//
+//            ECFieldElement.F2m aF2m = (ECFieldElement.F2m)a;
+//            ECFieldElement.F2m bF2m = (ECFieldElement.F2m)b;
+//
+//            if ((aF2m.m != bF2m.m) || (aF2m.k1 != bF2m.k1)
+//                    || (aF2m.k2 != bF2m.k2) || (aF2m.k3 != bF2m.k3))
+//            {
+//                throw new IllegalArgumentException("Field elements are not "
+//                        + "elements of the same field F2m");
+//            }
+//
+//            if (aF2m.representation != bF2m.representation)
+//            {
+//                // Should never occur
+//                throw new IllegalArgumentException(
+//                        "One of the field "
+//                                + "elements are not elements has incorrect representation");
+//            }
+//        }
+//
+//        /**
+//         * Computes <code>z * a(z) mod f(z)</code>, where <code>f(z)</code> is
+//         * the reduction polynomial of <code>this</code>.
+//         * @param a The polynomial <code>a(z)</code> to be multiplied by
+//         * <code>z mod f(z)</code>.
+//         * @return <code>z * a(z) mod f(z)</code>
+//         */
+//        private BigInteger multZModF(final BigInteger a)
+//        {
+//            // Left-shift of a(z)
+//            BigInteger az = a.shiftLeft(1);
+//            if (az.testBit(this.m)) 
+//            {
+//                // If the coefficient of z^m in a(z) equals 1, reduction
+//                // modulo f(z) is performed: Add f(z) to to a(z):
+//                // Step 1: Unset mth coeffient of a(z)
+//                az = az.clearBit(this.m);
+//
+//                // Step 2: Add r(z) to a(z), where r(z) is defined as
+//                // f(z) = z^m + r(z), and k1, k2, k3 are the positions of
+//                // the non-zero coefficients in r(z)
+//                az = az.flipBit(0);
+//                az = az.flipBit(this.k1);
+//                if (this.representation == PPB) 
+//                {
+//                    az = az.flipBit(this.k2);
+//                    az = az.flipBit(this.k3);
+//                }
+//            }
+//            return az;
+//        }
+//
+//        public ECFieldElement add(final ECFieldElement b)
+//        {
+//            // No check performed here for performance reasons. Instead the
+//            // elements involved are checked in ECPoint.F2m
+//            // checkFieldElements(this, b);
+//            if (b.toBigInteger().signum() == 0)
+//            {
+//                return this;
+//            }
+//
+//            return new F2m(this.m, this.k1, this.k2, this.k3, this.x.xor(b.toBigInteger()));
+//        }
+//
+//        public ECFieldElement subtract(final ECFieldElement b)
+//        {
+//            // Addition and subtraction are the same in F2m
+//            return add(b);
+//        }
+//
+//
+//        public ECFieldElement multiply(final ECFieldElement b)
+//        {
+//            // Left-to-right shift-and-add field multiplication in F2m
+//            // Input: Binary polynomials a(z) and b(z) of degree at most m-1
+//            // Output: c(z) = a(z) * b(z) mod f(z)
+//
+//            // No check performed here for performance reasons. Instead the
+//            // elements involved are checked in ECPoint.F2m
+//            // checkFieldElements(this, b);
+//            final BigInteger az = this.x;
+//            BigInteger bz = b.toBigInteger();
+//            BigInteger cz;
+//
+//            // Compute c(z) = a(z) * b(z) mod f(z)
+//            if (az.testBit(0)) 
+//            {
+//                cz = bz;
+//            } 
+//            else 
+//            {
+//                cz = ECConstants.ZERO;
+//            }
+//
+//            for (int i = 1; i < this.m; i++) 
+//            {
+//                // b(z) := z * b(z) mod f(z)
+//                bz = multZModF(bz);
+//
+//                if (az.testBit(i)) 
+//                {
+//                    // If the coefficient of x^i in a(z) equals 1, b(z) is added
+//                    // to c(z)
+//                    cz = cz.xor(bz);
+//                }
+//            }
+//            return new ECFieldElement.F2m(m, this.k1, this.k2, this.k3, cz);
+//        }
+//
+//
+//        public ECFieldElement divide(final ECFieldElement b)
+//        {
+//            // There may be more efficient implementations
+//            ECFieldElement bInv = b.invert();
+//            return multiply(bInv);
+//        }
+//
+//        public ECFieldElement negate()
+//        {
+//            // -x == x holds for all x in F2m
+//            return this;
+//        }
+//
+//        public ECFieldElement square()
+//        {
+//            // Naive implementation, can probably be speeded up using modular
+//            // reduction
+//            return multiply(this);
+//        }
+//
+//        public ECFieldElement invert()
+//        {
+//            // Inversion in F2m using the extended Euclidean algorithm
+//            // Input: A nonzero polynomial a(z) of degree at most m-1
+//            // Output: a(z)^(-1) mod f(z)
+//
+//            // u(z) := a(z)
+//            BigInteger uz = this.x;
+//            if (uz.signum() <= 0) 
+//            {
+//                throw new ArithmeticException("x is zero or negative, " +
+//                        "inversion is impossible");
+//            }
+//
+//            // v(z) := f(z)
+//            BigInteger vz = ECConstants.ZERO.setBit(m);
+//            vz = vz.setBit(0);
+//            vz = vz.setBit(this.k1);
+//            if (this.representation == PPB) 
+//            {
+//                vz = vz.setBit(this.k2);
+//                vz = vz.setBit(this.k3);
+//            }
+//
+//            // g1(z) := 1, g2(z) := 0
+//            BigInteger g1z = ECConstants.ONE;
+//            BigInteger g2z = ECConstants.ZERO;
+//
+//            // while u != 1
+//            while (!(uz.equals(ECConstants.ZERO))) 
+//            {
+//                // j := deg(u(z)) - deg(v(z))
+//                int j = uz.bitLength() - vz.bitLength();
+//
+//                // If j < 0 then: u(z) <-> v(z), g1(z) <-> g2(z), j := -j
+//                if (j < 0) 
+//                {
+//                    final BigInteger uzCopy = uz;
+//                    uz = vz;
+//                    vz = uzCopy;
+//
+//                    final BigInteger g1zCopy = g1z;
+//                    g1z = g2z;
+//                    g2z = g1zCopy;
+//
+//                    j = -j;
+//                }
+//
+//                // u(z) := u(z) + z^j * v(z)
+//                // Note, that no reduction modulo f(z) is required, because
+//                // deg(u(z) + z^j * v(z)) <= max(deg(u(z)), j + deg(v(z)))
+//                // = max(deg(u(z)), deg(u(z)) - deg(v(z)) + deg(v(z))
+//                // = deg(u(z))
+//                uz = uz.xor(vz.shiftLeft(j));
+//
+//                // g1(z) := g1(z) + z^j * g2(z)
+//                g1z = g1z.xor(g2z.shiftLeft(j));
+////                if (g1z.bitLength() > this.m) {
+////                    throw new ArithmeticException(
+////                            "deg(g1z) >= m, g1z = " + g1z.toString(2));
+////                }
+//            }
+//            return new ECFieldElement.F2m(
+//                    this.m, this.k1, this.k2, this.k3, g2z);
+//        }
+//
+//        public ECFieldElement sqrt()
+//        {
+//            throw new RuntimeException("Not implemented");
+//        }
+//
+//        /**
+//         * @return the representation of the field
+//         * <code>F<sub>2<sup>m</sup></sub></code>, either of
+//         * TPB (trinomial
+//         * basis representation) or
+//         * PPB (pentanomial
+//         * basis representation).
+//         */
+//        public int getRepresentation()
+//        {
+//            return this.representation;
+//        }
+//
+//        /**
+//         * @return the degree <code>m</code> of the reduction polynomial
+//         * <code>f(z)</code>.
+//         */
+//        public int getM()
+//        {
+//            return this.m;
+//        }
+//
+//        /**
+//         * @return TPB: The integer <code>k</code> where <code>x<sup>m</sup> +
+//         * x<sup>k</sup> + 1</code> represents the reduction polynomial
+//         * <code>f(z)</code>.<br>
+//         * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +
+//         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+//         * represents the reduction polynomial <code>f(z)</code>.<br>
+//         */
+//        public int getK1()
+//        {
+//            return this.k1;
+//        }
+//
+//        /**
+//         * @return TPB: Always returns <code>0</code><br>
+//         * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +
+//         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+//         * represents the reduction polynomial <code>f(z)</code>.<br>
+//         */
+//        public int getK2()
+//        {
+//            return this.k2;
+//        }
+//
+//        /**
+//         * @return TPB: Always set to <code>0</code><br>
+//         * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +
+//         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+//         * represents the reduction polynomial <code>f(z)</code>.<br>
+//         */
+//        public int getK3()
+//        {
+//            return this.k3;
+//        }
+//
+//        public boolean equals(Object anObject)
+//        {
+//            if (anObject == this) 
+//            {
+//                return true;
+//            }
+//
+//            if (!(anObject instanceof ECFieldElement.F2m)) 
+//            {
+//                return false;
+//            }
+//
+//            ECFieldElement.F2m b = (ECFieldElement.F2m)anObject;
+//            
+//            return ((this.m == b.m) && (this.k1 == b.k1) && (this.k2 == b.k2)
+//                && (this.k3 == b.k3)
+//                && (this.representation == b.representation)
+//                && (this.x.equals(b.x)));
+//        }
+//
+//        public int hashCode()
+//        {
+//            return x.hashCode() ^ m ^ k1 ^ k2 ^ k3;
+//        }
+//    }
+
+    /**
+     * Class representing the Elements of the finite field
+     * <code>F<sub>2<sup>m</sup></sub></code> in polynomial basis (PB)
+     * representation. Both trinomial (TPB) and pentanomial (PPB) polynomial
+     * basis representations are supported. Gaussian normal basis (GNB)
+     * representation is not supported.
+     */
+    public static class F2m extends ECFieldElement
+    {
+        /**
+         * Indicates gaussian normal basis representation (GNB). Number chosen
+         * according to X9.62. GNB is not implemented at present.
+         */
+        public static final int GNB = 1;
+
+        /**
+         * Indicates trinomial basis representation (TPB). Number chosen
+         * according to X9.62.
+         */
+        public static final int TPB = 2;
+
+        /**
+         * Indicates pentanomial basis representation (PPB). Number chosen
+         * according to X9.62.
+         */
+        public static final int PPB = 3;
+
+        /**
+         * TPB or PPB.
+         */
+        private int representation;
+
+        /**
+         * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
+         */
+        private int m;
+
+        /**
+         * TPB: The integer <code>k</code> where <code>x<sup>m</sup> +
+         * x<sup>k</sup> + 1</code> represents the reduction polynomial
+         * <code>f(z)</code>.<br>
+         * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.<br>
+         */
+        private int k1;
+
+        /**
+         * TPB: Always set to <code>0</code><br>
+         * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.<br>
+         */
+        private int k2;
+
+        /**
+         * TPB: Always set to <code>0</code><br>
+         * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.<br>
+         */
+        private int k3;
+
+        /**
+         * The <code>IntArray</code> holding the bits.
+         */
+        private IntArray x;
+
+        /**
+         * The number of <code>int</code>s required to hold <code>m</code> bits.
+         */
+        private int t;
+
+        /**
+         * Constructor for PPB.
+         * @param m  The exponent <code>m</code> of
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.
+         * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.
+         * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.
+         * @param x The BigInteger representing the value of the field element.
+         */
+        public F2m(
+            int m, 
+            int k1, 
+            int k2, 
+            int k3,
+            BigInteger x)
+        {
+            // t = m / 32 rounded up to the next integer
+            t = (m + 31) >> 5;
+            this.x = new IntArray(x, t);
+
+            if ((k2 == 0) && (k3 == 0))
+            {
+                this.representation = TPB;
+            }
+            else
+            {
+                if (k2 >= k3)
+                {
+                    throw new IllegalArgumentException(
+                            "k2 must be smaller than k3");
+                }
+                if (k2 <= 0)
+                {
+                    throw new IllegalArgumentException(
+                            "k2 must be larger than 0");
+                }
+                this.representation = PPB;
+            }
+
+            if (x.signum() < 0)
+            {
+                throw new IllegalArgumentException("x value cannot be negative");
+            }
+
+            this.m = m;
+            this.k1 = k1;
+            this.k2 = k2;
+            this.k3 = k3;
+        }
+
+        /**
+         * Constructor for TPB.
+         * @param m  The exponent <code>m</code> of
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
+         * x<sup>k</sup> + 1</code> represents the reduction
+         * polynomial <code>f(z)</code>.
+         * @param x The BigInteger representing the value of the field element.
+         */
+        public F2m(int m, int k, BigInteger x)
+        {
+            // Set k1 to k, and set k2 and k3 to 0
+            this(m, k, 0, 0, x);
+        }
+
+        private F2m(int m, int k1, int k2, int k3, IntArray x)
+        {
+            t = (m + 31) >> 5;
+            this.x = x;
+            this.m = m;
+            this.k1 = k1;
+            this.k2 = k2;
+            this.k3 = k3;
+
+            if ((k2 == 0) && (k3 == 0))
+            {
+                this.representation = TPB;
+            }
+            else
+            {
+                this.representation = PPB;
+            }
+
+        }
+
+        public BigInteger toBigInteger()
+        {
+            return x.toBigInteger();
+        }
+
+        public String getFieldName()
+        {
+            return "F2m";
+        }
+
+        public int getFieldSize()
+        {
+            return m;
+        }
+
+        /**
+         * Checks, if the ECFieldElements <code>a</code> and <code>b</code>
+         * are elements of the same field <code>F<sub>2<sup>m</sup></sub></code>
+         * (having the same representation).
+         * @param a field element.
+         * @param b field element to be compared.
+         * @throws IllegalArgumentException if <code>a</code> and <code>b</code>
+         * are not elements of the same field
+         * <code>F<sub>2<sup>m</sup></sub></code> (having the same
+         * representation). 
+         */
+        public static void checkFieldElements(
+            ECFieldElement a,
+            ECFieldElement b)
+        {
+            if ((!(a instanceof F2m)) || (!(b instanceof F2m)))
+            {
+                throw new IllegalArgumentException("Field elements are not "
+                        + "both instances of ECFieldElement.F2m");
+            }
+
+            ECFieldElement.F2m aF2m = (ECFieldElement.F2m)a;
+            ECFieldElement.F2m bF2m = (ECFieldElement.F2m)b;
+
+            if ((aF2m.m != bF2m.m) || (aF2m.k1 != bF2m.k1)
+                    || (aF2m.k2 != bF2m.k2) || (aF2m.k3 != bF2m.k3))
+            {
+                throw new IllegalArgumentException("Field elements are not "
+                        + "elements of the same field F2m");
+            }
+
+            if (aF2m.representation != bF2m.representation)
+            {
+                // Should never occur
+                throw new IllegalArgumentException(
+                        "One of the field "
+                                + "elements are not elements has incorrect representation");
+            }
+        }
+
+        public ECFieldElement add(final ECFieldElement b)
+        {
+            // No check performed here for performance reasons. Instead the
+            // elements involved are checked in ECPoint.F2m
+            // checkFieldElements(this, b);
+            IntArray iarrClone = (IntArray)this.x.clone();
+            F2m bF2m = (F2m)b;
+            iarrClone.addShifted(bF2m.x, 0);
+            return new F2m(m, k1, k2, k3, iarrClone);
+        }
+
+        public ECFieldElement subtract(final ECFieldElement b)
+        {
+            // Addition and subtraction are the same in F2m
+            return add(b);
+        }
+
+        public ECFieldElement multiply(final ECFieldElement b)
+        {
+            // Right-to-left comb multiplication in the IntArray
+            // Input: Binary polynomials a(z) and b(z) of degree at most m-1
+            // Output: c(z) = a(z) * b(z) mod f(z)
+
+            // No check performed here for performance reasons. Instead the
+            // elements involved are checked in ECPoint.F2m
+            // checkFieldElements(this, b);
+            F2m bF2m = (F2m)b;
+            IntArray mult = x.multiply(bF2m.x, m);
+            mult.reduce(m, new int[]{k1, k2, k3});
+            return new F2m(m, k1, k2, k3, mult);
+        }
+
+        public ECFieldElement divide(final ECFieldElement b)
+        {
+            // There may be more efficient implementations
+            ECFieldElement bInv = b.invert();
+            return multiply(bInv);
+        }
+
+        public ECFieldElement negate()
+        {
+            // -x == x holds for all x in F2m
+            return this;
+        }
+
+        public ECFieldElement square()
+        {
+            IntArray squared = x.square(m);
+            squared.reduce(m, new int[]{k1, k2, k3});
+            return new F2m(m, k1, k2, k3, squared);
+        }
+
+
+        public ECFieldElement invert()
+        {
+            // Inversion in F2m using the extended Euclidean algorithm
+            // Input: A nonzero polynomial a(z) of degree at most m-1
+            // Output: a(z)^(-1) mod f(z)
+
+            // u(z) := a(z)
+            IntArray uz = (IntArray)this.x.clone();
+
+            // v(z) := f(z)
+            IntArray vz = new IntArray(t);
+            vz.setBit(m);
+            vz.setBit(0);
+            vz.setBit(this.k1);
+            if (this.representation == PPB) 
+            {
+                vz.setBit(this.k2);
+                vz.setBit(this.k3);
+            }
+
+            // g1(z) := 1, g2(z) := 0
+            IntArray g1z = new IntArray(t);
+            g1z.setBit(0);
+            IntArray g2z = new IntArray(t);
+
+            // while u != 0
+            while (!uz.isZero())
+//            while (uz.getUsedLength() > 0)
+//            while (uz.bitLength() > 1)
+            {
+                // j := deg(u(z)) - deg(v(z))
+                int j = uz.bitLength() - vz.bitLength();
+
+                // If j < 0 then: u(z) <-> v(z), g1(z) <-> g2(z), j := -j
+                if (j < 0) 
+                {
+                    final IntArray uzCopy = uz;
+                    uz = vz;
+                    vz = uzCopy;
+
+                    final IntArray g1zCopy = g1z;
+                    g1z = g2z;
+                    g2z = g1zCopy;
+
+                    j = -j;
+                }
+
+                // u(z) := u(z) + z^j * v(z)
+                // Note, that no reduction modulo f(z) is required, because
+                // deg(u(z) + z^j * v(z)) <= max(deg(u(z)), j + deg(v(z)))
+                // = max(deg(u(z)), deg(u(z)) - deg(v(z)) + deg(v(z))
+                // = deg(u(z))
+                // uz = uz.xor(vz.shiftLeft(j));
+                // jInt = n / 32
+                int jInt = j >> 5;
+                // jInt = n % 32
+                int jBit = j & 0x1F;
+                IntArray vzShift = vz.shiftLeft(jBit);
+                uz.addShifted(vzShift, jInt);
+
+                // g1(z) := g1(z) + z^j * g2(z)
+//                g1z = g1z.xor(g2z.shiftLeft(j));
+                IntArray g2zShift = g2z.shiftLeft(jBit);
+                g1z.addShifted(g2zShift, jInt);
+                
+            }
+            return new ECFieldElement.F2m(
+                    this.m, this.k1, this.k2, this.k3, g2z);
+        }
+
+        public ECFieldElement sqrt()
+        {
+            throw new RuntimeException("Not implemented");
+        }
+
+        /**
+         * @return the representation of the field
+         * <code>F<sub>2<sup>m</sup></sub></code>, either of
+         * TPB (trinomial
+         * basis representation) or
+         * PPB (pentanomial
+         * basis representation).
+         */
+        public int getRepresentation()
+        {
+            return this.representation;
+        }
+
+        /**
+         * @return the degree <code>m</code> of the reduction polynomial
+         * <code>f(z)</code>.
+         */
+        public int getM()
+        {
+            return this.m;
+        }
+
+        /**
+         * @return TPB: The integer <code>k</code> where <code>x<sup>m</sup> +
+         * x<sup>k</sup> + 1</code> represents the reduction polynomial
+         * <code>f(z)</code>.<br>
+         * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.<br>
+         */
+        public int getK1()
+        {
+            return this.k1;
+        }
+
+        /**
+         * @return TPB: Always returns <code>0</code><br>
+         * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.<br>
+         */
+        public int getK2()
+        {
+            return this.k2;
+        }
+
+        /**
+         * @return TPB: Always set to <code>0</code><br>
+         * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.<br>
+         */
+        public int getK3()
+        {
+            return this.k3;
+        }
+
+        public boolean equals(Object anObject)
+        {
+            if (anObject == this) 
+            {
+                return true;
+            }
+
+            if (!(anObject instanceof ECFieldElement.F2m)) 
+            {
+                return false;
+            }
+
+            ECFieldElement.F2m b = (ECFieldElement.F2m)anObject;
+            
+            return ((this.m == b.m) && (this.k1 == b.k1) && (this.k2 == b.k2)
+                && (this.k3 == b.k3)
+                && (this.representation == b.representation)
+                && (this.x.equals(b.x)));
+        }
+
+        public int hashCode()
+        {
+            return x.hashCode() ^ m ^ k1 ^ k2 ^ k3;
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/math/ec/ECMultiplier.java b/src/main/java/org/bouncycastle/math/ec/ECMultiplier.java
new file mode 100644
index 0000000..4d72e33
--- /dev/null
+++ b/src/main/java/org/bouncycastle/math/ec/ECMultiplier.java
@@ -0,0 +1,19 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Interface for classes encapsulating a point multiplication algorithm
+ * for <code>ECPoint</code>s.
+ */
+interface ECMultiplier
+{
+    /**
+     * Multiplies the <code>ECPoint p</code> by <code>k</code>, i.e.
+     * <code>p</code> is added <code>k</code> times to itself.
+     * @param p The <code>ECPoint</code> to be multiplied.
+     * @param k The factor by which <code>p</code> i multiplied.
+     * @return <code>p</code> multiplied by <code>k</code>.
+     */
+    ECPoint multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo);
+}
diff --git a/src/main/java/org/bouncycastle/math/ec/ECPoint.java b/src/main/java/org/bouncycastle/math/ec/ECPoint.java
new file mode 100644
index 0000000..2d38ee4
--- /dev/null
+++ b/src/main/java/org/bouncycastle/math/ec/ECPoint.java
@@ -0,0 +1,594 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.x9.X9IntegerConverter;
+
+/**
+ * base class for points on elliptic curves.
+ */
+public abstract class ECPoint
+{
+    ECCurve        curve;
+    ECFieldElement x;
+    ECFieldElement y;
+
+    protected boolean withCompression;
+
+    protected ECMultiplier multiplier = null;
+
+    protected PreCompInfo preCompInfo = null;
+
+    private static X9IntegerConverter converter = new X9IntegerConverter();
+
+    protected ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y)
+    {
+        this.curve = curve;
+        this.x = x;
+        this.y = y;
+    }
+    
+    public ECCurve getCurve()
+    {
+        return curve;
+    }
+    
+    public ECFieldElement getX()
+    {
+        return x;
+    }
+
+    public ECFieldElement getY()
+    {
+        return y;
+    }
+
+    public boolean isInfinity()
+    {
+        return x == null && y == null;
+    }
+
+    public boolean isCompressed()
+    {
+        return withCompression;
+    }
+
+    public boolean equals(
+        Object  other)
+    {
+        if (other == this)
+        {
+            return true;
+        }
+
+        if (!(other instanceof ECPoint))
+        {
+            return false;
+        }
+
+        ECPoint o = (ECPoint)other;
+
+        if (this.isInfinity())
+        {
+            return o.isInfinity();
+        }
+
+        return x.equals(o.x) && y.equals(o.y);
+    }
+
+    public int hashCode()
+    {
+        if (this.isInfinity())
+        {
+            return 0;
+        }
+        
+        return x.hashCode() ^ y.hashCode();
+    }
+
+//    /**
+//     * Mainly for testing. Explicitly set the <code>ECMultiplier</code>.
+//     * @param multiplier The <code>ECMultiplier</code> to be used to multiply
+//     * this <code>ECPoint</code>.
+//     */
+//    public void setECMultiplier(ECMultiplier multiplier)
+//    {
+//        this.multiplier = multiplier;
+//    }
+
+    /**
+     * Sets the <code>PreCompInfo</code>. Used by <code>ECMultiplier</code>s
+     * to save the precomputation for this <code>ECPoint</code> to store the
+     * precomputation result for use by subsequent multiplication.
+     * @param preCompInfo The values precomputed by the
+     * <code>ECMultiplier</code>.
+     */
+    void setPreCompInfo(PreCompInfo preCompInfo)
+    {
+        this.preCompInfo = preCompInfo;
+    }
+
+    public abstract byte[] getEncoded();
+
+    public abstract ECPoint add(ECPoint b);
+    public abstract ECPoint subtract(ECPoint b);
+    public abstract ECPoint negate();
+    public abstract ECPoint twice();
+
+    /**
+     * Sets the default <code>ECMultiplier</code>, unless already set. 
+     */
+    synchronized void assertECMultiplier()
+    {
+        if (this.multiplier == null)
+        {
+            this.multiplier = new FpNafMultiplier();
+        }
+    }
+
+    /**
+     * Multiplies this <code>ECPoint</code> by the given number.
+     * @param k The multiplicator.
+     * @return <code>k * this</code>.
+     */
+    public ECPoint multiply(BigInteger k)
+    {
+        if (this.isInfinity())
+        {
+            return this;
+        }
+
+        if (k.signum() == 0)
+        {
+            return this.curve.getInfinity();
+        }
+
+        assertECMultiplier();
+        return this.multiplier.multiply(this, k, preCompInfo);
+    }
+
+    /**
+     * Elliptic curve points over Fp
+     */
+    public static class Fp extends ECPoint
+    {
+        
+        /**
+         * Create a point which encodes with point compression.
+         * 
+         * @param curve the curve to use
+         * @param x affine x co-ordinate
+         * @param y affine y co-ordinate
+         */
+        public Fp(ECCurve curve, ECFieldElement x, ECFieldElement y)
+        {
+            this(curve, x, y, false);
+        }
+
+        /**
+         * Create a point that encodes with or without point compresion.
+         * 
+         * @param curve the curve to use
+         * @param x affine x co-ordinate
+         * @param y affine y co-ordinate
+         * @param withCompression if true encode with point compression
+         */
+        public Fp(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
+        {
+            super(curve, x, y);
+
+            if ((x != null && y == null) || (x == null && y != null))
+            {
+                throw new IllegalArgumentException("Exactly one of the field elements is null");
+            }
+
+            this.withCompression = withCompression;
+        }
+         
+        /**
+         * return the field element encoded with point compression. (S 4.3.6)
+         */
+        public byte[] getEncoded()
+        {
+            if (this.isInfinity()) 
+            {
+                return new byte[1];
+            }
+
+            int qLength = converter.getByteLength(x);
+            
+            if (withCompression)
+            {
+                byte    PC;
+    
+                if (this.getY().toBigInteger().testBit(0))
+                {
+                    PC = 0x03;
+                }
+                else
+                {
+                    PC = 0x02;
+                }
+    
+                byte[]  X = converter.integerToBytes(this.getX().toBigInteger(), qLength);
+                byte[]  PO = new byte[X.length + 1];
+    
+                PO[0] = PC;
+                System.arraycopy(X, 0, PO, 1, X.length);
+    
+                return PO;
+            }
+            else
+            {
+                byte[]  X = converter.integerToBytes(this.getX().toBigInteger(), qLength);
+                byte[]  Y = converter.integerToBytes(this.getY().toBigInteger(), qLength);
+                byte[]  PO = new byte[X.length + Y.length + 1];
+                
+                PO[0] = 0x04;
+                System.arraycopy(X, 0, PO, 1, X.length);
+                System.arraycopy(Y, 0, PO, X.length + 1, Y.length);
+
+                return PO;
+            }
+        }
+
+        // B.3 pg 62
+        public ECPoint add(ECPoint b)
+        {
+            if (this.isInfinity())
+            {
+                return b;
+            }
+
+            if (b.isInfinity())
+            {
+                return this;
+            }
+
+            // Check if b = this or b = -this
+            if (this.x.equals(b.x))
+            {
+                if (this.y.equals(b.y))
+                {
+                    // this = b, i.e. this must be doubled
+                    return this.twice();
+                }
+
+                // this = -b, i.e. the result is the point at infinity
+                return this.curve.getInfinity();
+            }
+
+            ECFieldElement gamma = b.y.subtract(this.y).divide(b.x.subtract(this.x));
+
+            ECFieldElement x3 = gamma.square().subtract(this.x).subtract(b.x);
+            ECFieldElement y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
+
+            return new ECPoint.Fp(curve, x3, y3);
+        }
+
+        // B.3 pg 62
+        public ECPoint twice()
+        {
+            if (this.isInfinity())
+            {
+                // Twice identity element (point at infinity) is identity
+                return this;
+            }
+
+            if (this.y.toBigInteger().signum() == 0) 
+            {
+                // if y1 == 0, then (x1, y1) == (x1, -y1)
+                // and hence this = -this and thus 2(x1, y1) == infinity
+                return this.curve.getInfinity();
+            }
+
+            ECFieldElement TWO = this.curve.fromBigInteger(BigInteger.valueOf(2));
+            ECFieldElement THREE = this.curve.fromBigInteger(BigInteger.valueOf(3));
+            ECFieldElement gamma = this.x.square().multiply(THREE).add(curve.a).divide(y.multiply(TWO));
+
+            ECFieldElement x3 = gamma.square().subtract(this.x.multiply(TWO));
+            ECFieldElement y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
+                
+            return new ECPoint.Fp(curve, x3, y3, this.withCompression);
+        }
+
+        // D.3.2 pg 102 (see Note:)
+        public ECPoint subtract(ECPoint b)
+        {
+            if (b.isInfinity())
+            {
+                return this;
+            }
+
+            // Add -b
+            return add(b.negate());
+        }
+
+        public ECPoint negate()
+        {
+            return new ECPoint.Fp(curve, this.x, this.y.negate(), this.withCompression);
+        }
+
+        // TODO Uncomment this to enable WNAF algorithm for Fp point multiplication
+//        /**
+//         * Sets the default <code>ECMultiplier</code>, unless already set. 
+//         */
+//        synchronized void assertECMultiplier()
+//        {
+//            if (this.multiplier == null)
+//            {
+//                this.multiplier = new WNafMultiplier();
+//            }
+//        }
+    }
+
+    /**
+     * Elliptic curve points over F2m
+     */
+    public static class F2m extends ECPoint
+    {
+        /**
+         * @param curve base curve
+         * @param x x point
+         * @param y y point
+         */
+        public F2m(ECCurve curve, ECFieldElement x, ECFieldElement y)
+        {
+            this(curve, x, y, false);
+        }
+        
+        /**
+         * @param curve base curve
+         * @param x x point
+         * @param y y point
+         * @param withCompression true if encode with point compression.
+         */
+        public F2m(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
+        {
+            super(curve, x, y);
+
+            if ((x != null && y == null) || (x == null && y != null))
+            {
+                throw new IllegalArgumentException("Exactly one of the field elements is null");
+            }
+            
+            if (x != null)
+            {
+                // Check if x and y are elements of the same field
+                ECFieldElement.F2m.checkFieldElements(this.x, this.y);
+    
+                // Check if x and a are elements of the same field
+                if (curve != null)
+                {
+                    ECFieldElement.F2m.checkFieldElements(this.x, this.curve.getA());
+                }
+            }
+            
+            this.withCompression = withCompression;
+        }
+
+        /**
+         * @deprecated use ECCurve.getInfinity()
+         * Constructor for point at infinity
+         */
+        public F2m(ECCurve curve)
+        {
+            super(curve, null, null);
+        }
+
+        /* (non-Javadoc)
+         * @see org.bouncycastle.math.ec.ECPoint#getEncoded()
+         */
+        public byte[] getEncoded()
+        {
+            if (this.isInfinity()) 
+            {
+                return new byte[1];
+            }
+
+            int byteCount = converter.getByteLength(this.x);
+            byte[] X = converter.integerToBytes(this.getX().toBigInteger(), byteCount);
+            byte[] PO;
+
+            if (withCompression)
+            {
+                // See X9.62 4.3.6 and 4.2.2
+                PO = new byte[byteCount + 1];
+
+                PO[0] = 0x02;
+                // X9.62 4.2.2 and 4.3.6:
+                // if x = 0 then ypTilde := 0, else ypTilde is the rightmost
+                // bit of y * x^(-1)
+                // if ypTilde = 0, then PC := 02, else PC := 03
+                // Note: PC === PO[0]
+                if (!(this.getX().toBigInteger().equals(ECConstants.ZERO)))
+                {
+                    if (this.getY().multiply(this.getX().invert())
+                            .toBigInteger().testBit(0))
+                    {
+                        // ypTilde = 1, hence PC = 03
+                        PO[0] = 0x03;
+                    }
+                }
+
+                System.arraycopy(X, 0, PO, 1, byteCount);
+            }
+            else
+            {
+                byte[] Y = converter.integerToBytes(this.getY().toBigInteger(), byteCount);
+    
+                PO = new byte[byteCount + byteCount + 1];
+    
+                PO[0] = 0x04;
+                System.arraycopy(X, 0, PO, 1, byteCount);
+                System.arraycopy(Y, 0, PO, byteCount + 1, byteCount);    
+            }
+
+            return PO;
+        }
+
+        /**
+         * Check, if two <code>ECPoint</code>s can be added or subtracted.
+         * @param a The first <code>ECPoint</code> to check.
+         * @param b The second <code>ECPoint</code> to check.
+         * @throws IllegalArgumentException if <code>a</code> and <code>b</code>
+         * cannot be added.
+         */
+        private static void checkPoints(ECPoint a, ECPoint b)
+        {
+            // Check, if points are on the same curve
+            if (!(a.curve.equals(b.curve)))
+            {
+                throw new IllegalArgumentException("Only points on the same "
+                        + "curve can be added or subtracted");
+            }
+
+//            ECFieldElement.F2m.checkFieldElements(a.x, b.x);
+        }
+
+        /* (non-Javadoc)
+         * @see org.bouncycastle.math.ec.ECPoint#add(org.bouncycastle.math.ec.ECPoint)
+         */
+        public ECPoint add(ECPoint b)
+        {
+            checkPoints(this, b);
+            return addSimple((ECPoint.F2m)b);
+        }
+
+        /**
+         * Adds another <code>ECPoints.F2m</code> to <code>this</code> without
+         * checking if both points are on the same curve. Used by multiplication
+         * algorithms, because there all points are a multiple of the same point
+         * and hence the checks can be omitted.
+         * @param b The other <code>ECPoints.F2m</code> to add to
+         * <code>this</code>.
+         * @return <code>this + b</code>
+         */
+        public ECPoint.F2m addSimple(ECPoint.F2m b)
+        {
+            ECPoint.F2m other = b;
+            if (this.isInfinity())
+            {
+                return other;
+            }
+
+            if (other.isInfinity())
+            {
+                return this;
+            }
+
+            ECFieldElement.F2m x2 = (ECFieldElement.F2m)other.getX();
+            ECFieldElement.F2m y2 = (ECFieldElement.F2m)other.getY();
+
+            // Check if other = this or other = -this
+            if (this.x.equals(x2))
+            {
+                if (this.y.equals(y2))
+                {
+                    // this = other, i.e. this must be doubled
+                    return (ECPoint.F2m)this.twice();
+                }
+
+                // this = -other, i.e. the result is the point at infinity
+                return (ECPoint.F2m)this.curve.getInfinity();
+            }
+
+            ECFieldElement.F2m lambda
+                = (ECFieldElement.F2m)(this.y.add(y2)).divide(this.x.add(x2));
+
+            ECFieldElement.F2m x3
+                = (ECFieldElement.F2m)lambda.square().add(lambda).add(this.x).add(x2).add(this.curve.getA());
+
+            ECFieldElement.F2m y3
+                = (ECFieldElement.F2m)lambda.multiply(this.x.add(x3)).add(x3).add(this.y);
+
+            return new ECPoint.F2m(curve, x3, y3, withCompression);
+        }
+
+        /* (non-Javadoc)
+         * @see org.bouncycastle.math.ec.ECPoint#subtract(org.bouncycastle.math.ec.ECPoint)
+         */
+        public ECPoint subtract(ECPoint b)
+        {
+            checkPoints(this, b);
+            return subtractSimple((ECPoint.F2m)b);
+        }
+
+        /**
+         * Subtracts another <code>ECPoints.F2m</code> from <code>this</code>
+         * without checking if both points are on the same curve. Used by
+         * multiplication algorithms, because there all points are a multiple
+         * of the same point and hence the checks can be omitted.
+         * @param b The other <code>ECPoints.F2m</code> to subtract from
+         * <code>this</code>.
+         * @return <code>this - b</code>
+         */
+        public ECPoint.F2m subtractSimple(ECPoint.F2m b)
+        {
+            if (b.isInfinity())
+            {
+                return this;
+            }
+
+            // Add -b
+            return addSimple((ECPoint.F2m)b.negate());
+        }
+
+        /* (non-Javadoc)
+         * @see org.bouncycastle.math.ec.ECPoint#twice()
+         */
+        public ECPoint twice()
+        {
+            if (this.isInfinity()) 
+            {
+                // Twice identity element (point at infinity) is identity
+                return this;
+            }
+
+            if (this.x.toBigInteger().signum() == 0) 
+            {
+                // if x1 == 0, then (x1, y1) == (x1, x1 + y1)
+                // and hence this = -this and thus 2(x1, y1) == infinity
+                return this.curve.getInfinity();
+            }
+
+            ECFieldElement.F2m lambda
+                = (ECFieldElement.F2m)this.x.add(this.y.divide(this.x));
+
+            ECFieldElement.F2m x3
+                = (ECFieldElement.F2m)lambda.square().add(lambda).
+                    add(this.curve.getA());
+
+            ECFieldElement ONE = this.curve.fromBigInteger(ECConstants.ONE);
+            ECFieldElement.F2m y3
+                = (ECFieldElement.F2m)this.x.square().add(
+                    x3.multiply(lambda.add(ONE)));
+
+            return new ECPoint.F2m(this.curve, x3, y3, withCompression);
+        }
+
+        public ECPoint negate()
+        {
+            return new ECPoint.F2m(curve, this.getX(), this.getY().add(this.getX()), withCompression);
+        }
+
+        // TODO Uncomment this to enable WNAF/WTNAF F2m point multiplication
+//        /**
+//         * Sets the appropriate <code>ECMultiplier</code>, unless already set. 
+//         */
+//        synchronized void assertECMultiplier()
+//        {
+//            if (this.multiplier == null)
+//            {
+//                if (((ECCurve.F2m)(this.curve)).isKoblitz())
+//                {
+//                    this.multiplier = new WTauNafMultiplier();
+//                }
+//                else
+//                {
+//                    this.multiplier = new WNafMultiplier();
+//                }
+//            }
+//        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/math/ec/FpNafMultiplier.java b/src/main/java/org/bouncycastle/math/ec/FpNafMultiplier.java
new file mode 100644
index 0000000..35e601d
--- /dev/null
+++ b/src/main/java/org/bouncycastle/math/ec/FpNafMultiplier.java
@@ -0,0 +1,39 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Class implementing the NAF (Non-Adjacent Form) multiplication algorithm.
+ */
+class FpNafMultiplier implements ECMultiplier
+{
+    /**
+     * D.3.2 pg 101
+     * @see org.bouncycastle.math.ec.ECMultiplier#multiply(org.bouncycastle.math.ec.ECPoint, java.math.BigInteger)
+     */
+    public ECPoint multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo)
+    {
+        // TODO Probably should try to add this
+        // BigInteger e = k.mod(n); // n == order of p
+        BigInteger e = k;
+        BigInteger h = e.multiply(BigInteger.valueOf(3));
+
+        ECPoint neg = p.negate();
+        ECPoint R = p;
+
+        for (int i = h.bitLength() - 2; i > 0; --i)
+        {             
+            R = R.twice();
+
+            boolean hBit = h.testBit(i);
+            boolean eBit = e.testBit(i);
+
+            if (hBit != eBit)
+            {
+                R = R.add(hBit ? p : neg);
+            }
+        }
+
+        return R;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/math/ec/IntArray.java b/src/main/java/org/bouncycastle/math/ec/IntArray.java
new file mode 100644
index 0000000..ead38c4
--- /dev/null
+++ b/src/main/java/org/bouncycastle/math/ec/IntArray.java
@@ -0,0 +1,518 @@
+package org.bouncycastle.math.ec;
+
+import org.bouncycastle.util.Arrays;
+
+import java.math.BigInteger;
+
+class IntArray
+{
+    // TODO make m fixed for the IntArray, and hence compute T once and for all
+
+    private int[] m_ints;
+
+    public IntArray(int intLen)
+    {
+        m_ints = new int[intLen];
+    }
+
+    public IntArray(int[] ints)
+    {
+        m_ints = ints;
+    }
+
+    public IntArray(BigInteger bigInt)
+    {
+        this(bigInt, 0);
+    }
+
+    public IntArray(BigInteger bigInt, int minIntLen)
+    {
+        if (bigInt.signum() == -1)
+        {
+            throw new IllegalArgumentException("Only positive Integers allowed");
+        }
+        if (bigInt.equals(ECConstants.ZERO))
+        {
+            m_ints = new int[] { 0 };
+            return;
+        }
+
+        byte[] barr = bigInt.toByteArray();
+        int barrLen = barr.length;
+        int barrStart = 0;
+        if (barr[0] == 0)
+        {
+            // First byte is 0 to enforce highest (=sign) bit is zero.
+            // In this case ignore barr[0].
+            barrLen--;
+            barrStart = 1;
+        }
+        int intLen = (barrLen + 3) / 4;
+        if (intLen < minIntLen)
+        {
+            m_ints = new int[minIntLen];
+        }
+        else
+        {
+            m_ints = new int[intLen];
+        }
+
+        int iarrJ = intLen - 1;
+        int rem = barrLen % 4 + barrStart;
+        int temp = 0;
+        int barrI = barrStart;
+        if (barrStart < rem)
+        {
+            for (; barrI < rem; barrI++)
+            {
+                temp <<= 8;
+                int barrBarrI = barr[barrI];
+                if (barrBarrI < 0)
+                {
+                    barrBarrI += 256;
+                }
+                temp |= barrBarrI;
+            }
+            m_ints[iarrJ--] = temp;
+        }
+
+        for (; iarrJ >= 0; iarrJ--)
+        {
+            temp = 0;
+            for (int i = 0; i < 4; i++)
+            {
+                temp <<= 8;
+                int barrBarrI = barr[barrI++];
+                if (barrBarrI < 0)
+                {
+                    barrBarrI += 256;
+                }
+                temp |= barrBarrI;
+            }
+            m_ints[iarrJ] = temp;
+        }
+    }
+
+    public boolean isZero()
+    {
+        return m_ints.length == 0
+            || (m_ints[0] == 0 && getUsedLength() == 0);
+    }
+
+    public int getUsedLength()
+    {
+        int highestIntPos = m_ints.length;
+
+        if (highestIntPos < 1)
+        {
+            return 0;
+        }
+
+        // Check if first element will act as sentinel
+        if (m_ints[0] != 0)
+        {
+            while (m_ints[--highestIntPos] == 0)
+            {
+            }
+            return highestIntPos + 1;
+        }
+
+        do
+        {
+            if (m_ints[--highestIntPos] != 0)
+            {
+                return highestIntPos + 1;
+            }
+        }
+        while (highestIntPos > 0);
+
+        return 0;
+    }
+
+    public int bitLength()
+    {
+        // JDK 1.5: see Integer.numberOfLeadingZeros()
+        int intLen = getUsedLength();
+        if (intLen == 0)
+        {
+            return 0;
+        }
+
+        int last = intLen - 1;
+        int highest = m_ints[last];
+        int bits = (last << 5) + 1;
+
+        // A couple of binary search steps
+        if ((highest & 0xffff0000) != 0)
+        {
+            if ((highest & 0xff000000) != 0)
+            {
+                bits += 24;
+                highest >>>= 24;
+            }
+            else
+            {
+                bits += 16;
+                highest >>>= 16;
+            }
+        }
+        else if (highest > 0x000000ff)
+        {
+            bits += 8;
+            highest >>>= 8;
+        }
+
+        while (highest != 1)
+        {
+            ++bits;
+            highest >>>= 1;
+        }
+
+        return bits;
+    }
+
+    private int[] resizedInts(int newLen)
+    {
+        int[] newInts = new int[newLen];
+        int oldLen = m_ints.length;
+        int copyLen = oldLen < newLen ? oldLen : newLen;
+        System.arraycopy(m_ints, 0, newInts, 0, copyLen);
+        return newInts;
+    }
+
+    public BigInteger toBigInteger()
+    {
+        int usedLen = getUsedLength();
+        if (usedLen == 0)
+        {
+            return ECConstants.ZERO;
+        }
+
+        int highestInt = m_ints[usedLen - 1];
+        byte[] temp = new byte[4];
+        int barrI = 0;
+        boolean trailingZeroBytesDone = false;
+        for (int j = 3; j >= 0; j--)
+        {
+            byte thisByte = (byte) (highestInt >>> (8 * j));
+            if (trailingZeroBytesDone || (thisByte != 0))
+            {
+                trailingZeroBytesDone = true;
+                temp[barrI++] = thisByte;
+            }
+        }
+
+        int barrLen = 4 * (usedLen - 1) + barrI;
+        byte[] barr = new byte[barrLen];
+        for (int j = 0; j < barrI; j++)
+        {
+            barr[j] = temp[j];
+        }
+        // Highest value int is done now
+
+        for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--)
+        {
+            for (int j = 3; j >= 0; j--)
+            {
+                barr[barrI++] = (byte) (m_ints[iarrJ] >>> (8 * j));
+            }
+        }
+        return new BigInteger(1, barr);
+    }
+
+    public void shiftLeft()
+    {
+        int usedLen = getUsedLength();
+        if (usedLen == 0)
+        {
+            return;
+        }
+        if (m_ints[usedLen - 1] < 0)
+        {
+            // highest bit of highest used byte is set, so shifting left will
+            // make the IntArray one byte longer
+            usedLen++;
+            if (usedLen > m_ints.length)
+            {
+                // make the m_ints one byte longer, because we need one more
+                // byte which is not available in m_ints
+                m_ints = resizedInts(m_ints.length + 1);
+            }
+        }
+
+        boolean carry = false;
+        for (int i = 0; i < usedLen; i++)
+        {
+            // nextCarry is true if highest bit is set
+            boolean nextCarry = m_ints[i] < 0;
+            m_ints[i] <<= 1;
+            if (carry)
+            {
+                // set lowest bit
+                m_ints[i] |= 1;
+            }
+            carry = nextCarry;
+        }
+    }
+
+    public IntArray shiftLeft(int n)
+    {
+        int usedLen = getUsedLength();
+        if (usedLen == 0)
+        {
+            return this;
+        }
+
+        if (n == 0)
+        {
+            return this;
+        }
+
+        if (n > 31)
+        {
+            throw new IllegalArgumentException("shiftLeft() for max 31 bits "
+                + ", " + n + "bit shift is not possible");
+        }
+
+        int[] newInts = new int[usedLen + 1];
+
+        int nm32 = 32 - n;
+        newInts[0] = m_ints[0] << n;
+        for (int i = 1; i < usedLen; i++)
+        {
+            newInts[i] = (m_ints[i] << n) | (m_ints[i - 1] >>> nm32);
+        }
+        newInts[usedLen] = m_ints[usedLen - 1] >>> nm32;
+
+        return new IntArray(newInts);
+    }
+
+    public void addShifted(IntArray other, int shift)
+    {
+        int usedLenOther = other.getUsedLength();
+        int newMinUsedLen = usedLenOther + shift;
+        if (newMinUsedLen > m_ints.length)
+        {
+            m_ints = resizedInts(newMinUsedLen);
+            //System.out.println("Resize required");
+        }
+
+        for (int i = 0; i < usedLenOther; i++)
+        {
+            m_ints[i + shift] ^= other.m_ints[i];
+        }
+    }
+
+    public int getLength()
+    {
+        return m_ints.length;
+    }
+
+    public boolean testBit(int n)
+    {
+        // theInt = n / 32
+        int theInt = n >> 5;
+        // theBit = n % 32
+        int theBit = n & 0x1F;
+        int tester = 1 << theBit;
+        return ((m_ints[theInt] & tester) != 0);
+    }
+
+    public void flipBit(int n)
+    {
+        // theInt = n / 32
+        int theInt = n >> 5;
+        // theBit = n % 32
+        int theBit = n & 0x1F;
+        int flipper = 1 << theBit;
+        m_ints[theInt] ^= flipper;
+    }
+
+    public void setBit(int n)
+    {
+        // theInt = n / 32
+        int theInt = n >> 5;
+        // theBit = n % 32
+        int theBit = n & 0x1F;
+        int setter = 1 << theBit;
+        m_ints[theInt] |= setter;
+    }
+
+    public IntArray multiply(IntArray other, int m)
+    {
+        // Lenght of c is 2m bits rounded up to the next int (32 bit)
+        int t = (m + 31) >> 5;
+        if (m_ints.length < t)
+        {
+            m_ints = resizedInts(t);
+        }
+
+        IntArray b = new IntArray(other.resizedInts(other.getLength() + 1));
+        IntArray c = new IntArray((m + m + 31) >> 5);
+        // IntArray c = new IntArray(t + t);
+        int testBit = 1;
+        for (int k = 0; k < 32; k++)
+        {
+            for (int j = 0; j < t; j++)
+            {
+                if ((m_ints[j] & testBit) != 0)
+                {
+                    // The kth bit of m_ints[j] is set
+                    c.addShifted(b, j);
+                }
+            }
+            testBit <<= 1;
+            b.shiftLeft();
+        }
+        return c;
+    }
+
+    // public IntArray multiplyLeftToRight(IntArray other, int m) {
+    // // Lenght of c is 2m bits rounded up to the next int (32 bit)
+    // int t = (m + 31) / 32;
+    // if (m_ints.length < t) {
+    // m_ints = resizedInts(t);
+    // }
+    //
+    // IntArray b = new IntArray(other.resizedInts(other.getLength() + 1));
+    // IntArray c = new IntArray((m + m + 31) / 32);
+    // // IntArray c = new IntArray(t + t);
+    // int testBit = 1 << 31;
+    // for (int k = 31; k >= 0; k--) {
+    // for (int j = 0; j < t; j++) {
+    // if ((m_ints[j] & testBit) != 0) {
+    // // The kth bit of m_ints[j] is set
+    // c.addShifted(b, j);
+    // }
+    // }
+    // testBit >>>= 1;
+    // if (k > 0) {
+    // c.shiftLeft();
+    // }
+    // }
+    // return c;
+    // }
+
+    // TODO note, redPol.length must be 3 for TPB and 5 for PPB
+    public void reduce(int m, int[] redPol)
+    {
+        for (int i = m + m - 2; i >= m; i--)
+        {
+            if (testBit(i))
+            {
+                int bit = i - m;
+                flipBit(bit);
+                flipBit(i);
+                int l = redPol.length;
+                while (--l >= 0)
+                {
+                    flipBit(redPol[l] + bit);
+                }
+            }
+        }
+        m_ints = resizedInts((m + 31) >> 5);
+    }
+
+    public IntArray square(int m)
+    {
+        // TODO make the table static final
+        final int[] table = { 0x0, 0x1, 0x4, 0x5, 0x10, 0x11, 0x14, 0x15, 0x40,
+            0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55 };
+
+        int t = (m + 31) >> 5;
+        if (m_ints.length < t)
+        {
+            m_ints = resizedInts(t);
+        }
+
+        IntArray c = new IntArray(t + t);
+
+        // TODO twice the same code, put in separate private method
+        for (int i = 0; i < t; i++)
+        {
+            int v0 = 0;
+            for (int j = 0; j < 4; j++)
+            {
+                v0 = v0 >>> 8;
+                int u = (m_ints[i] >>> (j * 4)) & 0xF;
+                int w = table[u] << 24;
+                v0 |= w;
+            }
+            c.m_ints[i + i] = v0;
+
+            v0 = 0;
+            int upper = m_ints[i] >>> 16;
+            for (int j = 0; j < 4; j++)
+            {
+                v0 = v0 >>> 8;
+                int u = (upper >>> (j * 4)) & 0xF;
+                int w = table[u] << 24;
+                v0 |= w;
+            }
+            c.m_ints[i + i + 1] = v0;
+        }
+        return c;
+    }
+
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof IntArray))
+        {
+            return false;
+        }
+        IntArray other = (IntArray) o;
+        int usedLen = getUsedLength();
+        if (other.getUsedLength() != usedLen)
+        {
+            return false;
+        }
+        for (int i = 0; i < usedLen; i++)
+        {
+            if (m_ints[i] != other.m_ints[i])
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public int hashCode()
+    {
+        int usedLen = getUsedLength();
+        int hash = 1;
+        for (int i = 0; i < usedLen; i++)
+        {
+            hash = hash * 31 + m_ints[i];
+        }
+        return hash;
+    }
+
+    public Object clone()
+    {
+        return new IntArray(Arrays.clone(m_ints));
+    }
+
+    public String toString()
+    {
+        int usedLen = getUsedLength();
+        if (usedLen == 0)
+        {
+            return "0";
+        }
+
+        StringBuffer sb = new StringBuffer(Integer
+            .toBinaryString(m_ints[usedLen - 1]));
+        for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--)
+        {
+            String hexString = Integer.toBinaryString(m_ints[iarrJ]);
+
+            // Add leading zeroes, except for highest significant int
+            for (int i = hexString.length(); i < 8; i++)
+            {
+                hexString = "0" + hexString;
+            }
+            sb.append(hexString);
+        }
+        return sb.toString();
+    }
+}
diff --git a/src/main/java/org/bouncycastle/math/ec/PreCompInfo.java b/src/main/java/org/bouncycastle/math/ec/PreCompInfo.java
new file mode 100644
index 0000000..804dcf7
--- /dev/null
+++ b/src/main/java/org/bouncycastle/math/ec/PreCompInfo.java
@@ -0,0 +1,10 @@
+package org.bouncycastle.math.ec;
+
+/**
+ * Interface for classes storing precomputation data for multiplication
+ * algorithms. Used as a Memento (see GOF patterns) for
+ * <code>WNafMultiplier</code>.
+ */
+interface PreCompInfo
+{
+}
diff --git a/src/main/java/org/bouncycastle/math/ec/SimpleBigDecimal.java b/src/main/java/org/bouncycastle/math/ec/SimpleBigDecimal.java
new file mode 100644
index 0000000..96e666d
--- /dev/null
+++ b/src/main/java/org/bouncycastle/math/ec/SimpleBigDecimal.java
@@ -0,0 +1,253 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Class representing a simple version of a big decimal. A
+ * <code>SimpleBigDecimal</code> is basically a
+ * {@link java.math.BigInteger BigInteger} with a few digits on the right of
+ * the decimal point. The number of (binary) digits on the right of the decimal
+ * point is called the <code>scale</code> of the <code>SimpleBigDecimal</code>.
+ * Unlike in {@link java.math.BigDecimal BigDecimal}, the scale is not adjusted
+ * automatically, but must be set manually. All <code>SimpleBigDecimal</code>s
+ * taking part in the same arithmetic operation must have equal scale. The
+ * result of a multiplication of two <code>SimpleBigDecimal</code>s returns a
+ * <code>SimpleBigDecimal</code> with double scale.
+ */
+class SimpleBigDecimal
+    //extends Number   // not in J2ME - add compatibility class?
+{
+    private static final long serialVersionUID = 1L;
+
+    private final BigInteger bigInt;
+    private final int scale;
+
+    /**
+     * Returns a <code>SimpleBigDecimal</code> representing the same numerical
+     * value as <code>value</code>.
+     * @param value The value of the <code>SimpleBigDecimal</code> to be
+     * created. 
+     * @param scale The scale of the <code>SimpleBigDecimal</code> to be
+     * created. 
+     * @return The such created <code>SimpleBigDecimal</code>.
+     */
+    public static SimpleBigDecimal getInstance(BigInteger value, int scale)
+    {
+        return new SimpleBigDecimal(value.shiftLeft(scale), scale);
+    }
+
+    /**
+     * Constructor for <code>SimpleBigDecimal</code>. The value of the
+     * constructed <code>SimpleBigDecimal</code> equals <code>bigInt / 
+     * 2<sup>scale</sup></code>.
+     * @param bigInt The <code>bigInt</code> value parameter.
+     * @param scale The scale of the constructed <code>SimpleBigDecimal</code>.
+     */
+    public SimpleBigDecimal(BigInteger bigInt, int scale)
+    {
+        if (scale < 0)
+        {
+            throw new IllegalArgumentException("scale may not be negative");
+        }
+
+        this.bigInt = bigInt;
+        this.scale = scale;
+    }
+
+    private SimpleBigDecimal(SimpleBigDecimal limBigDec)
+    {
+        bigInt = limBigDec.bigInt;
+        scale = limBigDec.scale;
+    }
+
+    private void checkScale(SimpleBigDecimal b)
+    {
+        if (scale != b.scale)
+        {
+            throw new IllegalArgumentException("Only SimpleBigDecimal of " +
+                "same scale allowed in arithmetic operations");
+        }
+    }
+
+    public SimpleBigDecimal adjustScale(int newScale)
+    {
+        if (newScale < 0)
+        {
+            throw new IllegalArgumentException("scale may not be negative");
+        }
+
+        if (newScale == scale)
+        {
+            return new SimpleBigDecimal(this);
+        }
+
+        return new SimpleBigDecimal(bigInt.shiftLeft(newScale - scale),
+                newScale);
+    }
+
+    public SimpleBigDecimal add(SimpleBigDecimal b)
+    {
+        checkScale(b);
+        return new SimpleBigDecimal(bigInt.add(b.bigInt), scale);
+    }
+
+    public SimpleBigDecimal add(BigInteger b)
+    {
+        return new SimpleBigDecimal(bigInt.add(b.shiftLeft(scale)), scale);
+    }
+
+    public SimpleBigDecimal negate()
+    {
+        return new SimpleBigDecimal(bigInt.negate(), scale);
+    }
+
+    public SimpleBigDecimal subtract(SimpleBigDecimal b)
+    {
+        return add(b.negate());
+    }
+
+    public SimpleBigDecimal subtract(BigInteger b)
+    {
+        return new SimpleBigDecimal(bigInt.subtract(b.shiftLeft(scale)),
+                scale);
+    }
+
+    public SimpleBigDecimal multiply(SimpleBigDecimal b)
+    {
+        checkScale(b);
+        return new SimpleBigDecimal(bigInt.multiply(b.bigInt), scale + scale);
+    }
+
+    public SimpleBigDecimal multiply(BigInteger b)
+    {
+        return new SimpleBigDecimal(bigInt.multiply(b), scale);
+    }
+
+    public SimpleBigDecimal divide(SimpleBigDecimal b)
+    {
+        checkScale(b);
+        BigInteger dividend = bigInt.shiftLeft(scale);
+        return new SimpleBigDecimal(dividend.divide(b.bigInt), scale);
+    }
+
+    public SimpleBigDecimal divide(BigInteger b)
+    {
+        return new SimpleBigDecimal(bigInt.divide(b), scale);
+    }
+
+    public SimpleBigDecimal shiftLeft(int n)
+    {
+        return new SimpleBigDecimal(bigInt.shiftLeft(n), scale);
+    }
+
+    public int compareTo(SimpleBigDecimal val)
+    {
+        checkScale(val);
+        return bigInt.compareTo(val.bigInt);
+    }
+
+    public int compareTo(BigInteger val)
+    {
+        return bigInt.compareTo(val.shiftLeft(scale));
+    }
+
+    public BigInteger floor()
+    {
+        return bigInt.shiftRight(scale);
+    }
+
+    public BigInteger round()
+    {
+        SimpleBigDecimal oneHalf = new SimpleBigDecimal(ECConstants.ONE, 1);
+        return add(oneHalf.adjustScale(scale)).floor();
+    }
+
+    public int intValue()
+    {
+        return floor().intValue();
+    }
+    
+    public long longValue()
+    {
+        return floor().longValue();
+    }
+          /* NON-J2ME compliant.
+    public double doubleValue()
+    {
+        return Double.valueOf(toString()).doubleValue();
+    }
+
+    public float floatValue()
+    {
+        return Float.valueOf(toString()).floatValue();
+    }
+       */
+    public int getScale()
+    {
+        return scale;
+    }
+
+    public String toString()
+    {
+        if (scale == 0)
+        {
+            return bigInt.toString();
+        }
+
+        BigInteger floorBigInt = floor();
+        
+        BigInteger fract = bigInt.subtract(floorBigInt.shiftLeft(scale));
+        if (bigInt.signum() == -1)
+        {
+            fract = ECConstants.ONE.shiftLeft(scale).subtract(fract);
+        }
+
+        if ((floorBigInt.signum() == -1) && (!(fract.equals(ECConstants.ZERO))))
+        {
+            floorBigInt = floorBigInt.add(ECConstants.ONE);
+        }
+        String leftOfPoint = floorBigInt.toString();
+
+        char[] fractCharArr = new char[scale];
+        String fractStr = fract.toString(2);
+        int fractLen = fractStr.length();
+        int zeroes = scale - fractLen;
+        for (int i = 0; i < zeroes; i++)
+        {
+            fractCharArr[i] = '0';
+        }
+        for (int j = 0; j < fractLen; j++)
+        {
+            fractCharArr[zeroes + j] = fractStr.charAt(j);
+        }
+        String rightOfPoint = new String(fractCharArr);
+
+        StringBuffer sb = new StringBuffer(leftOfPoint);
+        sb.append(".");
+        sb.append(rightOfPoint);
+
+        return sb.toString();
+    }
+
+    public boolean equals(Object o)
+    {
+        if (this == o)
+        {
+            return true;
+        }
+
+        if (!(o instanceof SimpleBigDecimal))
+        {
+            return false;
+        }
+
+        SimpleBigDecimal other = (SimpleBigDecimal)o;
+        return ((bigInt.equals(other.bigInt)) && (scale == other.scale));
+    }
+
+    public int hashCode()
+    {
+        return bigInt.hashCode() ^ scale;
+    }
+
+}
diff --git a/src/main/java/org/bouncycastle/math/ec/Tnaf.java b/src/main/java/org/bouncycastle/math/ec/Tnaf.java
new file mode 100644
index 0000000..af4355f
--- /dev/null
+++ b/src/main/java/org/bouncycastle/math/ec/Tnaf.java
@@ -0,0 +1,844 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Class holding methods for point multiplication based on the window
+ * &tau;-adic nonadjacent form (WTNAF). The algorithms are based on the
+ * paper "Improved Algorithms for Arithmetic on Anomalous Binary Curves"
+ * by Jerome A. Solinas. The paper first appeared in the Proceedings of
+ * Crypto 1997.
+ */
+class Tnaf
+{
+    private static final BigInteger MINUS_ONE = ECConstants.ONE.negate();
+    private static final BigInteger MINUS_TWO = ECConstants.TWO.negate();
+    private static final BigInteger MINUS_THREE = ECConstants.THREE.negate();
+
+    /**
+     * The window width of WTNAF. The standard value of 4 is slightly less
+     * than optimal for running time, but keeps space requirements for
+     * precomputation low. For typical curves, a value of 5 or 6 results in
+     * a better running time. When changing this value, the
+     * <code>&alpha;<sub>u</sub></code>'s must be computed differently, see
+     * e.g. "Guide to Elliptic Curve Cryptography", Darrel Hankerson,
+     * Alfred Menezes, Scott Vanstone, Springer-Verlag New York Inc., 2004,
+     * p. 121-122
+     */
+    public static final byte WIDTH = 4;
+
+    /**
+     * 2<sup>4</sup>
+     */
+    public static final byte POW_2_WIDTH = 16;
+
+    /**
+     * The <code>&alpha;<sub>u</sub></code>'s for <code>a=0</code> as an array
+     * of <code>ZTauElement</code>s.
+     */
+    public static final ZTauElement[] alpha0 = {
+        null,
+        new ZTauElement(ECConstants.ONE, ECConstants.ZERO), null,
+        new ZTauElement(MINUS_THREE, MINUS_ONE), null,
+        new ZTauElement(MINUS_ONE, MINUS_ONE), null,
+        new ZTauElement(ECConstants.ONE, MINUS_ONE), null
+    };
+
+    /**
+     * The <code>&alpha;<sub>u</sub></code>'s for <code>a=0</code> as an array
+     * of TNAFs.
+     */
+    public static final byte[][] alpha0Tnaf = {
+        null, {1}, null, {-1, 0, 1}, null, {1, 0, 1}, null, {-1, 0, 0, 1}
+    };
+
+    /**
+     * The <code>&alpha;<sub>u</sub></code>'s for <code>a=1</code> as an array
+     * of <code>ZTauElement</code>s.
+     */
+    public static final ZTauElement[] alpha1 = {null,
+        new ZTauElement(ECConstants.ONE, ECConstants.ZERO), null,
+        new ZTauElement(MINUS_THREE, ECConstants.ONE), null,
+        new ZTauElement(MINUS_ONE, ECConstants.ONE), null,
+        new ZTauElement(ECConstants.ONE, ECConstants.ONE), null
+    };
+
+    /**
+     * The <code>&alpha;<sub>u</sub></code>'s for <code>a=1</code> as an array
+     * of TNAFs.
+     */
+    public static final byte[][] alpha1Tnaf = {
+        null, {1}, null, {-1, 0, 1}, null, {1, 0, 1}, null, {-1, 0, 0, -1}
+    };
+
+    /**
+     * Computes the norm of an element <code>&lambda;</code> of
+     * <code><b>Z</b>[&tau;]</code>.
+     * @param mu The parameter <code>&mu;</code> of the elliptic curve.
+     * @param lambda The element <code>&lambda;</code> of
+     * <code><b>Z</b>[&tau;]</code>.
+     * @return The norm of <code>&lambda;</code>.
+     */
+    public static BigInteger norm(final byte mu, ZTauElement lambda)
+    {
+        BigInteger norm;
+
+        // s1 = u^2
+        BigInteger s1 = lambda.u.multiply(lambda.u);
+
+        // s2 = u * v
+        BigInteger s2 = lambda.u.multiply(lambda.v);
+
+        // s3 = 2 * v^2
+        BigInteger s3 = lambda.v.multiply(lambda.v).shiftLeft(1);
+
+        if (mu == 1)
+        {
+            norm = s1.add(s2).add(s3);
+        }
+        else if (mu == -1)
+        {
+            norm = s1.subtract(s2).add(s3);
+        }
+        else
+        {
+            throw new IllegalArgumentException("mu must be 1 or -1");
+        }
+
+        return norm;
+    }
+
+    /**
+     * Computes the norm of an element <code>&lambda;</code> of
+     * <code><b>R</b>[&tau;]</code>, where <code>&lambda; = u + v&tau;</code>
+     * and <code>u</code> and <code>u</code> are real numbers (elements of
+     * <code><b>R</b></code>). 
+     * @param mu The parameter <code>&mu;</code> of the elliptic curve.
+     * @param u The real part of the element <code>&lambda;</code> of
+     * <code><b>R</b>[&tau;]</code>.
+     * @param v The <code>&tau;</code>-adic part of the element
+     * <code>&lambda;</code> of <code><b>R</b>[&tau;]</code>.
+     * @return The norm of <code>&lambda;</code>.
+     */
+    public static SimpleBigDecimal norm(final byte mu, SimpleBigDecimal u,
+            SimpleBigDecimal v)
+    {
+        SimpleBigDecimal norm;
+
+        // s1 = u^2
+        SimpleBigDecimal s1 = u.multiply(u);
+
+        // s2 = u * v
+        SimpleBigDecimal s2 = u.multiply(v);
+
+        // s3 = 2 * v^2
+        SimpleBigDecimal s3 = v.multiply(v).shiftLeft(1);
+
+        if (mu == 1)
+        {
+            norm = s1.add(s2).add(s3);
+        }
+        else if (mu == -1)
+        {
+            norm = s1.subtract(s2).add(s3);
+        }
+        else
+        {
+            throw new IllegalArgumentException("mu must be 1 or -1");
+        }
+
+        return norm;
+    }
+
+    /**
+     * Rounds an element <code>&lambda;</code> of <code><b>R</b>[&tau;]</code>
+     * to an element of <code><b>Z</b>[&tau;]</code>, such that their difference
+     * has minimal norm. <code>&lambda;</code> is given as
+     * <code>&lambda; = &lambda;<sub>0</sub> + &lambda;<sub>1</sub>&tau;</code>.
+     * @param lambda0 The component <code>&lambda;<sub>0</sub></code>.
+     * @param lambda1 The component <code>&lambda;<sub>1</sub></code>.
+     * @param mu The parameter <code>&mu;</code> of the elliptic curve. Must
+     * equal 1 or -1.
+     * @return The rounded element of <code><b>Z</b>[&tau;]</code>.
+     * @throws IllegalArgumentException if <code>lambda0</code> and
+     * <code>lambda1</code> do not have same scale.
+     */
+    public static ZTauElement round(SimpleBigDecimal lambda0,
+            SimpleBigDecimal lambda1, byte mu)
+    {
+        int scale = lambda0.getScale();
+        if (lambda1.getScale() != scale)
+        {
+            throw new IllegalArgumentException("lambda0 and lambda1 do not " +
+                    "have same scale");
+        }
+
+        if (!((mu == 1) || (mu == -1)))
+        {
+            throw new IllegalArgumentException("mu must be 1 or -1");
+        }
+
+        BigInteger f0 = lambda0.round();
+        BigInteger f1 = lambda1.round();
+
+        SimpleBigDecimal eta0 = lambda0.subtract(f0);
+        SimpleBigDecimal eta1 = lambda1.subtract(f1);
+
+        // eta = 2*eta0 + mu*eta1
+        SimpleBigDecimal eta = eta0.add(eta0);
+        if (mu == 1)
+        {
+            eta = eta.add(eta1);
+        }
+        else
+        {
+            // mu == -1
+            eta = eta.subtract(eta1);
+        }
+
+        // check1 = eta0 - 3*mu*eta1
+        // check2 = eta0 + 4*mu*eta1
+        SimpleBigDecimal threeEta1 = eta1.add(eta1).add(eta1);
+        SimpleBigDecimal fourEta1 = threeEta1.add(eta1);
+        SimpleBigDecimal check1;
+        SimpleBigDecimal check2;
+        if (mu == 1)
+        {
+            check1 = eta0.subtract(threeEta1);
+            check2 = eta0.add(fourEta1);
+        }
+        else
+        {
+            // mu == -1
+            check1 = eta0.add(threeEta1);
+            check2 = eta0.subtract(fourEta1);
+        }
+
+        byte h0 = 0;
+        byte h1 = 0;
+
+        // if eta >= 1
+        if (eta.compareTo(ECConstants.ONE) >= 0)
+        {
+            if (check1.compareTo(MINUS_ONE) < 0)
+            {
+                h1 = mu;
+            }
+            else
+            {
+                h0 = 1;
+            }
+        }
+        else
+        {
+            // eta < 1
+            if (check2.compareTo(ECConstants.TWO) >= 0)
+            {
+                h1 = mu;
+            }
+        }
+
+        // if eta < -1
+        if (eta.compareTo(MINUS_ONE) < 0)
+        {
+            if (check1.compareTo(ECConstants.ONE) >= 0)
+            {
+                h1 = (byte)-mu;
+            }
+            else
+            {
+                h0 = -1;
+            }
+        }
+        else
+        {
+            // eta >= -1
+            if (check2.compareTo(MINUS_TWO) < 0)
+            {
+                h1 = (byte)-mu;
+            }
+        }
+
+        BigInteger q0 = f0.add(BigInteger.valueOf(h0));
+        BigInteger q1 = f1.add(BigInteger.valueOf(h1));
+        return new ZTauElement(q0, q1);
+    }
+
+    /**
+     * Approximate division by <code>n</code>. For an integer
+     * <code>k</code>, the value <code>&lambda; = s k / n</code> is
+     * computed to <code>c</code> bits of accuracy.
+     * @param k The parameter <code>k</code>.
+     * @param s The curve parameter <code>s<sub>0</sub></code> or
+     * <code>s<sub>1</sub></code>.
+     * @param vm The Lucas Sequence element <code>V<sub>m</sub></code>.
+     * @param a The parameter <code>a</code> of the elliptic curve.
+     * @param m The bit length of the finite field
+     * <code><b>F</b><sub>m</sub></code>.
+     * @param c The number of bits of accuracy, i.e. the scale of the returned
+     * <code>SimpleBigDecimal</code>.
+     * @return The value <code>&lambda; = s k / n</code> computed to
+     * <code>c</code> bits of accuracy.
+     */
+    public static SimpleBigDecimal approximateDivisionByN(BigInteger k,
+            BigInteger s, BigInteger vm, byte a, int m, int c)
+    {
+        int _k = (m + 5)/2 + c;
+        BigInteger ns = k.shiftRight(m - _k - 2 + a);
+
+        BigInteger gs = s.multiply(ns);
+
+        BigInteger hs = gs.shiftRight(m);
+
+        BigInteger js = vm.multiply(hs);
+
+        BigInteger gsPlusJs = gs.add(js);
+        BigInteger ls = gsPlusJs.shiftRight(_k-c);
+        if (gsPlusJs.testBit(_k-c-1))
+        {
+            // round up
+            ls = ls.add(ECConstants.ONE);
+        }
+
+        return new SimpleBigDecimal(ls, c);
+    }
+
+    /**
+     * Computes the <code>&tau;</code>-adic NAF (non-adjacent form) of an
+     * element <code>&lambda;</code> of <code><b>Z</b>[&tau;]</code>.
+     * @param mu The parameter <code>&mu;</code> of the elliptic curve.
+     * @param lambda The element <code>&lambda;</code> of
+     * <code><b>Z</b>[&tau;]</code>.
+     * @return The <code>&tau;</code>-adic NAF of <code>&lambda;</code>.
+     */
+    public static byte[] tauAdicNaf(byte mu, ZTauElement lambda)
+    {
+        if (!((mu == 1) || (mu == -1)))
+        {
+            throw new IllegalArgumentException("mu must be 1 or -1");
+        }
+        
+        BigInteger norm = norm(mu, lambda);
+
+        // Ceiling of log2 of the norm 
+        int log2Norm = norm.bitLength();
+
+        // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52
+        int maxLength = log2Norm > 30 ? log2Norm + 4 : 34;
+
+        // The array holding the TNAF
+        byte[] u = new byte[maxLength];
+        int i = 0;
+
+        // The actual length of the TNAF
+        int length = 0;
+
+        BigInteger r0 = lambda.u;
+        BigInteger r1 = lambda.v;
+
+        while(!((r0.equals(ECConstants.ZERO)) && (r1.equals(ECConstants.ZERO))))
+        {
+            // If r0 is odd
+            if (r0.testBit(0))
+            {
+                u[i] = (byte) ECConstants.TWO.subtract((r0.subtract(r1.shiftLeft(1))).mod(ECConstants.FOUR)).intValue();
+
+                // r0 = r0 - u[i]
+                if (u[i] == 1)
+                {
+                    r0 = r0.clearBit(0);
+                }
+                else
+                {
+                    // u[i] == -1
+                    r0 = r0.add(ECConstants.ONE);
+                }
+                length = i;
+            }
+            else
+            {
+                u[i] = 0;
+            }
+
+            BigInteger t = r0;
+            BigInteger s = r0.shiftRight(1);
+            if (mu == 1)
+            {
+                r0 = r1.add(s);
+            }
+            else
+            {
+                // mu == -1
+                r0 = r1.subtract(s);
+            }
+
+            r1 = t.shiftRight(1).negate();
+            i++;
+        }
+
+        length++;
+
+        // Reduce the TNAF array to its actual length
+        byte[] tnaf = new byte[length];
+        System.arraycopy(u, 0, tnaf, 0, length);
+        return tnaf;
+    }
+
+    /**
+     * Applies the operation <code>&tau;()</code> to an
+     * <code>ECPoint.F2m</code>. 
+     * @param p The ECPoint.F2m to which <code>&tau;()</code> is applied.
+     * @return <code>&tau;(p)</code>
+     */
+    public static ECPoint.F2m tau(ECPoint.F2m p)
+    {
+        if (p.isInfinity())
+        {
+            return p;
+        }
+
+        ECFieldElement x = p.getX();
+        ECFieldElement y = p.getY();
+
+        return new ECPoint.F2m(p.getCurve(), x.square(), y.square(), p.isCompressed());
+    }
+
+    /**
+     * Returns the parameter <code>&mu;</code> of the elliptic curve.
+     * @param curve The elliptic curve from which to obtain <code>&mu;</code>.
+     * The curve must be a Koblitz curve, i.e. <code>a</code> equals
+     * <code>0</code> or <code>1</code> and <code>b</code> equals
+     * <code>1</code>. 
+     * @return <code>&mu;</code> of the elliptic curve.
+     * @throws IllegalArgumentException if the given ECCurve is not a Koblitz
+     * curve.
+     */
+    public static byte getMu(ECCurve.F2m curve)
+    {
+        BigInteger a = curve.getA().toBigInteger();
+        byte mu;
+
+        if (a.equals(ECConstants.ZERO))
+        {
+            mu = -1;
+        }
+        else if (a.equals(ECConstants.ONE))
+        {
+            mu = 1;
+        }
+        else
+        {
+            throw new IllegalArgumentException("No Koblitz curve (ABC), " +
+                    "TNAF multiplication not possible");
+        }
+        return mu;
+    }
+
+    /**
+     * Calculates the Lucas Sequence elements <code>U<sub>k-1</sub></code> and
+     * <code>U<sub>k</sub></code> or <code>V<sub>k-1</sub></code> and
+     * <code>V<sub>k</sub></code>.
+     * @param mu The parameter <code>&mu;</code> of the elliptic curve.
+     * @param k The index of the second element of the Lucas Sequence to be
+     * returned.
+     * @param doV If set to true, computes <code>V<sub>k-1</sub></code> and
+     * <code>V<sub>k</sub></code>, otherwise <code>U<sub>k-1</sub></code> and
+     * <code>U<sub>k</sub></code>.
+     * @return An array with 2 elements, containing <code>U<sub>k-1</sub></code>
+     * and <code>U<sub>k</sub></code> or <code>V<sub>k-1</sub></code>
+     * and <code>V<sub>k</sub></code>.
+     */
+    public static BigInteger[] getLucas(byte mu, int k, boolean doV)
+    {
+        if (!((mu == 1) || (mu == -1)))
+        {
+            throw new IllegalArgumentException("mu must be 1 or -1");
+        }
+
+        BigInteger u0;
+        BigInteger u1;
+        BigInteger u2;
+
+        if (doV)
+        {
+            u0 = ECConstants.TWO;
+            u1 = BigInteger.valueOf(mu);
+        }
+        else
+        {
+            u0 = ECConstants.ZERO;
+            u1 = ECConstants.ONE;
+        }
+
+        for (int i = 1; i < k; i++)
+        {
+            // u2 = mu*u1 - 2*u0;
+            BigInteger s = null;
+            if (mu == 1)
+            {
+                s = u1;
+            }
+            else
+            {
+                // mu == -1
+                s = u1.negate();
+            }
+            
+            u2 = s.subtract(u0.shiftLeft(1));
+            u0 = u1;
+            u1 = u2;
+//            System.out.println(i + ": " + u2);
+//            System.out.println();
+        }
+
+        BigInteger[] retVal = {u0, u1};
+        return retVal;
+    }
+
+    /**
+     * Computes the auxiliary value <code>t<sub>w</sub></code>. If the width is
+     * 4, then for <code>mu = 1</code>, <code>t<sub>w</sub> = 6</code> and for
+     * <code>mu = -1</code>, <code>t<sub>w</sub> = 10</code> 
+     * @param mu The parameter <code>&mu;</code> of the elliptic curve.
+     * @param w The window width of the WTNAF.
+     * @return the auxiliary value <code>t<sub>w</sub></code>
+     */
+    public static BigInteger getTw(byte mu, int w)
+    {
+        if (w == 4)
+        {
+            if (mu == 1)
+            {
+                return BigInteger.valueOf(6);
+            }
+            else
+            {
+                // mu == -1
+                return BigInteger.valueOf(10);
+            }
+        }
+        else
+        {
+            // For w <> 4, the values must be computed
+            BigInteger[] us = getLucas(mu, w, false);
+            BigInteger twoToW = ECConstants.ZERO.setBit(w);
+            BigInteger u1invert = us[1].modInverse(twoToW);
+            BigInteger tw;
+            tw = ECConstants.TWO.multiply(us[0]).multiply(u1invert).mod(twoToW);
+//            System.out.println("mu = " + mu);
+//            System.out.println("tw = " + tw);
+            return tw;
+        }
+    }
+
+    /**
+     * Computes the auxiliary values <code>s<sub>0</sub></code> and
+     * <code>s<sub>1</sub></code> used for partial modular reduction. 
+     * @param curve The elliptic curve for which to compute
+     * <code>s<sub>0</sub></code> and <code>s<sub>1</sub></code>.
+     * @throws IllegalArgumentException if <code>curve</code> is not a
+     * Koblitz curve (Anomalous Binary Curve, ABC).
+     */
+    public static BigInteger[] getSi(ECCurve.F2m curve)
+    {
+        if (!curve.isKoblitz())
+        {
+            throw new IllegalArgumentException("si is defined for Koblitz curves only");
+        }
+
+        int m = curve.getM();
+        int a = curve.getA().toBigInteger().intValue();
+        byte mu = curve.getMu();
+        int h = curve.getH().intValue();
+        int index = m + 3 - a;
+        BigInteger[] ui = getLucas(mu, index, false);
+
+        BigInteger dividend0;
+        BigInteger dividend1;
+        if (mu == 1)
+        {
+            dividend0 = ECConstants.ONE.subtract(ui[1]);
+            dividend1 = ECConstants.ONE.subtract(ui[0]);
+        }
+        else if (mu == -1)
+        {
+            dividend0 = ECConstants.ONE.add(ui[1]);
+            dividend1 = ECConstants.ONE.add(ui[0]);
+        }
+        else
+        {
+            throw new IllegalArgumentException("mu must be 1 or -1");
+        }
+
+        BigInteger[] si = new BigInteger[2];
+
+        if (h == 2)
+        {
+            si[0] = dividend0.shiftRight(1);
+            si[1] = dividend1.shiftRight(1).negate();
+        }
+        else if (h == 4)
+        {
+            si[0] = dividend0.shiftRight(2);
+            si[1] = dividend1.shiftRight(2).negate();
+        }
+        else
+        {
+            throw new IllegalArgumentException("h (Cofactor) must be 2 or 4");
+        }
+
+        return si;
+    }
+
+    /**
+     * Partial modular reduction modulo
+     * <code>(&tau;<sup>m</sup> - 1)/(&tau; - 1)</code>.
+     * @param k The integer to be reduced.
+     * @param m The bitlength of the underlying finite field.
+     * @param a The parameter <code>a</code> of the elliptic curve.
+     * @param s The auxiliary values <code>s<sub>0</sub></code> and
+     * <code>s<sub>1</sub></code>.
+     * @param mu The parameter &mu; of the elliptic curve.
+     * @param c The precision (number of bits of accuracy) of the partial
+     * modular reduction.
+     * @return <code>&rho; := k partmod (&tau;<sup>m</sup> - 1)/(&tau; - 1)</code>
+     */
+    public static ZTauElement partModReduction(BigInteger k, int m, byte a,
+            BigInteger[] s, byte mu, byte c)
+    {
+        // d0 = s[0] + mu*s[1]; mu is either 1 or -1
+        BigInteger d0;
+        if (mu == 1)
+        {
+            d0 = s[0].add(s[1]);
+        }
+        else
+        {
+            d0 = s[0].subtract(s[1]);
+        }
+
+        BigInteger[] v = getLucas(mu, m, true);
+        BigInteger vm = v[1];
+
+        SimpleBigDecimal lambda0 = approximateDivisionByN(
+                k, s[0], vm, a, m, c);
+        
+        SimpleBigDecimal lambda1 = approximateDivisionByN(
+                k, s[1], vm, a, m, c);
+
+        ZTauElement q = round(lambda0, lambda1, mu);
+
+        // r0 = n - d0*q0 - 2*s1*q1
+        BigInteger r0 = k.subtract(d0.multiply(q.u)).subtract(
+                BigInteger.valueOf(2).multiply(s[1]).multiply(q.v));
+
+        // r1 = s1*q0 - s0*q1
+        BigInteger r1 = s[1].multiply(q.u).subtract(s[0].multiply(q.v));
+        
+        return new ZTauElement(r0, r1);
+    }
+
+    /**
+     * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m}
+     * by a <code>BigInteger</code> using the reduced <code>&tau;</code>-adic
+     * NAF (RTNAF) method.
+     * @param p The ECPoint.F2m to multiply.
+     * @param k The <code>BigInteger</code> by which to multiply <code>p</code>.
+     * @return <code>k * p</code>
+     */
+    public static ECPoint.F2m multiplyRTnaf(ECPoint.F2m p, BigInteger k)
+    {
+        ECCurve.F2m curve = (ECCurve.F2m) p.getCurve();
+        int m = curve.getM();
+        byte a = (byte) curve.getA().toBigInteger().intValue();
+        byte mu = curve.getMu();
+        BigInteger[] s = curve.getSi();
+        ZTauElement rho = partModReduction(k, m, a, s, mu, (byte)10);
+
+        return multiplyTnaf(p, rho);
+    }
+
+    /**
+     * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m}
+     * by an element <code>&lambda;</code> of <code><b>Z</b>[&tau;]</code>
+     * using the <code>&tau;</code>-adic NAF (TNAF) method.
+     * @param p The ECPoint.F2m to multiply.
+     * @param lambda The element <code>&lambda;</code> of
+     * <code><b>Z</b>[&tau;]</code>.
+     * @return <code>&lambda; * p</code>
+     */
+    public static ECPoint.F2m multiplyTnaf(ECPoint.F2m p, ZTauElement lambda)
+    {
+        ECCurve.F2m curve = (ECCurve.F2m)p.getCurve();
+        byte mu = curve.getMu();
+        byte[] u = tauAdicNaf(mu, lambda);
+
+        ECPoint.F2m q = multiplyFromTnaf(p, u);
+
+        return q;
+    }
+
+    /**
+    * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m}
+    * by an element <code>&lambda;</code> of <code><b>Z</b>[&tau;]</code>
+    * using the <code>&tau;</code>-adic NAF (TNAF) method, given the TNAF
+    * of <code>&lambda;</code>.
+    * @param p The ECPoint.F2m to multiply.
+    * @param u The the TNAF of <code>&lambda;</code>..
+    * @return <code>&lambda; * p</code>
+    */
+    public static ECPoint.F2m multiplyFromTnaf(ECPoint.F2m p, byte[] u)
+    {
+        ECCurve.F2m curve = (ECCurve.F2m)p.getCurve();
+        ECPoint.F2m q = (ECPoint.F2m) curve.getInfinity();
+        for (int i = u.length - 1; i >= 0; i--)
+        {
+            q = tau(q);
+            if (u[i] == 1)
+            {
+                q = (ECPoint.F2m)q.addSimple(p);
+            }
+            else if (u[i] == -1)
+            {
+                q = (ECPoint.F2m)q.subtractSimple(p);
+            }
+        }
+        return q;
+    }
+
+    /**
+     * Computes the <code>[&tau;]</code>-adic window NAF of an element
+     * <code>&lambda;</code> of <code><b>Z</b>[&tau;]</code>.
+     * @param mu The parameter &mu; of the elliptic curve.
+     * @param lambda The element <code>&lambda;</code> of
+     * <code><b>Z</b>[&tau;]</code> of which to compute the
+     * <code>[&tau;]</code>-adic NAF.
+     * @param width The window width of the resulting WNAF.
+     * @param pow2w 2<sup>width</sup>.
+     * @param tw The auxiliary value <code>t<sub>w</sub></code>.
+     * @param alpha The <code>&alpha;<sub>u</sub></code>'s for the window width.
+     * @return The <code>[&tau;]</code>-adic window NAF of
+     * <code>&lambda;</code>.
+     */
+    public static byte[] tauAdicWNaf(byte mu, ZTauElement lambda,
+            byte width, BigInteger pow2w, BigInteger tw, ZTauElement[] alpha)
+    {
+        if (!((mu == 1) || (mu == -1)))
+        {
+            throw new IllegalArgumentException("mu must be 1 or -1");
+        }
+
+        BigInteger norm = norm(mu, lambda);
+
+        // Ceiling of log2 of the norm 
+        int log2Norm = norm.bitLength();
+
+        // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52
+        int maxLength = log2Norm > 30 ? log2Norm + 4 + width : 34 + width;
+
+        // The array holding the TNAF
+        byte[] u = new byte[maxLength];
+
+        // 2^(width - 1)
+        BigInteger pow2wMin1 = pow2w.shiftRight(1);
+
+        // Split lambda into two BigIntegers to simplify calculations
+        BigInteger r0 = lambda.u;
+        BigInteger r1 = lambda.v;
+        int i = 0;
+
+        // while lambda <> (0, 0)
+        while (!((r0.equals(ECConstants.ZERO))&&(r1.equals(ECConstants.ZERO))))
+        {
+            // if r0 is odd
+            if (r0.testBit(0))
+            {
+                // uUnMod = r0 + r1*tw mod 2^width
+                BigInteger uUnMod
+                    = r0.add(r1.multiply(tw)).mod(pow2w);
+                
+                byte uLocal;
+                // if uUnMod >= 2^(width - 1)
+                if (uUnMod.compareTo(pow2wMin1) >= 0)
+                {
+                    uLocal = (byte) uUnMod.subtract(pow2w).intValue();
+                }
+                else
+                {
+                    uLocal = (byte) uUnMod.intValue();
+                }
+                // uLocal is now in [-2^(width-1), 2^(width-1)-1]
+
+                u[i] = uLocal;
+                boolean s = true;
+                if (uLocal < 0)
+                {
+                    s = false;
+                    uLocal = (byte)-uLocal;
+                }
+                // uLocal is now >= 0
+
+                if (s)
+                {
+                    r0 = r0.subtract(alpha[uLocal].u);
+                    r1 = r1.subtract(alpha[uLocal].v);
+                }
+                else
+                {
+                    r0 = r0.add(alpha[uLocal].u);
+                    r1 = r1.add(alpha[uLocal].v);
+                }
+            }
+            else
+            {
+                u[i] = 0;
+            }
+
+            BigInteger t = r0;
+
+            if (mu == 1)
+            {
+                r0 = r1.add(r0.shiftRight(1));
+            }
+            else
+            {
+                // mu == -1
+                r0 = r1.subtract(r0.shiftRight(1));
+            }
+            r1 = t.shiftRight(1).negate();
+            i++;
+        }
+        return u;
+    }
+
+    /**
+     * Does the precomputation for WTNAF multiplication.
+     * @param p The <code>ECPoint</code> for which to do the precomputation.
+     * @param a The parameter <code>a</code> of the elliptic curve.
+     * @return The precomputation array for <code>p</code>. 
+     */
+    public static ECPoint.F2m[] getPreComp(ECPoint.F2m p, byte a)
+    {
+        ECPoint.F2m[] pu;
+        pu = new ECPoint.F2m[16];
+        pu[1] = p;
+        byte[][] alphaTnaf;
+        if (a == 0)
+        {
+            alphaTnaf = Tnaf.alpha0Tnaf;
+        }
+        else
+        {
+            // a == 1
+            alphaTnaf = Tnaf.alpha1Tnaf;
+        }
+
+        int precompLen = alphaTnaf.length;
+        for (int i = 3; i < precompLen; i = i + 2)
+        {
+            pu[i] = Tnaf.multiplyFromTnaf(p, alphaTnaf[i]);
+        }
+        
+        return pu;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/math/ec/ZTauElement.java b/src/main/java/org/bouncycastle/math/ec/ZTauElement.java
new file mode 100644
index 0000000..7402f22
--- /dev/null
+++ b/src/main/java/org/bouncycastle/math/ec/ZTauElement.java
@@ -0,0 +1,37 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Class representing an element of <code><b>Z</b>[&tau;]</code>. Let
+ * <code>&lambda;</code> be an element of <code><b>Z</b>[&tau;]</code>. Then
+ * <code>&lambda;</code> is given as <code>&lambda; = u + v&tau;</code>. The
+ * components <code>u</code> and <code>v</code> may be used directly, there
+ * are no accessor methods.
+ * Immutable class.
+ */
+class ZTauElement
+{
+    /**
+     * The &quot;real&quot; part of <code>&lambda;</code>.
+     */
+    public final BigInteger u;
+
+    /**
+     * The &quot;<code>&tau;</code>-adic&quot; part of <code>&lambda;</code>.
+     */
+    public final BigInteger v;
+
+    /**
+     * Constructor for an element <code>&lambda;</code> of
+     * <code><b>Z</b>[&tau;]</code>.
+     * @param u The &quot;real&quot; part of <code>&lambda;</code>.
+     * @param v The &quot;<code>&tau;</code>-adic&quot; part of
+     * <code>&lambda;</code>.
+     */
+    public ZTauElement(BigInteger u, BigInteger v)
+    {
+        this.u = u;
+        this.v = v;
+    }
+}