Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/quite/humla-spongycastle.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/main/java/org')
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java182
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java154
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/ASN1Integer.java136
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java425
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/DERBoolean.java173
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/DEREnumerated.java161
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/DERInteger.java150
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java440
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/cms/Attribute.java12
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java17
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/ess/ContentHints.java20
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/oiw/ElGamalParameter.java16
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java67
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java13
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/x500/style/AbstractX500NameStyle.java188
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java162
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java153
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java2
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java25
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java5
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java4
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java18
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java23
-rw-r--r--core/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java24
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/agreement/kdf/DHKEKGenerator.java4
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/ec/CustomNamedCurves.java190
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/ec/ECElGamalEncryptor.java7
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/ec/ECFixedTransform.java7
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/ec/ECNewPublicKeyTransform.java7
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/ec/ECNewRandomnessTransform.java7
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/engines/IDEAEngine.java14
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java7
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java8
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/io/CipherIOException.java26
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java6
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java39
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/io/InvalidCipherTextIOException.java13
-rwxr-xr-xcore/src/main/java/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java7
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/macs/SipHash.java106
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java22
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java39
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java49
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java23
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java18
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java2
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/prng/drbg/CTRSP800DRBG.java10
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java10
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/prng/drbg/HMacSP800DRBG.java10
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/prng/drbg/HashSP800DRBG.java25
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/prng/drbg/SP80090DRBG.java7
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/signers/DSADigestSigner.java10
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/signers/DSTU4145Signer.java7
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java9
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/signers/ECGOST3410Signer.java315
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/signers/ECNRSigner.java2
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java2
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/util/Pack.java9
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java3
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java3
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java143
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/ECCurve.java38
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java79
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/ECPoint.java82
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/ECPointMap.java6
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/FixedPointCombMultiplier.java8
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/GLVMultiplier.java42
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/Mod.java29
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/Nat.java617
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/ScaleXPointMap.java16
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/ScaleYPointMap.java16
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/WNafUtil.java112
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519.java105
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519Field.java (renamed from core/src/main/java/org/bouncycastle/math/ec/custom/sec/Curve25519Field.java)102
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519FieldElement.java234
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519Point.java304
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat192.java714
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat224.java1183
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat256.java608
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat384.java44
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat512.java6
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Curve.java9
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Field.java71
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1FieldElement.java6
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Point.java41
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Curve.java5
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Field.java151
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1FieldElement.java6
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Point.java35
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Curve.java107
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Field.java177
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1FieldElement.java242
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Point.java314
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Curve.java105
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Field.java297
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1FieldElement.java272
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Point.java323
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Curve.java9
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Field.java71
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1FieldElement.java6
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Point.java41
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Curve.java5
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java184
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1FieldElement.java6
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Point.java35
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Curve.java105
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Field.java294
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1FieldElement.java211
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Point.java324
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Curve.java5
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Field.java31
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1FieldElement.java6
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Point.java4
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/endo/ECEndomorphism.java10
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/endo/GLVEndomorphism.java8
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/endo/GLVTypeBEndomorphism.java58
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/endo/GLVTypeBParameters.java59
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/tools/DiscoverEndomorphisms.java373
-rw-r--r--core/src/main/java/org/bouncycastle/util/Arrays.java38
-rw-r--r--core/src/main/java/org/bouncycastle/util/encoders/Base64Encoder.java28
-rw-r--r--core/src/main/java/org/bouncycastle/util/encoders/HexEncoder.java10
120 files changed, 9550 insertions, 2613 deletions
diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java
index 1360e8b5..1d4f5af0 100644
--- a/core/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java
+++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java
@@ -1,15 +1,187 @@
package org.bouncycastle.asn1;
+import java.io.IOException;
+
+import org.bouncycastle.util.Arrays;
+
public class ASN1Boolean
- extends DERBoolean
+ extends ASN1Primitive
{
- public ASN1Boolean(boolean value)
+ private static final byte[] TRUE_VALUE = new byte[] { (byte)0xff };
+ private static final byte[] FALSE_VALUE = new byte[] { 0 };
+
+ private byte[] value;
+
+ public static final ASN1Boolean FALSE = new ASN1Boolean(false);
+ public static final ASN1Boolean TRUE = new ASN1Boolean(true);
+
+
+ /**
+ * return a boolean from the passed in object.
+ *
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static ASN1Boolean getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof ASN1Boolean)
+ {
+ return (ASN1Boolean)obj;
+ }
+
+ if (obj instanceof byte[])
+ {
+ byte[] enc = (byte[])obj;
+ try
+ {
+ return (ASN1Boolean)fromByteArray(enc);
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("failed to construct boolean from byte[]: " + e.getMessage());
+ }
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return an ASN1Boolean from the passed in boolean.
+ */
+ public static ASN1Boolean getInstance(
+ boolean value)
+ {
+ return (value ? TRUE : FALSE);
+ }
+
+ /**
+ * return an ASN1Boolean from the passed in value.
+ */
+ public static ASN1Boolean getInstance(
+ int value)
+ {
+ return (value != 0 ? TRUE : FALSE);
+ }
+
+ /**
+ * return a Boolean from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception IllegalArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static ASN1Boolean getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ ASN1Primitive o = obj.getObject();
+
+ if (explicit || o instanceof ASN1Boolean)
+ {
+ return getInstance(o);
+ }
+ else
+ {
+ return ASN1Boolean.fromOctetString(((ASN1OctetString)o).getOctets());
+ }
+ }
+
+ ASN1Boolean(
+ byte[] value)
+ {
+ if (value.length != 1)
+ {
+ throw new IllegalArgumentException("byte value should have 1 byte in it");
+ }
+
+ if (value[0] == 0)
+ {
+ this.value = FALSE_VALUE;
+ }
+ else if ((value[0] & 0xff) == 0xff)
+ {
+ this.value = TRUE_VALUE;
+ }
+ else
+ {
+ this.value = Arrays.clone(value);
+ }
+ }
+
+ /**
+ * @deprecated use getInstance(boolean) method.
+ * @param value true or false.
+ */
+ public ASN1Boolean(
+ boolean value)
{
- super(value);
+ this.value = (value) ? TRUE_VALUE : FALSE_VALUE;
}
- ASN1Boolean(byte[] value)
+ public boolean isTrue()
{
- super(value);
+ return (value[0] != 0);
+ }
+
+ boolean isConstructed()
+ {
+ return false;
+ }
+
+ int encodedLength()
+ {
+ return 3;
+ }
+
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ out.writeEncoded(BERTags.BOOLEAN, value);
+ }
+
+ protected boolean asn1Equals(
+ ASN1Primitive o)
+ {
+ if (o instanceof ASN1Boolean)
+ {
+ return (value[0] == ((ASN1Boolean)o).value[0]);
+ }
+
+ return false;
+ }
+
+ public int hashCode()
+ {
+ return value[0];
+ }
+
+
+ public String toString()
+ {
+ return (value[0] != 0) ? "TRUE" : "FALSE";
+ }
+
+ static ASN1Boolean fromOctetString(byte[] value)
+ {
+ if (value.length != 1)
+ {
+ throw new IllegalArgumentException("BOOLEAN value should have 1 byte in it");
+ }
+
+ if (value[0] == 0)
+ {
+ return FALSE;
+ }
+ else if ((value[0] & 0xff) == 0xff)
+ {
+ return TRUE;
+ }
+ else
+ {
+ return new ASN1Boolean(value);
+ }
}
}
diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java
index d93fd912..09a518f6 100644
--- a/core/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java
+++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java
@@ -1,22 +1,162 @@
package org.bouncycastle.asn1;
+import java.io.IOException;
import java.math.BigInteger;
+import org.bouncycastle.util.Arrays;
+
public class ASN1Enumerated
- extends DEREnumerated
+ extends ASN1Primitive
{
- ASN1Enumerated(byte[] bytes)
+ byte[] bytes;
+
+ /**
+ * return an integer from the passed in object
+ *
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static ASN1Enumerated getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof ASN1Enumerated)
+ {
+ return (ASN1Enumerated)obj;
+ }
+
+ if (obj instanceof byte[])
+ {
+ try
+ {
+ return (ASN1Enumerated)fromByteArray((byte[])obj);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
+ }
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return an Enumerated from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception IllegalArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static ASN1Enumerated getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ ASN1Primitive o = obj.getObject();
+
+ if (explicit || o instanceof ASN1Enumerated)
+ {
+ return getInstance(o);
+ }
+ else
+ {
+ return fromOctetString(((ASN1OctetString)o).getOctets());
+ }
+ }
+
+ /**
+ * @deprecated use ASN1Enumerated
+ */
+ public ASN1Enumerated(
+ int value)
+ {
+ bytes = BigInteger.valueOf(value).toByteArray();
+ }
+
+ /**
+ * @deprecated use ASN1Enumerated
+ */
+ public ASN1Enumerated(
+ BigInteger value)
+ {
+ bytes = value.toByteArray();
+ }
+
+ /**
+ * @deprecated use ASN1Enumerated
+ */
+ public ASN1Enumerated(
+ byte[] bytes)
+ {
+ this.bytes = bytes;
+ }
+
+ public BigInteger getValue()
{
- super(bytes);
+ return new BigInteger(bytes);
}
- public ASN1Enumerated(BigInteger value)
+ boolean isConstructed()
{
- super(value);
+ return false;
}
- public ASN1Enumerated(int value)
+ int encodedLength()
{
- super(value);
+ return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length;
+ }
+
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ out.writeEncoded(BERTags.ENUMERATED, bytes);
+ }
+
+ boolean asn1Equals(
+ ASN1Primitive o)
+ {
+ if (!(o instanceof ASN1Enumerated))
+ {
+ return false;
+ }
+
+ ASN1Enumerated other = (ASN1Enumerated)o;
+
+ return Arrays.areEqual(this.bytes, other.bytes);
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(bytes);
+ }
+
+ private static ASN1Enumerated[] cache = new ASN1Enumerated[12];
+
+ static ASN1Enumerated fromOctetString(byte[] enc)
+ {
+ if (enc.length > 1)
+ {
+ return new ASN1Enumerated(Arrays.clone(enc));
+ }
+
+ if (enc.length == 0)
+ {
+ throw new IllegalArgumentException("ENUMERATED has zero length");
+ }
+ int value = enc[0] & 0xff;
+
+ if (value >= cache.length)
+ {
+ return new ASN1Enumerated(Arrays.clone(enc));
+ }
+
+ ASN1Enumerated possibleMatch = cache[value];
+
+ if (possibleMatch == null)
+ {
+ possibleMatch = cache[value] = new ASN1Enumerated(Arrays.clone(enc));
+ }
+
+ return possibleMatch;
}
}
diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Integer.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Integer.java
index 18e89c6d..b951e745 100644
--- a/core/src/main/java/org/bouncycastle/asn1/ASN1Integer.java
+++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Integer.java
@@ -1,34 +1,150 @@
package org.bouncycastle.asn1;
+import java.io.IOException;
import java.math.BigInteger;
import org.bouncycastle.util.Arrays;
public class ASN1Integer
- extends DERInteger
+ extends ASN1Primitive
{
- ASN1Integer(byte[] bytes, boolean clone)
+ byte[] bytes;
+
+ /**
+ * return an integer from the passed in object
+ *
+ * @throws IllegalArgumentException if the object cannot be converted.
+ */
+ public static ASN1Integer getInstance(
+ Object obj)
{
- super(clone ? Arrays.clone(bytes) : bytes);
+ if (obj == null || obj instanceof ASN1Integer)
+ {
+ return (ASN1Integer)obj;
+ }
+
+ if (obj instanceof byte[])
+ {
+ try
+ {
+ return (ASN1Integer)fromByteArray((byte[])obj);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
+ }
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
}
/**
- * Constructor from a byte array containing a signed representation of the number.
+ * return an Integer from a tagged object.
*
- * @param bytes a byte array containing the signed number.A copy is made of the byte array.
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @throws IllegalArgumentException if the tagged object cannot
+ * be converted.
*/
- public ASN1Integer(byte[] bytes)
+ public static ASN1Integer getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ ASN1Primitive o = obj.getObject();
+
+ if (explicit || o instanceof ASN1Integer)
+ {
+ return getInstance(o);
+ }
+ else
+ {
+ return new ASN1Integer(ASN1OctetString.getInstance(obj.getObject()).getOctets());
+ }
+ }
+
+ public ASN1Integer(
+ long value)
+ {
+ bytes = BigInteger.valueOf(value).toByteArray();
+ }
+
+ public ASN1Integer(
+ BigInteger value)
+ {
+ bytes = value.toByteArray();
+ }
+
+ public ASN1Integer(
+ byte[] bytes)
{
this(bytes, true);
}
- public ASN1Integer(BigInteger value)
+ ASN1Integer(byte[] bytes, boolean clone)
+ {
+ this.bytes = (clone) ? Arrays.clone(bytes) : bytes;
+ }
+
+ public BigInteger getValue()
+ {
+ return new BigInteger(bytes);
+ }
+
+ /**
+ * in some cases positive values get crammed into a space,
+ * that's not quite big enough...
+ */
+ public BigInteger getPositiveValue()
+ {
+ return new BigInteger(1, bytes);
+ }
+
+ boolean isConstructed()
{
- super(value);
+ return false;
}
- public ASN1Integer(long value)
+ int encodedLength()
{
- super(value);
+ return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length;
}
+
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ out.writeEncoded(BERTags.INTEGER, bytes);
+ }
+
+ public int hashCode()
+ {
+ int value = 0;
+
+ for (int i = 0; i != bytes.length; i++)
+ {
+ value ^= (bytes[i] & 0xff) << (i % 4);
+ }
+
+ return value;
+ }
+
+ boolean asn1Equals(
+ ASN1Primitive o)
+ {
+ if (!(o instanceof ASN1Integer))
+ {
+ return false;
+ }
+
+ ASN1Integer other = (ASN1Integer)o;
+
+ return Arrays.areEqual(bytes, other.bytes);
+ }
+
+ public String toString()
+ {
+ return getValue().toString();
+ }
+
}
diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java
index 98f46a6d..6bd335bc 100644
--- a/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java
+++ b/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java
@@ -1,21 +1,429 @@
package org.bouncycastle.asn1;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+
+import org.bouncycastle.util.Arrays;
+
public class ASN1ObjectIdentifier
- extends DERObjectIdentifier
+ extends ASN1Primitive
{
- public ASN1ObjectIdentifier(String identifier)
+ String identifier;
+
+ private byte[] body;
+
+ /**
+ * return an OID from the passed in object
+ *
+ * @throws IllegalArgumentException if the object cannot be converted.
+ */
+ public static ASN1ObjectIdentifier getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof ASN1ObjectIdentifier)
+ {
+ return (ASN1ObjectIdentifier)obj;
+ }
+
+ if (obj instanceof ASN1Encodable && ((ASN1Encodable)obj).toASN1Primitive() instanceof ASN1ObjectIdentifier)
+ {
+ return (ASN1ObjectIdentifier)((ASN1Encodable)obj).toASN1Primitive();
+ }
+
+ if (obj instanceof byte[])
+ {
+ byte[] enc = (byte[])obj;
+ try
+ {
+ return (ASN1ObjectIdentifier)fromByteArray(enc);
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("failed to construct object identifier from byte[]: " + e.getMessage());
+ }
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return an Object Identifier from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @throws IllegalArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static ASN1ObjectIdentifier getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ ASN1Primitive o = obj.getObject();
+
+ if (explicit || o instanceof ASN1ObjectIdentifier)
+ {
+ return getInstance(o);
+ }
+ else
+ {
+ return ASN1ObjectIdentifier.fromOctetString(ASN1OctetString.getInstance(obj.getObject()).getOctets());
+ }
+ }
+
+ private static final long LONG_LIMIT = (Long.MAX_VALUE >> 7) - 0x7f;
+
+ ASN1ObjectIdentifier(
+ byte[] bytes)
+ {
+ StringBuffer objId = new StringBuffer();
+ long value = 0;
+ BigInteger bigValue = null;
+ boolean first = true;
+
+ for (int i = 0; i != bytes.length; i++)
+ {
+ int b = bytes[i] & 0xff;
+
+ if (value <= LONG_LIMIT)
+ {
+ value += (b & 0x7f);
+ if ((b & 0x80) == 0) // end of number reached
+ {
+ if (first)
+ {
+ if (value < 40)
+ {
+ objId.append('0');
+ }
+ else if (value < 80)
+ {
+ objId.append('1');
+ value -= 40;
+ }
+ else
+ {
+ objId.append('2');
+ value -= 80;
+ }
+ first = false;
+ }
+
+ objId.append('.');
+ objId.append(value);
+ value = 0;
+ }
+ else
+ {
+ value <<= 7;
+ }
+ }
+ else
+ {
+ if (bigValue == null)
+ {
+ bigValue = BigInteger.valueOf(value);
+ }
+ bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f));
+ if ((b & 0x80) == 0)
+ {
+ if (first)
+ {
+ objId.append('2');
+ bigValue = bigValue.subtract(BigInteger.valueOf(80));
+ first = false;
+ }
+
+ objId.append('.');
+ objId.append(bigValue);
+ bigValue = null;
+ value = 0;
+ }
+ else
+ {
+ bigValue = bigValue.shiftLeft(7);
+ }
+ }
+ }
+
+ this.identifier = objId.toString();
+ this.body = Arrays.clone(bytes);
+ }
+
+ public ASN1ObjectIdentifier(
+ String identifier)
{
- super(identifier);
+ if (identifier == null)
+ {
+ throw new IllegalArgumentException("'identifier' cannot be null");
+ }
+ if (!isValidIdentifier(identifier))
+ {
+ throw new IllegalArgumentException("string " + identifier + " not an OID");
+ }
+
+ this.identifier = identifier;
}
- ASN1ObjectIdentifier(byte[] bytes)
+ ASN1ObjectIdentifier(ASN1ObjectIdentifier oid, String branchID)
{
- super(bytes);
+ if (!isValidBranchID(branchID, 0))
+ {
+ throw new IllegalArgumentException("string " + branchID + " not a valid OID branch");
+ }
+
+ this.identifier = oid.getId() + "." + branchID;
}
- ASN1ObjectIdentifier(ASN1ObjectIdentifier oid, String branch)
+ public String getId()
{
- super(oid, branch);
+ return identifier;
+ }
+
+ private void writeField(
+ ByteArrayOutputStream out,
+ long fieldValue)
+ {
+ byte[] result = new byte[9];
+ int pos = 8;
+ result[pos] = (byte)((int)fieldValue & 0x7f);
+ while (fieldValue >= (1L << 7))
+ {
+ fieldValue >>= 7;
+ result[--pos] = (byte)((int)fieldValue & 0x7f | 0x80);
+ }
+ out.write(result, pos, 9 - pos);
+ }
+
+ private void writeField(
+ ByteArrayOutputStream out,
+ BigInteger fieldValue)
+ {
+ int byteCount = (fieldValue.bitLength() + 6) / 7;
+ if (byteCount == 0)
+ {
+ out.write(0);
+ }
+ else
+ {
+ BigInteger tmpValue = fieldValue;
+ byte[] tmp = new byte[byteCount];
+ for (int i = byteCount - 1; i >= 0; i--)
+ {
+ tmp[i] = (byte)((tmpValue.intValue() & 0x7f) | 0x80);
+ tmpValue = tmpValue.shiftRight(7);
+ }
+ tmp[byteCount - 1] &= 0x7f;
+ out.write(tmp, 0, tmp.length);
+ }
+ }
+
+ private void doOutput(ByteArrayOutputStream aOut)
+ {
+ OIDTokenizer tok = new OIDTokenizer(identifier);
+ int first = Integer.parseInt(tok.nextToken()) * 40;
+
+ String secondToken = tok.nextToken();
+ if (secondToken.length() <= 18)
+ {
+ writeField(aOut, first + Long.parseLong(secondToken));
+ }
+ else
+ {
+ writeField(aOut, new BigInteger(secondToken).add(BigInteger.valueOf(first)));
+ }
+
+ while (tok.hasMoreTokens())
+ {
+ String token = tok.nextToken();
+ if (token.length() <= 18)
+ {
+ writeField(aOut, Long.parseLong(token));
+ }
+ else
+ {
+ writeField(aOut, new BigInteger(token));
+ }
+ }
+ }
+
+ protected synchronized byte[] getBody()
+ {
+ if (body == null)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ doOutput(bOut);
+
+ body = bOut.toByteArray();
+ }
+
+ return body;
+ }
+
+ boolean isConstructed()
+ {
+ return false;
+ }
+
+ int encodedLength()
+ throws IOException
+ {
+ int length = getBody().length;
+
+ return 1 + StreamUtil.calculateBodyLength(length) + length;
+ }
+
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ byte[] enc = getBody();
+
+ out.write(BERTags.OBJECT_IDENTIFIER);
+ out.writeLength(enc.length);
+ out.write(enc);
+ }
+
+ public int hashCode()
+ {
+ return identifier.hashCode();
+ }
+
+ boolean asn1Equals(
+ ASN1Primitive o)
+ {
+ if (!(o instanceof ASN1ObjectIdentifier))
+ {
+ return false;
+ }
+
+ return identifier.equals(((ASN1ObjectIdentifier)o).identifier);
+ }
+
+ public String toString()
+ {
+ return getId();
+ }
+
+ private static boolean isValidBranchID(
+ String branchID, int start)
+ {
+ boolean periodAllowed = false;
+
+ int pos = branchID.length();
+ while (--pos >= start)
+ {
+ char ch = branchID.charAt(pos);
+
+ // TODO Leading zeroes?
+ if ('0' <= ch && ch <= '9')
+ {
+ periodAllowed = true;
+ continue;
+ }
+
+ if (ch == '.')
+ {
+ if (!periodAllowed)
+ {
+ return false;
+ }
+
+ periodAllowed = false;
+ continue;
+ }
+
+ return false;
+ }
+
+ return periodAllowed;
+ }
+
+ private static boolean isValidIdentifier(
+ String identifier)
+ {
+ if (identifier.length() < 3 || identifier.charAt(1) != '.')
+ {
+ return false;
+ }
+
+ char first = identifier.charAt(0);
+ if (first < '0' || first > '2')
+ {
+ return false;
+ }
+
+ return isValidBranchID(identifier, 2);
+ }
+
+ private static ASN1ObjectIdentifier[][] cache = new ASN1ObjectIdentifier[256][];
+
+ static ASN1ObjectIdentifier fromOctetString(byte[] enc)
+ {
+ if (enc.length < 3)
+ {
+ return new ASN1ObjectIdentifier(enc);
+ }
+
+ int idx1 = enc[enc.length - 2] & 0xff;
+ // in this case top bit is always zero
+ int idx2 = enc[enc.length - 1] & 0x7f;
+
+ ASN1ObjectIdentifier possibleMatch;
+
+ synchronized (cache)
+ {
+ ASN1ObjectIdentifier[] first = cache[idx1];
+ if (first == null)
+ {
+ first = cache[idx1] = new ASN1ObjectIdentifier[128];
+ }
+
+ possibleMatch = first[idx2];
+ if (possibleMatch == null)
+ {
+ return first[idx2] = new ASN1ObjectIdentifier(enc);
+ }
+
+ if (Arrays.areEqual(enc, possibleMatch.getBody()))
+ {
+ return possibleMatch;
+ }
+
+ idx1 = (idx1 + 1) & 0xff;
+ first = cache[idx1];
+ if (first == null)
+ {
+ first = cache[idx1] = new ASN1ObjectIdentifier[128];
+ }
+
+ possibleMatch = first[idx2];
+ if (possibleMatch == null)
+ {
+ return first[idx2] = new ASN1ObjectIdentifier(enc);
+ }
+
+ if (Arrays.areEqual(enc, possibleMatch.getBody()))
+ {
+ return possibleMatch;
+ }
+
+ idx2 = (idx2 + 1) & 0x7f;
+ possibleMatch = first[idx2];
+ if (possibleMatch == null)
+ {
+ return first[idx2] = new ASN1ObjectIdentifier(enc);
+ }
+ }
+
+ if (Arrays.areEqual(enc, possibleMatch.getBody()))
+ {
+ return possibleMatch;
+ }
+
+ return new ASN1ObjectIdentifier(enc);
}
/**
@@ -31,8 +439,9 @@ public class ASN1ObjectIdentifier
/**
* Return true if this oid is an extension of the passed in branch, stem.
+ *
* @param stem the arc or branch that is a possible parent.
- * @return true if the branch is on the passed in stem, false otherwise.
+ * @return true if the branch is on the passed in stem, false otherwise.
*/
public boolean on(ASN1ObjectIdentifier stem)
{
diff --git a/core/src/main/java/org/bouncycastle/asn1/DERBoolean.java b/core/src/main/java/org/bouncycastle/asn1/DERBoolean.java
index 8b8d2260..378ea359 100644
--- a/core/src/main/java/org/bouncycastle/asn1/DERBoolean.java
+++ b/core/src/main/java/org/bouncycastle/asn1/DERBoolean.java
@@ -1,179 +1,22 @@
package org.bouncycastle.asn1;
-import java.io.IOException;
-
-import org.bouncycastle.util.Arrays;
-
+/**
+ * @deprecated use ASN1Boolean
+ */
public class DERBoolean
- extends ASN1Primitive
+ extends ASN1Boolean
{
- private static final byte[] TRUE_VALUE = new byte[] { (byte)0xff };
- private static final byte[] FALSE_VALUE = new byte[] { 0 };
-
- private byte[] value;
-
- public static final ASN1Boolean FALSE = new ASN1Boolean(false);
- public static final ASN1Boolean TRUE = new ASN1Boolean(true);
-
-
- /**
- * return a boolean from the passed in object.
- *
- * @exception IllegalArgumentException if the object cannot be converted.
- */
- public static ASN1Boolean getInstance(
- Object obj)
- {
- if (obj == null || obj instanceof ASN1Boolean)
- {
- return (ASN1Boolean)obj;
- }
-
- if (obj instanceof DERBoolean)
- {
- return ((DERBoolean)obj).isTrue() ? DERBoolean.TRUE : DERBoolean.FALSE;
- }
-
- throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
- }
-
- /**
- * return a ASN1Boolean from the passed in boolean.
- */
- public static ASN1Boolean getInstance(
- boolean value)
- {
- return (value ? TRUE : FALSE);
- }
-
- /**
- * return a ASN1Boolean from the passed in boolean.
- */
- public static ASN1Boolean getInstance(
- int value)
- {
- return (value != 0 ? TRUE : FALSE);
- }
-
- /**
- * return a Boolean from a tagged object.
- *
- * @param obj the tagged object holding the object we want
- * @param explicit true if the object is meant to be explicitly
- * tagged false otherwise.
- * @exception IllegalArgumentException if the tagged object cannot
- * be converted.
- */
- public static ASN1Boolean getInstance(
- ASN1TaggedObject obj,
- boolean explicit)
- {
- ASN1Primitive o = obj.getObject();
-
- if (explicit || o instanceof DERBoolean)
- {
- return getInstance(o);
- }
- else
- {
- return ASN1Boolean.fromOctetString(((ASN1OctetString)o).getOctets());
- }
- }
-
- DERBoolean(
- byte[] value)
- {
- if (value.length != 1)
- {
- throw new IllegalArgumentException("byte value should have 1 byte in it");
- }
-
- if (value[0] == 0)
- {
- this.value = FALSE_VALUE;
- }
- else if (value[0] == 0xff)
- {
- this.value = TRUE_VALUE;
- }
- else
- {
- this.value = Arrays.clone(value);
- }
- }
-
/**
* @deprecated use getInstance(boolean) method.
* @param value
*/
- public DERBoolean(
- boolean value)
- {
- this.value = (value) ? TRUE_VALUE : FALSE_VALUE;
- }
-
- public boolean isTrue()
- {
- return (value[0] != 0);
- }
-
- boolean isConstructed()
- {
- return false;
- }
-
- int encodedLength()
+ public DERBoolean(boolean value)
{
- return 3;
+ super(value);
}
- void encode(
- ASN1OutputStream out)
- throws IOException
+ DERBoolean(byte[] value)
{
- out.writeEncoded(BERTags.BOOLEAN, value);
- }
-
- protected boolean asn1Equals(
- ASN1Primitive o)
- {
- if ((o == null) || !(o instanceof DERBoolean))
- {
- return false;
- }
-
- return (value[0] == ((DERBoolean)o).value[0]);
- }
-
- public int hashCode()
- {
- return value[0];
- }
-
-
- public String toString()
- {
- return (value[0] != 0) ? "TRUE" : "FALSE";
- }
-
- static ASN1Boolean fromOctetString(byte[] value)
- {
- if (value.length != 1)
- {
- throw new IllegalArgumentException("BOOLEAN value should have 1 byte in it");
- }
-
- if (value[0] == 0)
- {
- return FALSE;
- }
- else if (value[0] == 0xff)
- {
- return TRUE;
- }
- else
- {
- return new ASN1Boolean(value);
- }
+ super(value);
}
}
diff --git a/core/src/main/java/org/bouncycastle/asn1/DEREnumerated.java b/core/src/main/java/org/bouncycastle/asn1/DEREnumerated.java
index 9b1ef55c..879a01ca 100644
--- a/core/src/main/java/org/bouncycastle/asn1/DEREnumerated.java
+++ b/core/src/main/java/org/bouncycastle/asn1/DEREnumerated.java
@@ -1,170 +1,25 @@
package org.bouncycastle.asn1;
-import java.io.IOException;
import java.math.BigInteger;
-import org.bouncycastle.util.Arrays;
-
/**
- * Use ASN1Enumerated instead of this.
+ * @deprecated Use ASN1Enumerated instead of this.
*/
public class DEREnumerated
- extends ASN1Primitive
+ extends ASN1Enumerated
{
- byte[] bytes;
-
- /**
- * return an integer from the passed in object
- *
- * @exception IllegalArgumentException if the object cannot be converted.
- */
- public static ASN1Enumerated getInstance(
- Object obj)
- {
- if (obj == null || obj instanceof ASN1Enumerated)
- {
- return (ASN1Enumerated)obj;
- }
-
- if (obj instanceof DEREnumerated)
- {
- return new ASN1Enumerated(((DEREnumerated)obj).getValue());
- }
-
- if (obj instanceof byte[])
- {
- try
- {
- return (ASN1Enumerated)fromByteArray((byte[])obj);
- }
- catch (Exception e)
- {
- throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
- }
- }
-
- throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
- }
-
- /**
- * return an Enumerated from a tagged object.
- *
- * @param obj the tagged object holding the object we want
- * @param explicit true if the object is meant to be explicitly
- * tagged false otherwise.
- * @exception IllegalArgumentException if the tagged object cannot
- * be converted.
- */
- public static ASN1Enumerated getInstance(
- ASN1TaggedObject obj,
- boolean explicit)
- {
- ASN1Primitive o = obj.getObject();
-
- if (explicit || o instanceof DEREnumerated)
- {
- return getInstance(o);
- }
- else
- {
- return fromOctetString(((ASN1OctetString)o).getOctets());
- }
- }
-
- /**
- * @deprecated use ASN1Enumerated
- */
- public DEREnumerated(
- int value)
- {
- bytes = BigInteger.valueOf(value).toByteArray();
- }
-
- /**
- * @deprecated use ASN1Enumerated
- */
- public DEREnumerated(
- BigInteger value)
- {
- bytes = value.toByteArray();
- }
-
- /**
- * @deprecated use ASN1Enumerated
- */
- public DEREnumerated(
- byte[] bytes)
- {
- this.bytes = bytes;
- }
-
- public BigInteger getValue()
- {
- return new BigInteger(bytes);
- }
-
- boolean isConstructed()
- {
- return false;
- }
-
- int encodedLength()
- {
- return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length;
- }
-
- void encode(
- ASN1OutputStream out)
- throws IOException
+ DEREnumerated(byte[] bytes)
{
- out.writeEncoded(BERTags.ENUMERATED, bytes);
+ super(bytes);
}
-
- boolean asn1Equals(
- ASN1Primitive o)
- {
- if (!(o instanceof DEREnumerated))
- {
- return false;
- }
-
- DEREnumerated other = (DEREnumerated)o;
- return Arrays.areEqual(this.bytes, other.bytes);
- }
-
- public int hashCode()
+ public DEREnumerated(BigInteger value)
{
- return Arrays.hashCode(bytes);
+ super(value);
}
- private static ASN1Enumerated[] cache = new ASN1Enumerated[12];
-
- static ASN1Enumerated fromOctetString(byte[] enc)
+ public DEREnumerated(int value)
{
- if (enc.length > 1)
- {
- return new ASN1Enumerated(Arrays.clone(enc));
- }
-
- if (enc.length == 0)
- {
- throw new IllegalArgumentException("ENUMERATED has zero length");
- }
- int value = enc[0] & 0xff;
-
- if (value >= cache.length)
- {
- return new ASN1Enumerated(Arrays.clone(enc));
- }
-
- ASN1Enumerated possibleMatch = cache[value];
-
- if (possibleMatch == null)
- {
- possibleMatch = cache[value] = new ASN1Enumerated(Arrays.clone(enc));
- }
-
- return possibleMatch;
+ super(value);
}
}
diff --git a/core/src/main/java/org/bouncycastle/asn1/DERInteger.java b/core/src/main/java/org/bouncycastle/asn1/DERInteger.java
index 57cc84a7..d2e850f3 100644
--- a/core/src/main/java/org/bouncycastle/asn1/DERInteger.java
+++ b/core/src/main/java/org/bouncycastle/asn1/DERInteger.java
@@ -1,160 +1,30 @@
package org.bouncycastle.asn1;
-import java.io.IOException;
import java.math.BigInteger;
-import org.bouncycastle.util.Arrays;
-
/**
- * Use ASN1Integer instead of this,
+ * @deprecated Use ASN1Integer instead of this,
*/
public class DERInteger
- extends ASN1Primitive
+ extends ASN1Integer
{
- byte[] bytes;
-
- /**
- * return an integer from the passed in object
- *
- * @exception IllegalArgumentException if the object cannot be converted.
- */
- public static ASN1Integer getInstance(
- Object obj)
- {
- if (obj == null || obj instanceof ASN1Integer)
- {
- return (ASN1Integer)obj;
- }
- if (obj instanceof DERInteger)
- {
- return new ASN1Integer((((DERInteger)obj).getValue()));
- }
-
- if (obj instanceof byte[])
- {
- try
- {
- return (ASN1Integer)fromByteArray((byte[])obj);
- }
- catch (Exception e)
- {
- throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
- }
- }
-
- throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
- }
-
/**
- * return an Integer from a tagged object.
+ * Constructor from a byte array containing a signed representation of the number.
*
- * @param obj the tagged object holding the object we want
- * @param explicit true if the object is meant to be explicitly
- * tagged false otherwise.
- * @exception IllegalArgumentException if the tagged object cannot
- * be converted.
- */
- public static ASN1Integer getInstance(
- ASN1TaggedObject obj,
- boolean explicit)
- {
- ASN1Primitive o = obj.getObject();
-
- if (explicit || o instanceof DERInteger)
- {
- return getInstance(o);
- }
- else
- {
- return new ASN1Integer(ASN1OctetString.getInstance(obj.getObject()).getOctets());
- }
- }
-
- /**
- * @deprecated use ASN1Integer constructor
- */
- public DERInteger(
- long value)
- {
- bytes = BigInteger.valueOf(value).toByteArray();
- }
-
- /**
- * @deprecated use ASN1Integer constructor
+ * @param bytes a byte array containing the signed number.A copy is made of the byte array.
*/
- public DERInteger(
- BigInteger value)
+ public DERInteger(byte[] bytes)
{
- bytes = value.toByteArray();
+ super(bytes, true);
}
- /**
- * @deprecated use ASN1Integer constructor
- */
- public DERInteger(
- byte[] bytes)
+ public DERInteger(BigInteger value)
{
- this.bytes = bytes;
- }
-
- public BigInteger getValue()
- {
- return new BigInteger(bytes);
- }
-
- /**
- * in some cases positive values get crammed into a space,
- * that's not quite big enough...
- */
- public BigInteger getPositiveValue()
- {
- return new BigInteger(1, bytes);
- }
-
- boolean isConstructed()
- {
- return false;
- }
-
- int encodedLength()
- {
- return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length;
- }
-
- void encode(
- ASN1OutputStream out)
- throws IOException
- {
- out.writeEncoded(BERTags.INTEGER, bytes);
- }
-
- public int hashCode()
- {
- int value = 0;
-
- for (int i = 0; i != bytes.length; i++)
- {
- value ^= (bytes[i] & 0xff) << (i % 4);
- }
-
- return value;
- }
-
- boolean asn1Equals(
- ASN1Primitive o)
- {
- if (!(o instanceof DERInteger))
- {
- return false;
- }
-
- DERInteger other = (DERInteger)o;
-
- return Arrays.areEqual(bytes, other.bytes);
+ super(value);
}
- public String toString()
+ public DERInteger(long value)
{
- return getValue().toString();
+ super(value);
}
}
diff --git a/core/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java
index 3d4d04c1..acb2ada6 100644
--- a/core/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java
+++ b/core/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java
@@ -1,446 +1,24 @@
package org.bouncycastle.asn1;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.math.BigInteger;
-
-import org.bouncycastle.util.Arrays;
-
/**
- * Use ASN1ObjectIdentifier instead of this,
+ *
+ * @deprecated Use ASN1ObjectIdentifier instead of this,
*/
public class DERObjectIdentifier
- extends ASN1Primitive
+ extends ASN1ObjectIdentifier
{
- String identifier;
-
- private byte[] body;
-
- /**
- * return an OID from the passed in object
- *
- * @throws IllegalArgumentException if the object cannot be converted.
- */
- public static ASN1ObjectIdentifier getInstance(
- Object obj)
- {
- if (obj == null || obj instanceof ASN1ObjectIdentifier)
- {
- return (ASN1ObjectIdentifier)obj;
- }
-
- if (obj instanceof DERObjectIdentifier)
- {
- return new ASN1ObjectIdentifier(((DERObjectIdentifier)obj).getId());
- }
-
- if (obj instanceof ASN1Encodable && ((ASN1Encodable)obj).toASN1Primitive() instanceof ASN1ObjectIdentifier)
- {
- return (ASN1ObjectIdentifier)((ASN1Encodable)obj).toASN1Primitive();
- }
-
- if (obj instanceof byte[])
- {
- byte[] enc = (byte[])obj;
- if (enc[0] == BERTags.OBJECT_IDENTIFIER)
- {
- try
- {
- return (ASN1ObjectIdentifier)fromByteArray(enc);
- }
- catch (IOException e)
- {
- throw new IllegalArgumentException("failed to construct sequence from byte[]: " + e.getMessage());
- }
- }
- else
- { // TODO: this really shouldn't be supported here...
- return ASN1ObjectIdentifier.fromOctetString((byte[])obj);
- }
- }
-
- throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
- }
-
- /**
- * return an Object Identifier from a tagged object.
- *
- * @param obj the tagged object holding the object we want
- * @param explicit true if the object is meant to be explicitly
- * tagged false otherwise.
- * @throws IllegalArgumentException if the tagged object cannot
- * be converted.
- */
- public static ASN1ObjectIdentifier getInstance(
- ASN1TaggedObject obj,
- boolean explicit)
- {
- ASN1Primitive o = obj.getObject();
-
- if (explicit || o instanceof DERObjectIdentifier)
- {
- return getInstance(o);
- }
- else
- {
- return ASN1ObjectIdentifier.fromOctetString(ASN1OctetString.getInstance(obj.getObject()).getOctets());
- }
- }
-
- private static final long LONG_LIMIT = (Long.MAX_VALUE >> 7) - 0x7f;
-
- DERObjectIdentifier(
- byte[] bytes)
+ public DERObjectIdentifier(String identifier)
{
- StringBuffer objId = new StringBuffer();
- long value = 0;
- BigInteger bigValue = null;
- boolean first = true;
-
- for (int i = 0; i != bytes.length; i++)
- {
- int b = bytes[i] & 0xff;
-
- if (value <= LONG_LIMIT)
- {
- value += (b & 0x7f);
- if ((b & 0x80) == 0) // end of number reached
- {
- if (first)
- {
- if (value < 40)
- {
- objId.append('0');
- }
- else if (value < 80)
- {
- objId.append('1');
- value -= 40;
- }
- else
- {
- objId.append('2');
- value -= 80;
- }
- first = false;
- }
-
- objId.append('.');
- objId.append(value);
- value = 0;
- }
- else
- {
- value <<= 7;
- }
- }
- else
- {
- if (bigValue == null)
- {
- bigValue = BigInteger.valueOf(value);
- }
- bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f));
- if ((b & 0x80) == 0)
- {
- if (first)
- {
- objId.append('2');
- bigValue = bigValue.subtract(BigInteger.valueOf(80));
- first = false;
- }
-
- objId.append('.');
- objId.append(bigValue);
- bigValue = null;
- value = 0;
- }
- else
- {
- bigValue = bigValue.shiftLeft(7);
- }
- }
- }
-
- this.identifier = objId.toString();
- this.body = Arrays.clone(bytes);
+ super(identifier);
}
- /**
- * @deprecated use ASN1ObjectIdentifier constructor.
- */
- public DERObjectIdentifier(
- String identifier)
+ DERObjectIdentifier(byte[] bytes)
{
- if (identifier == null)
- {
- throw new IllegalArgumentException("'identifier' cannot be null");
- }
- if (!isValidIdentifier(identifier))
- {
- throw new IllegalArgumentException("string " + identifier + " not an OID");
- }
-
- this.identifier = identifier;
+ super(bytes);
}
- DERObjectIdentifier(DERObjectIdentifier oid, String branchID)
+ DERObjectIdentifier(ASN1ObjectIdentifier oid, String branch)
{
- if (!isValidBranchID(branchID, 0))
- {
- throw new IllegalArgumentException("string " + branchID + " not a valid OID branch");
- }
-
- this.identifier = oid.getId() + "." + branchID;
- }
-
- public String getId()
- {
- return identifier;
- }
-
- private void writeField(
- ByteArrayOutputStream out,
- long fieldValue)
- {
- byte[] result = new byte[9];
- int pos = 8;
- result[pos] = (byte)((int)fieldValue & 0x7f);
- while (fieldValue >= (1L << 7))
- {
- fieldValue >>= 7;
- result[--pos] = (byte)((int)fieldValue & 0x7f | 0x80);
- }
- out.write(result, pos, 9 - pos);
- }
-
- private void writeField(
- ByteArrayOutputStream out,
- BigInteger fieldValue)
- {
- int byteCount = (fieldValue.bitLength() + 6) / 7;
- if (byteCount == 0)
- {
- out.write(0);
- }
- else
- {
- BigInteger tmpValue = fieldValue;
- byte[] tmp = new byte[byteCount];
- for (int i = byteCount - 1; i >= 0; i--)
- {
- tmp[i] = (byte)((tmpValue.intValue() & 0x7f) | 0x80);
- tmpValue = tmpValue.shiftRight(7);
- }
- tmp[byteCount - 1] &= 0x7f;
- out.write(tmp, 0, tmp.length);
- }
- }
-
- private void doOutput(ByteArrayOutputStream aOut)
- {
- OIDTokenizer tok = new OIDTokenizer(identifier);
- int first = Integer.parseInt(tok.nextToken()) * 40;
-
- String secondToken = tok.nextToken();
- if (secondToken.length() <= 18)
- {
- writeField(aOut, first + Long.parseLong(secondToken));
- }
- else
- {
- writeField(aOut, new BigInteger(secondToken).add(BigInteger.valueOf(first)));
- }
-
- while (tok.hasMoreTokens())
- {
- String token = tok.nextToken();
- if (token.length() <= 18)
- {
- writeField(aOut, Long.parseLong(token));
- }
- else
- {
- writeField(aOut, new BigInteger(token));
- }
- }
- }
-
- protected synchronized byte[] getBody()
- {
- if (body == null)
- {
- ByteArrayOutputStream bOut = new ByteArrayOutputStream();
-
- doOutput(bOut);
-
- body = bOut.toByteArray();
- }
-
- return body;
- }
-
- boolean isConstructed()
- {
- return false;
- }
-
- int encodedLength()
- throws IOException
- {
- int length = getBody().length;
-
- return 1 + StreamUtil.calculateBodyLength(length) + length;
- }
-
- void encode(
- ASN1OutputStream out)
- throws IOException
- {
- byte[] enc = getBody();
-
- out.write(BERTags.OBJECT_IDENTIFIER);
- out.writeLength(enc.length);
- out.write(enc);
- }
-
- public int hashCode()
- {
- return identifier.hashCode();
- }
-
- boolean asn1Equals(
- ASN1Primitive o)
- {
- if (!(o instanceof DERObjectIdentifier))
- {
- return false;
- }
-
- return identifier.equals(((DERObjectIdentifier)o).identifier);
- }
-
- public String toString()
- {
- return getId();
- }
-
- private static boolean isValidBranchID(
- String branchID, int start)
- {
- boolean periodAllowed = false;
-
- int pos = branchID.length();
- while (--pos >= start)
- {
- char ch = branchID.charAt(pos);
-
- // TODO Leading zeroes?
- if ('0' <= ch && ch <= '9')
- {
- periodAllowed = true;
- continue;
- }
-
- if (ch == '.')
- {
- if (!periodAllowed)
- {
- return false;
- }
-
- periodAllowed = false;
- continue;
- }
-
- return false;
- }
-
- return periodAllowed;
- }
-
- private static boolean isValidIdentifier(
- String identifier)
- {
- if (identifier.length() < 3 || identifier.charAt(1) != '.')
- {
- return false;
- }
-
- char first = identifier.charAt(0);
- if (first < '0' || first > '2')
- {
- return false;
- }
-
- return isValidBranchID(identifier, 2);
- }
-
- private static ASN1ObjectIdentifier[][] cache = new ASN1ObjectIdentifier[256][];
-
- static ASN1ObjectIdentifier fromOctetString(byte[] enc)
- {
- if (enc.length < 3)
- {
- return new ASN1ObjectIdentifier(enc);
- }
-
- int idx1 = enc[enc.length - 2] & 0xff;
- // in this case top bit is always zero
- int idx2 = enc[enc.length - 1] & 0x7f;
-
- ASN1ObjectIdentifier possibleMatch;
-
- synchronized (cache)
- {
- ASN1ObjectIdentifier[] first = cache[idx1];
- if (first == null)
- {
- first = cache[idx1] = new ASN1ObjectIdentifier[128];
- }
-
- possibleMatch = first[idx2];
- if (possibleMatch == null)
- {
- return first[idx2] = new ASN1ObjectIdentifier(enc);
- }
-
- if (Arrays.areEqual(enc, possibleMatch.getBody()))
- {
- return possibleMatch;
- }
-
- idx1 = (idx1 + 1) & 0xff;
- first = cache[idx1];
- if (first == null)
- {
- first = cache[idx1] = new ASN1ObjectIdentifier[128];
- }
-
- possibleMatch = first[idx2];
- if (possibleMatch == null)
- {
- return first[idx2] = new ASN1ObjectIdentifier(enc);
- }
-
- if (Arrays.areEqual(enc, possibleMatch.getBody()))
- {
- return possibleMatch;
- }
-
- idx2 = (idx2 + 1) & 0x7f;
- possibleMatch = first[idx2];
- if (possibleMatch == null)
- {
- return first[idx2] = new ASN1ObjectIdentifier(enc);
- }
- }
-
- if (Arrays.areEqual(enc, possibleMatch.getBody()))
- {
- return possibleMatch;
- }
-
- return new ASN1ObjectIdentifier(enc);
+ super(oid, branch);
}
}
diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/Attribute.java b/core/src/main/java/org/bouncycastle/asn1/cms/Attribute.java
index 066cf693..8c487433 100644
--- a/core/src/main/java/org/bouncycastle/asn1/cms/Attribute.java
+++ b/core/src/main/java/org/bouncycastle/asn1/cms/Attribute.java
@@ -7,7 +7,6 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1Set;
-import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.DERSequence;
/**
@@ -73,17 +72,6 @@ public class Attribute
attrValues = (ASN1Set)seq.getObjectAt(1);
}
- /**
- * @deprecated use ASN1ObjectIdentifier
- */
- public Attribute(
- DERObjectIdentifier attrType,
- ASN1Set attrValues)
- {
- this.attrType = new ASN1ObjectIdentifier(attrType.getId());
- this.attrValues = attrValues;
- }
-
public Attribute(
ASN1ObjectIdentifier attrType,
ASN1Set attrValues)
diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java b/core/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java
index 02b6cc1e..3b8e0bed 100644
--- a/core/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java
+++ b/core/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java
@@ -8,7 +8,6 @@ import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Set;
-import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.DERSet;
/**
@@ -91,14 +90,6 @@ public class AttributeTable
}
/**
- * @deprecated use ASN1ObjectIdentifier
- */
- public Attribute get(DERObjectIdentifier oid)
- {
- return get(new ASN1ObjectIdentifier(oid.getId()));
- }
-
- /**
* Return the first attribute matching the OBJECT IDENTIFIER oid.
*
* @param oid type of attribute required.
@@ -117,14 +108,6 @@ public class AttributeTable
return (Attribute)value;
}
- /**
- * @deprecated use ASN1ObjectIdentifier
- */
- public ASN1EncodableVector getAll(DERObjectIdentifier oid)
- {
- return getAll(new ASN1ObjectIdentifier(oid.getId()));
- }
-
/**
* Return all the attributes matching the OBJECT IDENTIFIER oid. The vector will be
* empty if there are no attributes of the required type present.
diff --git a/core/src/main/java/org/bouncycastle/asn1/ess/ContentHints.java b/core/src/main/java/org/bouncycastle/asn1/ess/ContentHints.java
index 93d9d0c8..462d9685 100644
--- a/core/src/main/java/org/bouncycastle/asn1/ess/ContentHints.java
+++ b/core/src/main/java/org/bouncycastle/asn1/ess/ContentHints.java
@@ -6,7 +6,6 @@ import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERUTF8String;
@@ -47,25 +46,6 @@ public class ContentHints
}
}
- /**
- * @deprecated use ASN1ObjectIdentifier
- */
- public ContentHints(
- DERObjectIdentifier contentType)
- {
- this(new ASN1ObjectIdentifier(contentType.getId()));
- }
-
- /**
- * @deprecated use ASN1ObjectIdentifier
- */
- public ContentHints(
- DERObjectIdentifier contentType,
- DERUTF8String contentDescription)
- {
- this(new ASN1ObjectIdentifier(contentType.getId()), contentDescription);
- }
-
public ContentHints(
ASN1ObjectIdentifier contentType)
{
diff --git a/core/src/main/java/org/bouncycastle/asn1/oiw/ElGamalParameter.java b/core/src/main/java/org/bouncycastle/asn1/oiw/ElGamalParameter.java
index c6a2965b..d654d032 100644
--- a/core/src/main/java/org/bouncycastle/asn1/oiw/ElGamalParameter.java
+++ b/core/src/main/java/org/bouncycastle/asn1/oiw/ElGamalParameter.java
@@ -23,7 +23,7 @@ public class ElGamalParameter
this.g = new ASN1Integer(g);
}
- public ElGamalParameter(
+ private ElGamalParameter(
ASN1Sequence seq)
{
Enumeration e = seq.getObjects();
@@ -32,6 +32,20 @@ public class ElGamalParameter
g = (ASN1Integer)e.nextElement();
}
+ public static ElGamalParameter getInstance(Object o)
+ {
+ if (o instanceof ElGamalParameter)
+ {
+ return (ElGamalParameter)o;
+ }
+ else if (o != null)
+ {
+ return new ElGamalParameter(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
public BigInteger getP()
{
return p.getPositiveValue();
diff --git a/core/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java b/core/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java
index 1ba3dbea..450fd703 100644
--- a/core/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java
+++ b/core/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java
@@ -10,6 +10,8 @@ import org.bouncycastle.asn1.x9.X9ECParametersHolder;
import org.bouncycastle.math.ec.ECConstants;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.ec.endo.GLVTypeBEndomorphism;
+import org.bouncycastle.math.ec.endo.GLVTypeBParameters;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
@@ -20,6 +22,11 @@ public class SECNamedCurves
return curve;
}
+ private static ECCurve configureCurveGLV(ECCurve c, GLVTypeBParameters p)
+ {
+ return c.configure().setEndomorphism(new GLVTypeBEndomorphism(c, p)).create();
+ }
+
private static BigInteger fromHex(
String hex)
{
@@ -145,7 +152,20 @@ public class SECNamedCurves
BigInteger n = fromHex("0100000000000000000001B8FA16DFAB9ACA16B6B3");
BigInteger h = BigInteger.valueOf(1);
- ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h));
+ GLVTypeBParameters glv = new GLVTypeBParameters(
+ new BigInteger("9ba48cba5ebcb9b6bd33b92830b2a2e0e192f10a", 16),
+ new BigInteger("c39c6c3b3a36d7701b9c71a1f5804ae5d0003f4", 16),
+ new BigInteger[]{
+ new BigInteger("9162fbe73984472a0a9e", 16),
+ new BigInteger("-96341f1138933bc2f505", 16) },
+ new BigInteger[]{
+ new BigInteger("127971af8721782ecffa3", 16),
+ new BigInteger("9162fbe73984472a0a9e", 16) },
+ new BigInteger("48b17df39cc22395054e8", 16),
+ new BigInteger("4b1a0f889c499de17a820", 16),
+ 163);
+
+ ECCurve curve = configureCurveGLV(new ECCurve.Fp(p, a, b, n, h), glv);
// ECPoint G = curve.decodePoint(Hex.decode("02"
// + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB"));
ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -223,7 +243,20 @@ public class SECNamedCurves
BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D");
BigInteger h = BigInteger.valueOf(1);
- ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h));
+ GLVTypeBParameters glv = new GLVTypeBParameters(
+ new BigInteger("bb85691939b869c1d087f601554b96b80cb4f55b35f433c2", 16),
+ new BigInteger("3d84f26c12238d7b4f3d516613c1759033b1a5800175d0b1", 16),
+ new BigInteger[]{
+ new BigInteger("71169be7330b3038edb025f1", 16),
+ new BigInteger("-b3fb3400dec5c4adceb8655c", 16) },
+ new BigInteger[]{
+ new BigInteger("12511cfe811d0f4e6bc688b4d", 16),
+ new BigInteger("71169be7330b3038edb025f1", 16) },
+ new BigInteger("1c45a6f9ccc2cc0e3b6c097c7", 16),
+ new BigInteger("2cfecd0037b1712b73ae19575", 16),
+ 194);
+
+ ECCurve curve = configureCurveGLV(new ECCurve.Fp(p, a, b, n, h), glv);
//ECPoint G = curve.decodePoint(Hex.decode("03"
//+ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"));
ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -275,7 +308,20 @@ public class SECNamedCurves
BigInteger n = fromHex("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7");
BigInteger h = BigInteger.valueOf(1);
- ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h));
+ GLVTypeBParameters glv = new GLVTypeBParameters(
+ new BigInteger("fe0e87005b4e83761908c5131d552a850b3f58b749c37cf5b84d6768", 16),
+ new BigInteger("60dcd2104c4cbc0be6eeefc2bdd610739ec34e317f9b33046c9e4788", 16),
+ new BigInteger[]{
+ new BigInteger("6b8cf07d4ca75c88957d9d670591", 16),
+ new BigInteger("-b8adf1378a6eb73409fa6c9c637d", 16) },
+ new BigInteger[]{
+ new BigInteger("1243ae1b4d71613bc9f780a03690e", 16),
+ new BigInteger("6b8cf07d4ca75c88957d9d670591", 16) },
+ new BigInteger("35c6783ea653ae444abeceb382c82", 16),
+ new BigInteger("5c56f89bc5375b9a04fd364e31bdd", 16),
+ 227);
+
+ ECCurve curve = configureCurveGLV(new ECCurve.Fp(p, a, b, n, h), glv);
//ECPoint G = curve.decodePoint(Hex.decode("03"
//+ "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"));
ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -327,7 +373,20 @@ public class SECNamedCurves
BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
BigInteger h = BigInteger.valueOf(1);
- ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h));
+ GLVTypeBParameters glv = new GLVTypeBParameters(
+ new BigInteger("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee", 16),
+ new BigInteger("5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72", 16),
+ new BigInteger[]{
+ new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16),
+ new BigInteger("-e4437ed6010e88286f547fa90abfe4c3", 16) },
+ new BigInteger[]{
+ new BigInteger("114ca50f7a8e2f3f657c1108d9d44cfd8", 16),
+ new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16) },
+ new BigInteger("c21b48869f51af37a1b243924a13ac55", 16),
+ new BigInteger("3910dfb58043a20a1bd51fea42aff9311", 16),
+ 258);
+
+ ECCurve curve = configureCurveGLV(new ECCurve.Fp(p, a, b, n, h), glv);
//ECPoint G = curve.decodePoint(Hex.decode("02"
//+ "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"));
ECPoint G = curve.decodePoint(Hex.decode("04"
diff --git a/core/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java b/core/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java
index 4560f647..8221e182 100644
--- a/core/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java
+++ b/core/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java
@@ -3,7 +3,9 @@ package org.bouncycastle.asn1.util;
import java.io.IOException;
import java.util.Enumeration;
+import org.bouncycastle.asn1.ASN1Boolean;
import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Enumerated;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
@@ -12,7 +14,6 @@ import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1Set;
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.BERApplicationSpecific;
-import org.bouncycastle.asn1.BERConstructedOctetString;
import org.bouncycastle.asn1.BEROctetString;
import org.bouncycastle.asn1.BERSequence;
import org.bouncycastle.asn1.BERSet;
@@ -21,8 +22,6 @@ import org.bouncycastle.asn1.BERTags;
import org.bouncycastle.asn1.DERApplicationSpecific;
import org.bouncycastle.asn1.DERBMPString;
import org.bouncycastle.asn1.DERBitString;
-import org.bouncycastle.asn1.DERBoolean;
-import org.bouncycastle.asn1.DEREnumerated;
import org.bouncycastle.asn1.DERExternal;
import org.bouncycastle.asn1.DERGeneralizedTime;
import org.bouncycastle.asn1.DERIA5String;
@@ -193,9 +192,9 @@ public class ASN1Dump
{
buf.append(indent + "ObjectIdentifier(" + ((ASN1ObjectIdentifier)obj).getId() + ")" + nl);
}
- else if (obj instanceof DERBoolean)
+ else if (obj instanceof ASN1Boolean)
{
- buf.append(indent + "Boolean(" + ((DERBoolean)obj).isTrue() + ")" + nl);
+ buf.append(indent + "Boolean(" + ((ASN1Boolean)obj).isTrue() + ")" + nl);
}
else if (obj instanceof ASN1Integer)
{
@@ -254,9 +253,9 @@ public class ASN1Dump
{
buf.append(outputApplicationSpecific("DER", indent, verbose, obj, nl));
}
- else if (obj instanceof DEREnumerated)
+ else if (obj instanceof ASN1Enumerated)
{
- DEREnumerated en = (DEREnumerated) obj;
+ ASN1Enumerated en = (ASN1Enumerated) obj;
buf.append(indent + "DER Enumerated(" + en.getValue() + ")" + nl);
}
else if (obj instanceof DERExternal)
diff --git a/core/src/main/java/org/bouncycastle/asn1/x500/style/AbstractX500NameStyle.java b/core/src/main/java/org/bouncycastle/asn1/x500/style/AbstractX500NameStyle.java
new file mode 100644
index 00000000..a411f9ca
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/asn1/x500/style/AbstractX500NameStyle.java
@@ -0,0 +1,188 @@
+package org.bouncycastle.asn1.x500.style;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERUTF8String;
+import org.bouncycastle.asn1.x500.AttributeTypeAndValue;
+import org.bouncycastle.asn1.x500.RDN;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x500.X500NameStyle;
+
+/**
+ * This class provides some default behavior and common implementation for a
+ * X500NameStyle. It should be easily extendible to support implementing the
+ * desired X500NameStyle.
+ */
+public abstract class AbstractX500NameStyle
+ implements X500NameStyle
+{
+
+ /**
+ * Tool function to shallow copy a Hashtable.
+ *
+ * @param paramsMap table to copy
+ * @return the copy of the table
+ */
+ public static Hashtable copyHashTable(Hashtable paramsMap)
+ {
+ Hashtable newTable = new Hashtable();
+
+ Enumeration keys = paramsMap.keys();
+ while (keys.hasMoreElements())
+ {
+ Object key = keys.nextElement();
+ newTable.put(key, paramsMap.get(key));
+ }
+
+ return newTable;
+ }
+
+ private int calcHashCode(ASN1Encodable enc)
+ {
+ String value = IETFUtils.valueToString(enc);
+ value = IETFUtils.canonicalize(value);
+ return value.hashCode();
+ }
+
+ public int calculateHashCode(X500Name name)
+ {
+ int hashCodeValue = 0;
+ RDN[] rdns = name.getRDNs();
+
+ // this needs to be order independent, like equals
+ for (int i = 0; i != rdns.length; i++)
+ {
+ if (rdns[i].isMultiValued())
+ {
+ AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues();
+
+ for (int j = 0; j != atv.length; j++)
+ {
+ hashCodeValue ^= atv[j].getType().hashCode();
+ hashCodeValue ^= calcHashCode(atv[j].getValue());
+ }
+ }
+ else
+ {
+ hashCodeValue ^= rdns[i].getFirst().getType().hashCode();
+ hashCodeValue ^= calcHashCode(rdns[i].getFirst().getValue());
+ }
+ }
+
+ return hashCodeValue;
+ }
+
+
+ /**
+ * For all string values starting with '#' is assumed, that these are
+ * already valid ASN.1 objects encoded in hex.
+ * <p/>
+ * All other string values are send to
+ * {@link AbstractX500NameStyle#encodeStringValue(ASN1ObjectIdentifier, String)}.
+ * <p/>
+ * Subclasses should overwrite
+ * {@link AbstractX500NameStyle#encodeStringValue(ASN1ObjectIdentifier, String)}
+ * to change the encoding of specific types.
+ */
+ public ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value)
+ {
+ if (value.length() != 0 && value.charAt(0) == '#')
+ {
+ try
+ {
+ return IETFUtils.valueFromHexString(value, 1);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("can't recode value for oid " + oid.getId());
+ }
+ }
+
+ if (value.length() != 0 && value.charAt(0) == '\\')
+ {
+ value = value.substring(1);
+ }
+
+ return encodeStringValue(oid, value);
+ }
+
+ /**
+ * Encoded every value into a UTF8String.
+ * <p/>
+ * Subclasses should overwrite
+ * this method to change the encoding of specific types.
+ *
+ * @param oid of the value
+ * @param value to encode
+ * @return a the value encoded into a ASN.1 object. Never returns <code>null</code>.
+ */
+ protected ASN1Encodable encodeStringValue(ASN1ObjectIdentifier oid, String value)
+ {
+ return new DERUTF8String(value);
+ }
+
+ public boolean areEqual(X500Name name1, X500Name name2)
+ {
+ RDN[] rdns1 = name1.getRDNs();
+ RDN[] rdns2 = name2.getRDNs();
+
+ if (rdns1.length != rdns2.length)
+ {
+ return false;
+ }
+
+ boolean reverse = false;
+
+ if (rdns1[0].getFirst() != null && rdns2[0].getFirst() != null)
+ {
+ reverse = !rdns1[0].getFirst().getType().equals(rdns2[0].getFirst().getType()); // guess forward
+ }
+
+ for (int i = 0; i != rdns1.length; i++)
+ {
+ if (!foundMatch(reverse, rdns1[i], rdns2))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private boolean foundMatch(boolean reverse, RDN rdn, RDN[] possRDNs)
+ {
+ if (reverse)
+ {
+ for (int i = possRDNs.length - 1; i >= 0; i--)
+ {
+ if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i]))
+ {
+ possRDNs[i] = null;
+ return true;
+ }
+ }
+ }
+ else
+ {
+ for (int i = 0; i != possRDNs.length; i++)
+ {
+ if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i]))
+ {
+ possRDNs[i] = null;
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ protected boolean rdnAreEqual(RDN rdn1, RDN rdn2)
+ {
+ return IETFUtils.rDNAreEqual(rdn1, rdn2);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java b/core/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java
index 68421821..dc1cc366 100644
--- a/core/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java
+++ b/core/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java
@@ -1,7 +1,5 @@
package org.bouncycastle.asn1.x500.style;
-import java.io.IOException;
-import java.util.Enumeration;
import java.util.Hashtable;
import org.bouncycastle.asn1.ASN1Encodable;
@@ -9,16 +7,14 @@ import org.bouncycastle.asn1.ASN1GeneralizedTime;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.DERPrintableString;
-import org.bouncycastle.asn1.DERUTF8String;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import org.bouncycastle.asn1.x500.AttributeTypeAndValue;
import org.bouncycastle.asn1.x500.RDN;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameStyle;
import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
public class BCStyle
- implements X500NameStyle
+ extends AbstractX500NameStyle
{
/**
* country code - StringType(SIZE(2))
@@ -286,41 +282,25 @@ public class BCStyle
defaultLookUp = copyHashTable(DefaultLookUp);
}
- public ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value)
- {
- if (value.length() != 0 && value.charAt(0) == '#')
+
+ @Override
+ protected ASN1Encodable encodeStringValue(ASN1ObjectIdentifier oid,
+ String value) {
+ if (oid.equals(EmailAddress) || oid.equals(DC))
{
- try
- {
- return IETFUtils.valueFromHexString(value, 1);
- }
- catch (IOException e)
- {
- throw new RuntimeException("can't recode value for oid " + oid.getId());
- }
+ return new DERIA5String(value);
}
- else
+ else if (oid.equals(DATE_OF_BIRTH)) // accept time string as well as # (for compatibility)
{
- if (value.length() != 0 && value.charAt(0) == '\\')
- {
- value = value.substring(1);
- }
- if (oid.equals(EmailAddress) || oid.equals(DC))
- {
- return new DERIA5String(value);
- }
- else if (oid.equals(DATE_OF_BIRTH)) // accept time string as well as # (for compatibility)
- {
- return new ASN1GeneralizedTime(value);
- }
- else if (oid.equals(C) || oid.equals(SN) || oid.equals(DN_QUALIFIER)
- || oid.equals(TELEPHONE_NUMBER))
- {
- return new DERPrintableString(value);
- }
+ return new ASN1GeneralizedTime(value);
}
-
- return new DERUTF8String(value);
+ else if (oid.equals(C) || oid.equals(SN) || oid.equals(DN_QUALIFIER)
+ || oid.equals(TELEPHONE_NUMBER))
+ {
+ return new DERPrintableString(value);
+ }
+
+ return super.encodeStringValue(oid, value);
}
public String oidToDisplayName(ASN1ObjectIdentifier oid)
@@ -338,109 +318,11 @@ public class BCStyle
return IETFUtils.decodeAttrName(attrName, defaultLookUp);
}
- public boolean areEqual(X500Name name1, X500Name name2)
- {
- RDN[] rdns1 = name1.getRDNs();
- RDN[] rdns2 = name2.getRDNs();
-
- if (rdns1.length != rdns2.length)
- {
- return false;
- }
-
- boolean reverse = false;
-
- if (rdns1[0].getFirst() != null && rdns2[0].getFirst() != null)
- {
- reverse = !rdns1[0].getFirst().getType().equals(rdns2[0].getFirst().getType()); // guess forward
- }
-
- for (int i = 0; i != rdns1.length; i++)
- {
- if (!foundMatch(reverse, rdns1[i], rdns2))
- {
- return false;
- }
- }
-
- return true;
- }
-
- private boolean foundMatch(boolean reverse, RDN rdn, RDN[] possRDNs)
- {
- if (reverse)
- {
- for (int i = possRDNs.length - 1; i >= 0; i--)
- {
- if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i]))
- {
- possRDNs[i] = null;
- return true;
- }
- }
- }
- else
- {
- for (int i = 0; i != possRDNs.length; i++)
- {
- if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i]))
- {
- possRDNs[i] = null;
- return true;
- }
- }
- }
-
- return false;
- }
-
- protected boolean rdnAreEqual(RDN rdn1, RDN rdn2)
- {
- return IETFUtils.rDNAreEqual(rdn1, rdn2);
- }
-
public RDN[] fromString(String dirName)
{
return IETFUtils.rDNsFromString(dirName, this);
}
- public int calculateHashCode(X500Name name)
- {
- int hashCodeValue = 0;
- RDN[] rdns = name.getRDNs();
-
- // this needs to be order independent, like equals
- for (int i = 0; i != rdns.length; i++)
- {
- if (rdns[i].isMultiValued())
- {
- AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues();
-
- for (int j = 0; j != atv.length; j++)
- {
- hashCodeValue ^= atv[j].getType().hashCode();
- hashCodeValue ^= calcHashCode(atv[j].getValue());
- }
- }
- else
- {
- hashCodeValue ^= rdns[i].getFirst().getType().hashCode();
- hashCodeValue ^= calcHashCode(rdns[i].getFirst().getValue());
- }
- }
-
- return hashCodeValue;
- }
-
- private int calcHashCode(ASN1Encodable enc)
- {
- String value = IETFUtils.valueToString(enc);
-
- value = IETFUtils.canonicalize(value);
-
- return value.hashCode();
- }
-
public String toString(X500Name name)
{
StringBuffer buf = new StringBuffer();
@@ -465,17 +347,5 @@ public class BCStyle
return buf.toString();
}
- private static Hashtable copyHashTable(Hashtable paramsMap)
- {
- Hashtable newTable = new Hashtable();
- Enumeration keys = paramsMap.keys();
- while (keys.hasMoreElements())
- {
- Object key = keys.nextElement();
- newTable.put(key, paramsMap.get(key));
- }
-
- return newTable;
- }
}
diff --git a/core/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java b/core/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java
index 8c92257e..cc6a4281 100644
--- a/core/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java
+++ b/core/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java
@@ -1,21 +1,17 @@
package org.bouncycastle.asn1.x500.style;
-import java.io.IOException;
-import java.util.Enumeration;
import java.util.Hashtable;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.DERPrintableString;
-import org.bouncycastle.asn1.DERUTF8String;
-import org.bouncycastle.asn1.x500.AttributeTypeAndValue;
import org.bouncycastle.asn1.x500.RDN;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameStyle;
public class RFC4519Style
- implements X500NameStyle
+ extends AbstractX500NameStyle
{
public static final ASN1ObjectIdentifier businessCategory = new ASN1ObjectIdentifier("2.5.4.15");
public static final ASN1ObjectIdentifier c = new ASN1ObjectIdentifier("2.5.4.6");
@@ -179,37 +175,20 @@ public class RFC4519Style
defaultLookUp = copyHashTable(DefaultLookUp);
}
- public ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value)
- {
- if (value.length() != 0 && value.charAt(0) == '#')
+ @Override
+ protected ASN1Encodable encodeStringValue(ASN1ObjectIdentifier oid,
+ String value) {
+ if (oid.equals(dc))
{
- try
- {
- return IETFUtils.valueFromHexString(value, 1);
- }
- catch (IOException e)
- {
- throw new RuntimeException("can't recode value for oid " + oid.getId());
- }
+ return new DERIA5String(value);
}
- else
+ else if (oid.equals(c) || oid.equals(serialNumber) || oid.equals(dnQualifier)
+ || oid.equals(telephoneNumber))
{
- if (value.length() != 0 && value.charAt(0) == '\\')
- {
- value = value.substring(1);
- }
- if (oid.equals(dc))
- {
- return new DERIA5String(value);
- }
- else if (oid.equals(c) || oid.equals(serialNumber) || oid.equals(dnQualifier)
- || oid.equals(telephoneNumber))
- {
- return new DERPrintableString(value);
- }
+ return new DERPrintableString(value);
}
- return new DERUTF8String(value);
+ return super.encodeStringValue(oid, value);
}
public String oidToDisplayName(ASN1ObjectIdentifier oid)
@@ -227,67 +206,6 @@ public class RFC4519Style
return IETFUtils.decodeAttrName(attrName, defaultLookUp);
}
- public boolean areEqual(X500Name name1, X500Name name2)
- {
- RDN[] rdns1 = name1.getRDNs();
- RDN[] rdns2 = name2.getRDNs();
-
- if (rdns1.length != rdns2.length)
- {
- return false;
- }
-
- boolean reverse = false;
-
- if (rdns1[0].getFirst() != null && rdns2[0].getFirst() != null)
- {
- reverse = !rdns1[0].getFirst().getType().equals(rdns2[0].getFirst().getType()); // guess forward
- }
-
- for (int i = 0; i != rdns1.length; i++)
- {
- if (!foundMatch(reverse, rdns1[i], rdns2))
- {
- return false;
- }
- }
-
- return true;
- }
-
- private boolean foundMatch(boolean reverse, RDN rdn, RDN[] possRDNs)
- {
- if (reverse)
- {
- for (int i = possRDNs.length - 1; i >= 0; i--)
- {
- if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i]))
- {
- possRDNs[i] = null;
- return true;
- }
- }
- }
- else
- {
- for (int i = 0; i != possRDNs.length; i++)
- {
- if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i]))
- {
- possRDNs[i] = null;
- return true;
- }
- }
- }
-
- return false;
- }
-
- protected boolean rdnAreEqual(RDN rdn1, RDN rdn2)
- {
- return IETFUtils.rDNAreEqual(rdn1, rdn2);
- }
-
// parse backwards
public RDN[] fromString(String dirName)
{
@@ -302,43 +220,6 @@ public class RFC4519Style
return res;
}
- public int calculateHashCode(X500Name name)
- {
- int hashCodeValue = 0;
- RDN[] rdns = name.getRDNs();
-
- // this needs to be order independent, like equals
- for (int i = 0; i != rdns.length; i++)
- {
- if (rdns[i].isMultiValued())
- {
- AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues();
-
- for (int j = 0; j != atv.length; j++)
- {
- hashCodeValue ^= atv[j].getType().hashCode();
- hashCodeValue ^= calcHashCode(atv[j].getValue());
- }
- }
- else
- {
- hashCodeValue ^= rdns[i].getFirst().getType().hashCode();
- hashCodeValue ^= calcHashCode(rdns[i].getFirst().getValue());
- }
- }
-
- return hashCodeValue;
- }
-
- private int calcHashCode(ASN1Encodable enc)
- {
- String value = IETFUtils.valueToString(enc);
-
- value = IETFUtils.canonicalize(value);
-
- return value.hashCode();
- }
-
// convert in reverse
public String toString(X500Name name)
{
@@ -364,17 +245,5 @@ public class RFC4519Style
return buf.toString();
}
- private static Hashtable copyHashTable(Hashtable paramsMap)
- {
- Hashtable newTable = new Hashtable();
-
- Enumeration keys = paramsMap.keys();
- while (keys.hasMoreElements())
- {
- Object key = keys.nextElement();
- newTable.put(key, paramsMap.get(key));
- }
-
- return newTable;
- }
+
}
diff --git a/core/src/main/java/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java b/core/src/main/java/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java
index 2c8e3fcf..b7e52f22 100644
--- a/core/src/main/java/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java
+++ b/core/src/main/java/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java
@@ -6,7 +6,7 @@ package org.bouncycastle.asn1.x500.style;
* lightweight Java environment don't support classes like
* StringTokenizer.
*/
-class X500NameTokenizer
+public class X500NameTokenizer
{
private String value;
private int index;
diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java
index d250bf1e..bb90030c 100644
--- a/core/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java
+++ b/core/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java
@@ -8,7 +8,6 @@ import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DERNull;
-import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.DERSequence;
public class AlgorithmIdentifier
@@ -64,30 +63,6 @@ public class AlgorithmIdentifier
this.objectId = new ASN1ObjectIdentifier(objectId);
}
- /**
- * @deprecated use ASN1ObjectIdentifier
- * @param objectId
- */
- public AlgorithmIdentifier(
- DERObjectIdentifier objectId)
- {
- this.objectId = new ASN1ObjectIdentifier(objectId.getId());
- }
-
- /**
- * @deprecated use ASN1ObjectIdentifier
- * @param objectId
- * @param parameters
- */
- public AlgorithmIdentifier(
- DERObjectIdentifier objectId,
- ASN1Encodable parameters)
- {
- parametersDefined = true;
- this.objectId = new ASN1ObjectIdentifier(objectId.getId());
- this.parameters = parameters;
- }
-
public AlgorithmIdentifier(
ASN1ObjectIdentifier objectId,
ASN1Encodable parameters)
diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java b/core/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java
index 4a16bd4b..ba5ecf1f 100644
--- a/core/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java
+++ b/core/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java
@@ -9,7 +9,6 @@ import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1TaggedObject;
-import org.bouncycastle.asn1.DERBoolean;
import org.bouncycastle.asn1.DERSequence;
public class BasicConstraints
@@ -59,9 +58,9 @@ public class BasicConstraints
}
else
{
- if (seq.getObjectAt(0) instanceof DERBoolean)
+ if (seq.getObjectAt(0) instanceof ASN1Boolean)
{
- this.cA = DERBoolean.getInstance(seq.getObjectAt(0));
+ this.cA = ASN1Boolean.getInstance(seq.getObjectAt(0));
}
else
{
diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java b/core/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java
index f29284d5..93530571 100644
--- a/core/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java
+++ b/core/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java
@@ -2,11 +2,11 @@ package org.bouncycastle.asn1.x509;
import java.io.IOException;
+import org.bouncycastle.asn1.ASN1Boolean;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
-import org.bouncycastle.asn1.DERBoolean;
/**
* an object for the elements in the X.509 V3 extension block.
@@ -173,7 +173,7 @@ public class X509Extension
ASN1OctetString value;
public X509Extension(
- DERBoolean critical,
+ ASN1Boolean critical,
ASN1OctetString value)
{
this.critical = critical.isTrue();
diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java b/core/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java
index c72e3cc0..5b9ea9e1 100644
--- a/core/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java
+++ b/core/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java
@@ -4,6 +4,7 @@ import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
+import org.bouncycastle.asn1.ASN1Boolean;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
@@ -11,8 +12,6 @@ import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1TaggedObject;
-import org.bouncycastle.asn1.DERBoolean;
-import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.DERSequence;
/**
@@ -259,7 +258,7 @@ public class X509Extensions
if (s.size() == 3)
{
- extensions.put(s.getObjectAt(0), new X509Extension(DERBoolean.getInstance(s.getObjectAt(1)), ASN1OctetString.getInstance(s.getObjectAt(2))));
+ extensions.put(s.getObjectAt(0), new X509Extension(ASN1Boolean.getInstance(s.getObjectAt(1)), ASN1OctetString.getInstance(s.getObjectAt(2))));
}
else if (s.size() == 2)
{
@@ -369,17 +368,6 @@ public class X509Extensions
* @return the extension if it's present, null otherwise.
*/
public X509Extension getExtension(
- DERObjectIdentifier oid)
- {
- return (X509Extension)extensions.get(oid);
- }
-
- /**
- * @deprecated
- * @param oid
- * @return
- */
- public X509Extension getExtension(
ASN1ObjectIdentifier oid)
{
return (X509Extension)extensions.get(oid);
@@ -410,7 +398,7 @@ public class X509Extensions
if (ext.isCritical())
{
- v.add(DERBoolean.TRUE);
+ v.add(ASN1Boolean.TRUE);
}
v.add(ext.getValue());
diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java b/core/src/main/java/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java
index 468d1b96..589d512f 100644
--- a/core/src/main/java/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java
+++ b/core/src/main/java/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java
@@ -7,7 +7,6 @@ import java.util.Vector;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.DEROctetString;
/**
@@ -29,28 +28,6 @@ public class X509ExtensionsGenerator
}
/**
- * @deprecated use ASN1ObjectIdentifier
- */
- public void addExtension(
- DERObjectIdentifier oid,
- boolean critical,
- ASN1Encodable value)
- {
- addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value);
- }
-
- /**
- * @deprecated use ASN1ObjectIdentifier
- */
- public void addExtension(
- DERObjectIdentifier oid,
- boolean critical,
- byte[] value)
- {
- addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value);
- }
-
- /**
* Add an extension with the given oid and the passed in value to be included
* in the OCTET STRING associated with the extension.
*
diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java b/core/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java
index 6a97a48e..509111ad 100644
--- a/core/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java
+++ b/core/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java
@@ -1,5 +1,6 @@
package org.bouncycastle.asn1.x9;
+import java.math.BigInteger;
import java.util.Enumeration;
import org.bouncycastle.asn1.ASN1Encodable;
@@ -38,6 +39,29 @@ public class DHDomainParameters
+ obj.getClass().getName());
}
+ public DHDomainParameters(BigInteger p, BigInteger g, BigInteger q, BigInteger j,
+ DHValidationParms validationParms)
+ {
+ if (p == null)
+ {
+ throw new IllegalArgumentException("'p' cannot be null");
+ }
+ if (g == null)
+ {
+ throw new IllegalArgumentException("'g' cannot be null");
+ }
+ if (q == null)
+ {
+ throw new IllegalArgumentException("'q' cannot be null");
+ }
+
+ this.p = new ASN1Integer(p);
+ this.g = new ASN1Integer(g);
+ this.q = new ASN1Integer(q);
+ this.j = new ASN1Integer(j);
+ this.validationParms = validationParms;
+ }
+
public DHDomainParameters(ASN1Integer p, ASN1Integer g, ASN1Integer q, ASN1Integer j,
DHValidationParms validationParms)
{
diff --git a/core/src/main/java/org/bouncycastle/crypto/agreement/kdf/DHKEKGenerator.java b/core/src/main/java/org/bouncycastle/crypto/agreement/kdf/DHKEKGenerator.java
index 947bc5c4..55d8ba51 100644
--- a/core/src/main/java/org/bouncycastle/crypto/agreement/kdf/DHKEKGenerator.java
+++ b/core/src/main/java/org/bouncycastle/crypto/agreement/kdf/DHKEKGenerator.java
@@ -4,7 +4,7 @@ import java.io.IOException;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Encoding;
-import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERTaggedObject;
@@ -22,7 +22,7 @@ public class DHKEKGenerator
{
private final Digest digest;
- private DERObjectIdentifier algorithm;
+ private ASN1ObjectIdentifier algorithm;
private int keySize;
private byte[] z;
private byte[] partyAInfo;
diff --git a/core/src/main/java/org/bouncycastle/crypto/ec/CustomNamedCurves.java b/core/src/main/java/org/bouncycastle/crypto/ec/CustomNamedCurves.java
index 7da095b0..5bfe96d7 100644
--- a/core/src/main/java/org/bouncycastle/crypto/ec/CustomNamedCurves.java
+++ b/core/src/main/java/org/bouncycastle/crypto/ec/CustomNamedCurves.java
@@ -1,5 +1,6 @@
package org.bouncycastle.crypto.ec;
+import java.math.BigInteger;
import java.util.Enumeration;
import java.util.Hashtable;
@@ -9,11 +10,17 @@ 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.custom.djb.Curve25519;
import org.bouncycastle.math.ec.custom.sec.SecP192K1Curve;
import org.bouncycastle.math.ec.custom.sec.SecP192R1Curve;
+import org.bouncycastle.math.ec.custom.sec.SecP224K1Curve;
+import org.bouncycastle.math.ec.custom.sec.SecP224R1Curve;
import org.bouncycastle.math.ec.custom.sec.SecP256K1Curve;
import org.bouncycastle.math.ec.custom.sec.SecP256R1Curve;
+import org.bouncycastle.math.ec.custom.sec.SecP384R1Curve;
import org.bouncycastle.math.ec.custom.sec.SecP521R1Curve;
+import org.bouncycastle.math.ec.endo.GLVTypeBEndomorphism;
+import org.bouncycastle.math.ec.endo.GLVTypeBParameters;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
@@ -24,6 +31,38 @@ public class CustomNamedCurves
return curve;
}
+ private static ECCurve configureCurveGLV(ECCurve c, GLVTypeBParameters p)
+ {
+ return c.configure().setEndomorphism(new GLVTypeBEndomorphism(c, p)).create();
+ }
+
+ /*
+ * curve25519
+ */
+ static X9ECParametersHolder curve25519 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ byte[] S = null;
+ ECCurve curve = configureCurve(new Curve25519());
+
+ /*
+ * NOTE: Curve25519 was specified in Montgomery form. Rewriting in Weierstrass form
+ * involves substitution of variables, so the base-point x coordinate is 9 + (486662 / 3).
+ *
+ * The Curve25519 paper doesn't say which of the two possible y values the base
+ * point has. The choice here is guided by language in the Ed25519 paper.
+ *
+ * (The other possible y value is 5F51E65E475F794B1FE122D388B72EB36DC2B28192839E4DD6163A5D81312C14)
+ */
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD245A"
+ + "20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9"));
+
+ return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+ }
+ };
+
/*
* secp192k1
*/
@@ -32,7 +71,19 @@ public class CustomNamedCurves
protected X9ECParameters createParameters()
{
byte[] S = null;
- ECCurve curve = configureCurve(new SecP192K1Curve());
+ GLVTypeBParameters glv = new GLVTypeBParameters(
+ new BigInteger("bb85691939b869c1d087f601554b96b80cb4f55b35f433c2", 16),
+ new BigInteger("3d84f26c12238d7b4f3d516613c1759033b1a5800175d0b1", 16),
+ new BigInteger[]{
+ new BigInteger("71169be7330b3038edb025f1", 16),
+ new BigInteger("-b3fb3400dec5c4adceb8655c", 16) },
+ new BigInteger[]{
+ new BigInteger("12511cfe811d0f4e6bc688b4d", 16),
+ new BigInteger("71169be7330b3038edb025f1", 16) },
+ new BigInteger("1c45a6f9ccc2cc0e3b6c097c7", 16),
+ new BigInteger("2cfecd0037b1712b73ae19575", 16),
+ 194);
+ ECCurve curve = configureCurveGLV(new SecP192K1Curve(), glv);
ECPoint G = curve.decodePoint(Hex.decode("04"
+ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"
+ "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D"));
@@ -57,6 +108,50 @@ public class CustomNamedCurves
};
/*
+ * secp224k1
+ */
+ static X9ECParametersHolder secp224k1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ byte[] S = null;
+ GLVTypeBParameters glv = new GLVTypeBParameters(
+ new BigInteger("fe0e87005b4e83761908c5131d552a850b3f58b749c37cf5b84d6768", 16),
+ new BigInteger("60dcd2104c4cbc0be6eeefc2bdd610739ec34e317f9b33046c9e4788", 16),
+ new BigInteger[]{
+ new BigInteger("6b8cf07d4ca75c88957d9d670591", 16),
+ new BigInteger("-b8adf1378a6eb73409fa6c9c637d", 16) },
+ new BigInteger[]{
+ new BigInteger("1243ae1b4d71613bc9f780a03690e", 16),
+ new BigInteger("6b8cf07d4ca75c88957d9d670591", 16) },
+ new BigInteger("35c6783ea653ae444abeceb382c82", 16),
+ new BigInteger("5c56f89bc5375b9a04fd364e31bdd", 16),
+ 227);
+ ECCurve curve = configureCurveGLV(new SecP224K1Curve(), glv);
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"
+ + "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5"));
+ return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+ }
+ };
+
+ /*
+ * secp224r1
+ */
+ static X9ECParametersHolder secp224r1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ byte[] S = Hex.decode("BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5");
+ ECCurve curve = configureCurve(new SecP224R1Curve());
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"
+ + "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34"));
+ return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+ }
+ };
+
+ /*
* secp256k1
*/
static X9ECParametersHolder secp256k1 = new X9ECParametersHolder()
@@ -64,7 +159,19 @@ public class CustomNamedCurves
protected X9ECParameters createParameters()
{
byte[] S = null;
- ECCurve curve = configureCurve(new SecP256K1Curve());
+ GLVTypeBParameters glv = new GLVTypeBParameters(
+ new BigInteger("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee", 16),
+ new BigInteger("5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72", 16),
+ new BigInteger[]{
+ new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16),
+ new BigInteger("-e4437ed6010e88286f547fa90abfe4c3", 16) },
+ new BigInteger[]{
+ new BigInteger("114ca50f7a8e2f3f657c1108d9d44cfd8", 16),
+ new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16) },
+ new BigInteger("c21b48869f51af37a1b243924a13ac55", 16),
+ new BigInteger("3910dfb58043a20a1bd51fea42aff9311", 16),
+ 258);
+ ECCurve curve = configureCurveGLV(new SecP256K1Curve(), glv);
ECPoint G = curve.decodePoint(Hex.decode("04"
+ "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
+ "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"));
@@ -89,6 +196,22 @@ public class CustomNamedCurves
};
/*
+ * secp384r1
+ */
+ static X9ECParametersHolder secp384r1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ byte[] S = Hex.decode("A335926AA319A27A1D00896A6773A4827ACDAC73");
+ ECCurve curve = configureCurve(new SecP384R1Curve());
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7"
+ + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F"));
+ return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+ }
+ };
+
+ /*
* secp521r1
*/
static X9ECParametersHolder secp521r1 = new X9ECParametersHolder()
@@ -104,34 +227,55 @@ public class CustomNamedCurves
}
};
- static final Hashtable objIds = new Hashtable();
- static final Hashtable curves = new Hashtable();
- static final Hashtable names = new Hashtable();
+ static final Hashtable nameToCurve = new Hashtable();
+ static final Hashtable nameToOID = new Hashtable();
+ static final Hashtable oidToCurve = new Hashtable();
+ static final Hashtable oidToName = new Hashtable();
- static void defineCurve(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder)
+ static void defineCurve(String name, X9ECParametersHolder holder)
{
- objIds.put(name, oid);
- names.put(oid, name);
- curves.put(oid, holder);
+ nameToCurve.put(name, holder);
+ }
+
+ static void defineCurveWithOID(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder)
+ {
+ nameToCurve.put(name, holder);
+ nameToOID.put(name, oid);
+ oidToName.put(oid, name);
+ oidToCurve.put(oid, holder);
+ }
+
+ static void defineCurveAlias(String alias, ASN1ObjectIdentifier oid)
+ {
+ alias = Strings.toLowerCase(alias);
+ nameToOID.put(alias, oid);
+ nameToCurve.put(alias, oidToCurve.get(oid));
}
static
{
- defineCurve("secp192k1", SECObjectIdentifiers.secp192k1, secp192k1);
- defineCurve("secp192r1", SECObjectIdentifiers.secp192r1, secp192r1);
- defineCurve("secp256k1", SECObjectIdentifiers.secp256k1, secp256k1);
- defineCurve("secp256r1", SECObjectIdentifiers.secp256r1, secp256r1);
- defineCurve("secp521r1", SECObjectIdentifiers.secp521r1, secp521r1);
+ defineCurve("curve25519", curve25519);
+
+ defineCurveWithOID("secp192k1", SECObjectIdentifiers.secp192k1, secp192k1);
+ defineCurveWithOID("secp192r1", SECObjectIdentifiers.secp192r1, secp192r1);
+ defineCurveWithOID("secp224k1", SECObjectIdentifiers.secp224k1, secp224k1);
+ defineCurveWithOID("secp224r1", SECObjectIdentifiers.secp224r1, secp224r1);
+ defineCurveWithOID("secp256k1", SECObjectIdentifiers.secp256k1, secp256k1);
+ defineCurveWithOID("secp256r1", SECObjectIdentifiers.secp256r1, secp256r1);
+ defineCurveWithOID("secp384r1", SECObjectIdentifiers.secp384r1, secp384r1);
+ defineCurveWithOID("secp521r1", SECObjectIdentifiers.secp521r1, secp521r1);
- objIds.put(Strings.toLowerCase("P-192"), SECObjectIdentifiers.secp192r1);
- objIds.put(Strings.toLowerCase("P-256"), SECObjectIdentifiers.secp256r1);
- objIds.put(Strings.toLowerCase("P-521"), SECObjectIdentifiers.secp521r1);
+ defineCurveAlias("P-192", SECObjectIdentifiers.secp192r1);
+ defineCurveAlias("P-224", SECObjectIdentifiers.secp224r1);
+ defineCurveAlias("P-256", SECObjectIdentifiers.secp256r1);
+ defineCurveAlias("P-384", SECObjectIdentifiers.secp384r1);
+ defineCurveAlias("P-521", SECObjectIdentifiers.secp521r1);
}
public static X9ECParameters getByName(String name)
{
- ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name));
- return oid == null ? null : getByOID(oid);
+ X9ECParametersHolder holder = (X9ECParametersHolder)nameToCurve.get(Strings.toLowerCase(name));
+ return holder == null ? null : holder.getParameters();
}
/**
@@ -143,7 +287,7 @@ public class CustomNamedCurves
*/
public static X9ECParameters getByOID(ASN1ObjectIdentifier oid)
{
- X9ECParametersHolder holder = (X9ECParametersHolder)curves.get(oid);
+ X9ECParametersHolder holder = (X9ECParametersHolder)oidToCurve.get(oid);
return holder == null ? null : holder.getParameters();
}
@@ -155,7 +299,7 @@ public class CustomNamedCurves
*/
public static ASN1ObjectIdentifier getOID(String name)
{
- return (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name));
+ return (ASN1ObjectIdentifier)nameToOID.get(Strings.toLowerCase(name));
}
/**
@@ -163,7 +307,7 @@ public class CustomNamedCurves
*/
public static String getName(ASN1ObjectIdentifier oid)
{
- return (String)names.get(oid);
+ return (String)oidToName.get(oid);
}
/**
@@ -171,6 +315,6 @@ public class CustomNamedCurves
*/
public static Enumeration getNames()
{
- return objIds.keys();
+ return nameToCurve.keys();
}
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/ec/ECElGamalEncryptor.java b/core/src/main/java/org/bouncycastle/crypto/ec/ECElGamalEncryptor.java
index a5296830..48fc0467 100644
--- a/core/src/main/java/org/bouncycastle/crypto/ec/ECElGamalEncryptor.java
+++ b/core/src/main/java/org/bouncycastle/crypto/ec/ECElGamalEncryptor.java
@@ -67,7 +67,7 @@ public class ECElGamalEncryptor
ECDomainParameters ec = key.getParameters();
BigInteger k = ECUtil.generateK(ec.getN(), random);
- ECMultiplier basePointMultiplier = new FixedPointCombMultiplier();
+ ECMultiplier basePointMultiplier = createBasePointMultiplier();
ECPoint[] gamma_phi = new ECPoint[]{
basePointMultiplier.multiply(ec.getG(), k),
@@ -78,4 +78,9 @@ public class ECElGamalEncryptor
return new ECPair(gamma_phi[0], gamma_phi[1]);
}
+
+ protected ECMultiplier createBasePointMultiplier()
+ {
+ return new FixedPointCombMultiplier();
+ }
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/ec/ECFixedTransform.java b/core/src/main/java/org/bouncycastle/crypto/ec/ECFixedTransform.java
index 02f5ca37..2c6a920b 100644
--- a/core/src/main/java/org/bouncycastle/crypto/ec/ECFixedTransform.java
+++ b/core/src/main/java/org/bouncycastle/crypto/ec/ECFixedTransform.java
@@ -58,7 +58,7 @@ public class ECFixedTransform
ECDomainParameters ec = key.getParameters();
BigInteger n = ec.getN();
- ECMultiplier basePointMultiplier = new FixedPointCombMultiplier();
+ ECMultiplier basePointMultiplier = createBasePointMultiplier();
BigInteger k = this.k.mod(n);
ECPoint[] gamma_phi = new ECPoint[]{
@@ -80,4 +80,9 @@ public class ECFixedTransform
{
return k;
}
+
+ protected ECMultiplier createBasePointMultiplier()
+ {
+ return new FixedPointCombMultiplier();
+ }
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/ec/ECNewPublicKeyTransform.java b/core/src/main/java/org/bouncycastle/crypto/ec/ECNewPublicKeyTransform.java
index 9f7a0bf1..112d20c1 100644
--- a/core/src/main/java/org/bouncycastle/crypto/ec/ECNewPublicKeyTransform.java
+++ b/core/src/main/java/org/bouncycastle/crypto/ec/ECNewPublicKeyTransform.java
@@ -68,7 +68,7 @@ public class ECNewPublicKeyTransform
ECDomainParameters ec = key.getParameters();
BigInteger n = ec.getN();
- ECMultiplier basePointMultiplier = new FixedPointCombMultiplier();
+ ECMultiplier basePointMultiplier = createBasePointMultiplier();
BigInteger k = ECUtil.generateK(n, random);
ECPoint[] gamma_phi = new ECPoint[]{
@@ -80,4 +80,9 @@ public class ECNewPublicKeyTransform
return new ECPair(gamma_phi[0], gamma_phi[1]);
}
+
+ protected ECMultiplier createBasePointMultiplier()
+ {
+ return new FixedPointCombMultiplier();
+ }
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/ec/ECNewRandomnessTransform.java b/core/src/main/java/org/bouncycastle/crypto/ec/ECNewRandomnessTransform.java
index c146a0fb..7bfc0b30 100644
--- a/core/src/main/java/org/bouncycastle/crypto/ec/ECNewRandomnessTransform.java
+++ b/core/src/main/java/org/bouncycastle/crypto/ec/ECNewRandomnessTransform.java
@@ -73,7 +73,7 @@ public class ECNewRandomnessTransform
ECDomainParameters ec = key.getParameters();
BigInteger n = ec.getN();
- ECMultiplier basePointMultiplier = new FixedPointCombMultiplier();
+ ECMultiplier basePointMultiplier = createBasePointMultiplier();
BigInteger k = ECUtil.generateK(n, random);
ECPoint[] gamma_phi = new ECPoint[]{
@@ -97,4 +97,9 @@ public class ECNewRandomnessTransform
{
return lastK;
}
+
+ protected ECMultiplier createBasePointMultiplier()
+ {
+ return new FixedPointCombMultiplier();
+ }
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/IDEAEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/IDEAEngine.java
index fdf3f6d3..08cf738e 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/IDEAEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/IDEAEngine.java
@@ -10,22 +10,12 @@ import org.bouncycastle.crypto.params.KeyParameter;
* A class that provides a basic International Data Encryption Algorithm (IDEA) engine.
* <p>
* This implementation is based on the "HOWTO: INTERNATIONAL DATA ENCRYPTION ALGORITHM"
- * implementation summary by Fauzan Mirza (F.U.Mirza@sheffield.ac.uk). (baring 1 typo at the
+ * implementation summary by Fauzan Mirza (F.U.Mirza@sheffield.ac.uk). (barring 1 typo at the
* end of the mulinv function!).
* <p>
* It can be found at ftp://ftp.funet.fi/pub/crypt/cryptography/symmetric/idea/
* <p>
- * Note 1: This algorithm is patented in the USA, Japan, and Europe including
- * at least Austria, France, Germany, Italy, Netherlands, Spain, Sweden, Switzerland
- * and the United Kingdom. Non-commercial use is free, however any commercial
- * products are liable for royalties. Please see
- * <a href="http://www.mediacrypt.com">www.mediacrypt.com</a> for
- * further details. This announcement has been included at the request of
- * the patent holders.
- * <p>
- * Note 2: Due to the requests concerning the above, this algorithm is now only
- * included in the extended Bouncy Castle provider and JCE signed jars. It is
- * not included in the default distributions.
+ * Note: This algorithm was patented in the USA, Japan and Europe. These patents expired in 2011/2012.
*/
public class IDEAEngine
implements BlockCipher
diff --git a/core/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java b/core/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java
index e0d86fc3..d395d5d3 100644
--- a/core/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java
+++ b/core/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java
@@ -19,7 +19,6 @@ class DHKeyGeneratorHelper
BigInteger calculatePrivate(DHParameters dhParams, SecureRandom random)
{
- BigInteger p = dhParams.getP();
int limit = dhParams.getL();
if (limit != 0)
@@ -34,12 +33,12 @@ class DHKeyGeneratorHelper
min = ONE.shiftLeft(m - 1);
}
- BigInteger max = p.subtract(TWO);
BigInteger q = dhParams.getQ();
- if (q != null)
+ if (q == null)
{
- max = q.subtract(TWO);
+ q = dhParams.getP();
}
+ BigInteger max = q.subtract(TWO);
return BigIntegers.createRandomInRange(min, max, random);
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java
index 38807a4c..1bae4638 100644
--- a/core/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java
+++ b/core/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java
@@ -11,6 +11,7 @@ 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.ECMultiplier;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.math.ec.FixedPointCombMultiplier;
@@ -50,10 +51,15 @@ public class ECKeyPairGenerator
}
while (d.equals(ZERO) || (d.compareTo(n) >= 0));
- ECPoint Q = new FixedPointCombMultiplier().multiply(params.getG(), d);
+ ECPoint Q = createBasePointMultiplier().multiply(params.getG(), d);
return new AsymmetricCipherKeyPair(
new ECPublicKeyParameters(Q, params),
new ECPrivateKeyParameters(d, params));
}
+
+ protected ECMultiplier createBasePointMultiplier()
+ {
+ return new FixedPointCombMultiplier();
+ }
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/io/CipherIOException.java b/core/src/main/java/org/bouncycastle/crypto/io/CipherIOException.java
new file mode 100644
index 00000000..beeb60bc
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/crypto/io/CipherIOException.java
@@ -0,0 +1,26 @@
+package org.bouncycastle.crypto.io;
+
+import java.io.IOException;
+
+/**
+ * {@link IOException} wrapper around an exception indicating a problem with the use of a cipher.
+ */
+public class CipherIOException
+ extends IOException
+{
+ private static final long serialVersionUID = 1L;
+
+ private final Throwable cause;
+
+ public CipherIOException(String message, Throwable cause)
+ {
+ super(message);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+} \ No newline at end of file
diff --git a/core/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java b/core/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java
index 38ebcb0c..11cd903b 100644
--- a/core/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java
+++ b/core/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java
@@ -162,7 +162,7 @@ public class CipherInputStream
/**
* Reads data from the underlying stream and processes it with the cipher until the cipher
* outputs data, and returns the next available byte.
- * <p>
+ * <p/>
* If the underlying stream is exhausted by this call, the cipher will be finalised.
*
* @throws IOException if there was an error closing the input stream.
@@ -186,7 +186,7 @@ public class CipherInputStream
/**
* Reads data from the underlying stream and processes it with the cipher until the cipher
* outputs data, and then returns up to <code>b.length</code> bytes in the provided array.
- * <p>
+ * <p/>
* If the underlying stream is exhausted by this call, the cipher will be finalised.
*
* @param b the buffer into which the data is read.
@@ -206,7 +206,7 @@ public class CipherInputStream
/**
* Reads data from the underlying stream and processes it with the cipher until the cipher
* outputs data, and then returns up to <code>len</code> bytes in the provided array.
- * <p>
+ * <p/>
* If the underlying stream is exhausted by this call, the cipher will be finalised.
*
* @param b the buffer into which the data is read.
diff --git a/core/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java b/core/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java
index 4b68adfd..17e7f362 100644
--- a/core/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java
+++ b/core/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java
@@ -118,7 +118,7 @@ public class CipherOutputStream
int len)
throws IOException
{
- ensureCapacity(len);
+ ensureCapacity(len, false);
if (bufferedBlockCipher != null)
{
@@ -149,24 +149,35 @@ public class CipherOutputStream
/**
* Ensure the ciphertext buffer has space sufficient to accept an upcoming output.
*
- * @param outputSize the size of the pending update.
+ * @param updateSize the size of the pending update.
+ * @param <code>true</code> iff this the cipher is to be finalised.
*/
- private void ensureCapacity(int outputSize)
+ private void ensureCapacity(int updateSize, boolean finalOutput)
{
- // This overestimates buffer on updates for AEAD/padded, but keeps it simple.
- int bufLen;
- if (bufferedBlockCipher != null)
+ int bufLen = updateSize;
+ if (finalOutput)
{
- bufLen = bufferedBlockCipher.getOutputSize(outputSize);
- }
- else if (aeadBlockCipher != null)
- {
- bufLen = aeadBlockCipher.getOutputSize(outputSize);
+ if (bufferedBlockCipher != null)
+ {
+ bufLen = bufferedBlockCipher.getOutputSize(updateSize);
+ }
+ else if (aeadBlockCipher != null)
+ {
+ bufLen = aeadBlockCipher.getOutputSize(updateSize);
+ }
}
else
{
- bufLen = outputSize;
+ if (bufferedBlockCipher != null)
+ {
+ bufLen = bufferedBlockCipher.getUpdateOutputSize(updateSize);
+ }
+ else if (aeadBlockCipher != null)
+ {
+ bufLen = aeadBlockCipher.getUpdateOutputSize(updateSize);
+ }
}
+
if ((buf == null) || (buf.length < bufLen))
{
buf = new byte[bufLen];
@@ -212,7 +223,7 @@ public class CipherOutputStream
public void close()
throws IOException
{
- ensureCapacity(0);
+ ensureCapacity(0, true);
IOException error = null;
try
{
@@ -241,7 +252,7 @@ public class CipherOutputStream
}
catch (Exception e)
{
- error = new IOException("Error closing stream: " + e);
+ error = new CipherIOException("Error closing stream: ", e);
}
try
diff --git a/core/src/main/java/org/bouncycastle/crypto/io/InvalidCipherTextIOException.java b/core/src/main/java/org/bouncycastle/crypto/io/InvalidCipherTextIOException.java
index b601d4c1..46561c67 100644
--- a/core/src/main/java/org/bouncycastle/crypto/io/InvalidCipherTextIOException.java
+++ b/core/src/main/java/org/bouncycastle/crypto/io/InvalidCipherTextIOException.java
@@ -8,21 +8,12 @@ import java.io.IOException;
* expose invalid ciphertext errors.
*/
public class InvalidCipherTextIOException
- extends IOException
+ extends CipherIOException
{
private static final long serialVersionUID = 1L;
- private final Throwable cause;
-
public InvalidCipherTextIOException(String message, Throwable cause)
{
- super(message);
-
- this.cause = cause;
- }
-
- public Throwable getCause()
- {
- return cause;
+ super(message, cause);
}
} \ No newline at end of file
diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java b/core/src/main/java/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java
index 746d26ca..517acfb1 100755
--- a/core/src/main/java/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java
+++ b/core/src/main/java/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java
@@ -123,7 +123,7 @@ public class ECIESKeyEncapsulation
// Compute the static-ephemeral key agreement
BigInteger rPrime = CofactorMode ? r.multiply(h).mod(n) : r;
- ECMultiplier basePointMultiplier = new FixedPointCombMultiplier();
+ ECMultiplier basePointMultiplier = createBasePointMultiplier();
ECPoint[] ghTilde = new ECPoint[]{
basePointMultiplier.multiply(ecParams.getG(), r),
@@ -236,4 +236,9 @@ public class ECIESKeyEncapsulation
{
return decrypt(in, 0, in.length, keyLen);
}
+
+ protected ECMultiplier createBasePointMultiplier()
+ {
+ return new FixedPointCombMultiplier();
+ }
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/macs/SipHash.java b/core/src/main/java/org/bouncycastle/crypto/macs/SipHash.java
index 5a4845ca..35079aba 100644
--- a/core/src/main/java/org/bouncycastle/crypto/macs/SipHash.java
+++ b/core/src/main/java/org/bouncycastle/crypto/macs/SipHash.java
@@ -5,7 +5,6 @@ import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.Mac;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.util.Pack;
-import org.bouncycastle.util.Arrays;
/**
* Implementation of SipHash as specified in "SipHash: a fast short-input PRF", by Jean-Philippe
@@ -19,14 +18,13 @@ import org.bouncycastle.util.Arrays;
public class SipHash
implements Mac
{
-
protected final int c, d;
protected long k0, k1;
- protected long v0, v1, v2, v3, v4;
+ protected long v0, v1, v2, v3;
- protected byte[] buf = new byte[8];
- protected int bufPos = 0;
+ protected long m = 0;
+ protected int wordPos = 0;
protected int wordCount = 0;
/**
@@ -34,7 +32,7 @@ public class SipHash
*/
public SipHash()
{
- // use of this confuses flow analyser on earlier JDKs.
+ // use of 'this' confuses the flow analyser on earlier JDKs.
this.c = 2;
this.d = 4;
}
@@ -84,12 +82,13 @@ public class SipHash
public void update(byte input)
throws IllegalStateException
{
+ m >>>= 8;
+ m |= (input & 0xffL) << 56;
- buf[bufPos] = input;
- if (++bufPos == buf.length)
+ if (++wordPos == 8)
{
processMessageWord();
- bufPos = 0;
+ wordPos = 0;
}
}
@@ -97,14 +96,41 @@ public class SipHash
throws DataLengthException,
IllegalStateException
{
-
- for (int i = 0; i < length; ++i)
+ int i = 0, fullWords = length & ~7;
+ if (wordPos == 0)
{
- buf[bufPos] = input[offset + i];
- if (++bufPos == buf.length)
+ for (; i < fullWords; i += 8)
{
+ m = Pack.littleEndianToLong(input, offset + i);
processMessageWord();
- bufPos = 0;
+ }
+ for (; i < length; ++i)
+ {
+ m >>>= 8;
+ m |= (input[offset + i] & 0xffL) << 56;
+ }
+ wordPos = length - fullWords;
+ }
+ else
+ {
+ int bits = wordPos << 3;
+ for (; i < fullWords; i += 8)
+ {
+ long n = Pack.littleEndianToLong(input, offset + i);
+ m = (n << bits) | (m >>> -bits);
+ processMessageWord();
+ m = n;
+ }
+ for (; i < length; ++i)
+ {
+ m >>>= 8;
+ m |= (input[offset + i] & 0xffL) << 56;
+
+ if (++wordPos == 8)
+ {
+ processMessageWord();
+ wordPos = 0;
+ }
}
}
}
@@ -112,12 +138,10 @@ public class SipHash
public long doFinal()
throws DataLengthException, IllegalStateException
{
-
- buf[7] = (byte)(((wordCount << 3) + bufPos) & 0xff);
- while (bufPos < 7)
- {
- buf[bufPos++] = 0;
- }
+ // NOTE: 2 distinct shifts to avoid "64-bit shift" when wordPos == 0
+ m >>>= ((7 - wordPos) << 3);
+ m >>>= 8;
+ m |= (((wordCount << 3) + wordPos) & 0xffL) << 56;
processMessageWord();
@@ -135,7 +159,6 @@ public class SipHash
public int doFinal(byte[] out, int outOff)
throws DataLengthException, IllegalStateException
{
-
long result = doFinal();
Pack.longToLittleEndian(result, out, outOff);
return 8;
@@ -143,22 +166,19 @@ public class SipHash
public void reset()
{
-
v0 = k0 ^ 0x736f6d6570736575L;
v1 = k1 ^ 0x646f72616e646f6dL;
v2 = k0 ^ 0x6c7967656e657261L;
v3 = k1 ^ 0x7465646279746573L;
- Arrays.fill(buf, (byte)0);
- bufPos = 0;
+ m = 0;
+ wordPos = 0;
wordCount = 0;
}
protected void processMessageWord()
{
-
++wordCount;
- long m = Pack.littleEndianToLong(buf, 0);
v3 ^= m;
applySipRounds(c);
v0 ^= m;
@@ -166,27 +186,31 @@ public class SipHash
protected void applySipRounds(int n)
{
+ long r0 = v0, r1 = v1, r2 = v2, r3 = v3;
+
for (int r = 0; r < n; ++r)
{
- v0 += v1;
- v2 += v3;
- v1 = rotateLeft(v1, 13);
- v3 = rotateLeft(v3, 16);
- v1 ^= v0;
- v3 ^= v2;
- v0 = rotateLeft(v0, 32);
- v2 += v1;
- v0 += v3;
- v1 = rotateLeft(v1, 17);
- v3 = rotateLeft(v3, 21);
- v1 ^= v2;
- v3 ^= v0;
- v2 = rotateLeft(v2, 32);
+ r0 += r1;
+ r2 += r3;
+ r1 = rotateLeft(r1, 13);
+ r3 = rotateLeft(r3, 16);
+ r1 ^= r0;
+ r3 ^= r2;
+ r0 = rotateLeft(r0, 32);
+ r2 += r1;
+ r0 += r3;
+ r1 = rotateLeft(r1, 17);
+ r3 = rotateLeft(r3, 21);
+ r1 ^= r2;
+ r3 ^= r0;
+ r2 = rotateLeft(r2, 32);
}
+
+ v0 = r0; v1 = r1; v2 = r2; v3 = r3;
}
protected static long rotateLeft(long x, int n)
{
- return (x << n) | (x >>> (64 - n));
+ return (x << n) | (x >>> -n);
}
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java
index 71b75954..3a2f73a3 100644
--- a/core/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java
+++ b/core/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java
@@ -7,6 +7,15 @@ import org.bouncycastle.crypto.InvalidCipherTextException;
/**
* A block cipher mode that includes authenticated encryption with a streaming mode and optional associated data.
+ * <p/>
+ * Implementations of this interface may operate in a packet mode (where all input data is buffered and
+ * processed dugin the call to {@link #doFinal(byte[], int)}), or in a streaming mode (where output data is
+ * incrementally produced with each call to {@link #processByte(byte, byte[], int)} or
+ * {@link #processBytes(byte[], int, int, byte[], int)}.
+ * <br/>This is important to consider during decryption: in a streaming mode, unauthenticated plaintext data
+ * may be output prior to the call to {@link #doFinal(byte[], int)} that results in an authentication
+ * failure. The higher level protocol utilising this cipher must ensure the plaintext data is handled
+ * appropriately until the end of data is reached and the entire ciphertext is authenticated.
* @see org.bouncycastle.crypto.params.AEADParameters
*/
public interface AEADBlockCipher
@@ -101,7 +110,11 @@ public interface AEADBlockCipher
/**
* return the size of the output buffer required for a processBytes
* an input of len bytes.
- *
+ * <p/>
+ * The returned size may be dependent on the initialisation of this cipher
+ * and may not be accurate once subsequent input data is processed - this method
+ * should be invoked immediately prior to input data being processed.
+ *
* @param len the length of the input.
* @return the space required to accommodate a call to processBytes
* with len bytes of input.
@@ -111,7 +124,12 @@ public interface AEADBlockCipher
/**
* return the size of the output buffer required for a processBytes plus a
* doFinal with an input of len bytes.
- *
+ * <p/>
+ * The returned size may be dependent on the initialisation of this cipher
+ * and may not be accurate once subsequent input data is processed - this method
+ * should be invoked immediately prior to a call to final processing of input data
+ * and a call to {@link #doFinal(byte[], int)}.
+ *
* @param len the length of the input.
* @return the space required to accommodate a call to processBytes and doFinal
* with len bytes of input.
diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java
index fef51fdb..7f870ca2 100644
--- a/core/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java
+++ b/core/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java
@@ -7,6 +7,7 @@ import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.OutputLengthException;
import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
import org.bouncycastle.crypto.params.AEADParameters;
import org.bouncycastle.crypto.params.ParametersWithIV;
@@ -42,7 +43,7 @@ public class CCMBlockCipher
this.cipher = c;
this.blockSize = c.getBlockSize();
this.macBlock = new byte[blockSize];
-
+
if (blockSize != 16)
{
throw new IllegalArgumentException("cipher required with a block size of 16.");
@@ -99,7 +100,7 @@ public class CCMBlockCipher
{
throw new IllegalArgumentException("nonce must have length from 7 to 13 octets");
}
-
+
reset();
}
@@ -130,6 +131,10 @@ public class CCMBlockCipher
public int processBytes(byte[] in, int inOff, int inLen, byte[] out, int outOff)
throws DataLengthException, IllegalStateException
{
+ if (in.length < (inOff + inLen))
+ {
+ throw new DataLengthException("Input buffer too short");
+ }
data.write(in, inOff, inLen);
return 0;
@@ -155,15 +160,15 @@ public class CCMBlockCipher
/**
* Returns a byte array containing the mac calculated as part of the
* last encrypt or decrypt operation.
- *
+ *
* @return the last mac calculated.
*/
public byte[] getMac()
{
byte[] mac = new byte[macSize];
-
+
System.arraycopy(macBlock, 0, mac, 0, mac.length);
-
+
return mac;
}
@@ -267,7 +272,7 @@ public class CCMBlockCipher
outputLen = inLen + macSize;
if (output.length < (outputLen + outOff))
{
- throw new DataLengthException("Output buffer too short.");
+ throw new OutputLengthException("Output buffer too short.");
}
calculateMac(in, inOff, inLen, macBlock);
@@ -300,7 +305,7 @@ public class CCMBlockCipher
outputLen = inLen - macSize;
if (output.length < (outputLen + outOff))
{
- throw new DataLengthException("Output buffer too short.");
+ throw new OutputLengthException("Output buffer too short.");
}
System.arraycopy(in, inOff + outputLen, macBlock, 0, macSize);
@@ -350,18 +355,18 @@ public class CCMBlockCipher
// build b0
//
byte[] b0 = new byte[16];
-
+
if (hasAssociatedText())
{
b0[0] |= 0x40;
}
-
+
b0[0] |= (((cMac.getMacSize() - 2) / 2) & 0x7) << 3;
b0[0] |= ((15 - nonce.length) - 1) & 0x7;
-
+
System.arraycopy(nonce, 0, b0, 1, nonce.length);
-
+
int q = dataLen;
int count = 1;
while (q > 0)
@@ -370,22 +375,22 @@ public class CCMBlockCipher
q >>>= 8;
count++;
}
-
+
cMac.update(b0, 0, b0.length);
-
+
//
// process associated text
//
if (hasAssociatedText())
{
int extra;
-
+
int textLength = getAssociatedTextLength();
if (textLength < ((1 << 16) - (1 << 8)))
{
cMac.update((byte)(textLength >> 8));
cMac.update((byte)textLength);
-
+
extra = 2;
}
else // can't go any higher than 2^32
@@ -396,7 +401,7 @@ public class CCMBlockCipher
cMac.update((byte)(textLength >> 16));
cMac.update((byte)(textLength >> 8));
cMac.update((byte)textLength);
-
+
extra = 6;
}
@@ -418,7 +423,7 @@ public class CCMBlockCipher
}
}
}
-
+
//
// add the text
//
diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java
index 8f740006..209d5cdb 100644
--- a/core/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java
+++ b/core/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java
@@ -5,22 +5,23 @@ import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.OutputLengthException;
import org.bouncycastle.crypto.macs.CMac;
import org.bouncycastle.crypto.params.AEADParameters;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.util.Arrays;
/**
- * A Two-Pass Authenticated-Encryption Scheme Optimized for Simplicity and
+ * A Two-Pass Authenticated-Encryption Scheme Optimized for Simplicity and
* Efficiency - by M. Bellare, P. Rogaway, D. Wagner.
- *
+ *
* http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf
- *
- * EAX is an AEAD scheme based on CTR and OMAC1/CMAC, that uses a single block
- * cipher to encrypt and authenticate data. It's on-line (the length of a
+ *
+ * EAX is an AEAD scheme based on CTR and OMAC1/CMAC, that uses a single block
+ * cipher to encrypt and authenticate data. It's on-line (the length of a
* message isn't needed to begin processing it), has good performances, it's
* simple and provably secure (provided the underlying block cipher is secure).
- *
+ *
* Of course, this implementations is NOT thread-safe.
*/
public class EAXBlockCipher
@@ -43,7 +44,7 @@ public class EAXBlockCipher
private byte[] nonceMac;
private byte[] associatedTextMac;
private byte[] macBlock;
-
+
private int macSize;
private byte[] bufBlock;
private int bufOff;
@@ -61,7 +62,6 @@ public class EAXBlockCipher
blockSize = cipher.getBlockSize();
mac = new CMac(cipher);
macBlock = new byte[blockSize];
- bufBlock = new byte[blockSize * 2];
associatedTextMac = new byte[mac.getMacSize()];
nonceMac = new byte[mac.getMacSize()];
this.cipher = new SICBlockCipher(cipher);
@@ -113,6 +113,8 @@ public class EAXBlockCipher
throw new IllegalArgumentException("invalid parameters passed to EAX");
}
+ bufBlock = new byte[forEncryption ? blockSize : (blockSize + macSize)];
+
byte[] tag = new byte[blockSize];
// Key reuse implemented in CBC mode of underlying CMac
@@ -123,9 +125,9 @@ public class EAXBlockCipher
mac.update(nonce, 0, nonce.length);
mac.doFinal(nonceMac, 0);
- // Same BlockCipher underlies this and the mac, so reuse last key on cipher
+ // Same BlockCipher underlies this and the mac, so reuse last key on cipher
cipher.init(true, new ParametersWithIV(null, nonceMac));
-
+
reset();
}
@@ -218,6 +220,11 @@ public class EAXBlockCipher
{
initCipher();
+ if (in.length < (inOff + len))
+ {
+ throw new DataLengthException("Input buffer too short");
+ }
+
int resultLen = 0;
for (int i = 0; i != len; i++)
@@ -240,12 +247,11 @@ public class EAXBlockCipher
if (forEncryption)
{
- if (out.length < (outOff + extra))
+ if (out.length < (outOff + extra + macSize))
{
- throw new DataLengthException("Output buffer too short");
+ throw new OutputLengthException("Output buffer too short");
}
cipher.processBlock(bufBlock, 0, tmp, 0);
- cipher.processBlock(bufBlock, blockSize, tmp, blockSize);
System.arraycopy(tmp, 0, out, outOff, extra);
@@ -261,6 +267,10 @@ public class EAXBlockCipher
}
else
{
+ if (out.length < (outOff + extra - macSize))
+ {
+ throw new OutputLengthException("Output buffer too short");
+ }
if (extra < macSize)
{
throw new InvalidCipherTextException("data too short");
@@ -270,7 +280,6 @@ public class EAXBlockCipher
mac.update(bufBlock, 0, extra - macSize);
cipher.processBlock(bufBlock, 0, tmp, 0);
- cipher.processBlock(bufBlock, blockSize, tmp, blockSize);
System.arraycopy(tmp, 0, out, outOff, extra - macSize);
}
@@ -329,6 +338,10 @@ public class EAXBlockCipher
if (bufOff == bufBlock.length)
{
+ if (out.length < (outOff + blockSize))
+ {
+ throw new OutputLengthException("Output buffer is too short");
+ }
// TODO Could move the processByte(s) calls to here
// initCipher();
@@ -347,8 +360,12 @@ public class EAXBlockCipher
size = cipher.processBlock(bufBlock, 0, out, outOff);
}
- bufOff = blockSize;
- System.arraycopy(bufBlock, blockSize, bufBlock, 0, blockSize);
+ bufOff = 0;
+ if (!forEncryption)
+ {
+ System.arraycopy(bufBlock, blockSize, bufBlock, 0, macSize);
+ bufOff = macSize;
+ }
return size;
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
index 9e617ec9..59c2eb36 100644
--- a/core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
+++ b/core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
@@ -4,6 +4,7 @@ import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.OutputLengthException;
import org.bouncycastle.crypto.modes.gcm.GCMExponentiator;
import org.bouncycastle.crypto.modes.gcm.GCMMultiplier;
import org.bouncycastle.crypto.modes.gcm.Tables1kGCMExponentiator;
@@ -23,7 +24,7 @@ public class GCMBlockCipher
{
private static final int BLOCK_SIZE = 16;
- // not final due to a compiler bug
+ // not final due to a compiler bug
private BlockCipher cipher;
private GCMMultiplier multiplier;
private GCMExponentiator exp;
@@ -102,7 +103,7 @@ public class GCMBlockCipher
throw new IllegalArgumentException("Invalid value for MAC size: " + macSizeBits);
}
- macSize = macSizeBits / 8;
+ macSize = macSizeBits / 8;
keyParam = param.getKey();
}
else if (params instanceof ParametersWithIV)
@@ -119,7 +120,7 @@ public class GCMBlockCipher
throw new IllegalArgumentException("invalid parameters passed to GCM");
}
- int bufLength = forEncryption ? BLOCK_SIZE : (BLOCK_SIZE + macSize);
+ int bufLength = forEncryption ? BLOCK_SIZE : (BLOCK_SIZE + macSize);
this.bufBlock = new byte[bufLength];
if (nonce == null || nonce.length < 1)
@@ -271,6 +272,10 @@ public class GCMBlockCipher
public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
throws DataLengthException
{
+ if (in.length < (inOff + len))
+ {
+ throw new DataLengthException("Input buffer too short");
+ }
int resultLen = 0;
for (int i = 0; i < len; ++i)
@@ -288,6 +293,10 @@ public class GCMBlockCipher
private void outputBlock(byte[] output, int offset)
{
+ if (output.length < (offset + BLOCK_SIZE))
+ {
+ throw new OutputLengthException("Output buffer too short");
+ }
if (totalLength == 0)
{
initCipher();
@@ -324,6 +333,10 @@ public class GCMBlockCipher
if (extra > 0)
{
+ if (out.length < (outOff + extra))
+ {
+ throw new OutputLengthException("Output buffer too short");
+ }
gCTRPartial(bufBlock, 0, extra, out, outOff);
}
@@ -390,6 +403,10 @@ public class GCMBlockCipher
if (forEncryption)
{
+ if (out.length < (outOff + extra + macSize))
+ {
+ throw new OutputLengthException("Output buffer too short");
+ }
// Append T to the message
System.arraycopy(macBlock, 0, out, outOff + bufOff, macSize);
resultLen += macSize;
diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java
index c3e8a96c..b942fbfb 100644
--- a/core/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java
+++ b/core/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java
@@ -6,6 +6,7 @@ import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.OutputLengthException;
import org.bouncycastle.crypto.params.AEADParameters;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
@@ -317,6 +318,10 @@ public class OCBBlockCipher
public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
throws DataLengthException
{
+ if (input.length < (inOff + len))
+ {
+ throw new DataLengthException("Input buffer too short");
+ }
int resultLen = 0;
for (int i = 0; i < len; ++i)
@@ -378,6 +383,10 @@ public class OCBBlockCipher
xor(mainBlock, Pad);
+ if (output.length < (outOff + mainBlockPos))
+ {
+ throw new OutputLengthException("Output buffer too short");
+ }
System.arraycopy(mainBlock, 0, output, outOff, mainBlockPos);
if (!forEncryption)
@@ -405,6 +414,10 @@ public class OCBBlockCipher
if (forEncryption)
{
+ if (output.length < (outOff + resultLen + macSize))
+ {
+ throw new OutputLengthException("Output buffer too short");
+ }
// Append tag to the message
System.arraycopy(macBlock, 0, output, outOff + resultLen, macSize);
resultLen += macSize;
@@ -456,6 +469,11 @@ public class OCBBlockCipher
protected void processMainBlock(byte[] output, int outOff)
{
+ if (output.length < (outOff + BLOCK_SIZE))
+ {
+ throw new OutputLengthException("Output buffer too short");
+ }
+
/*
* OCB-ENCRYPT/OCB-DECRYPT: Process any whole blocks
*/
diff --git a/core/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java
index ee3fd60e..d5928f70 100644
--- a/core/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java
+++ b/core/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java
@@ -125,7 +125,7 @@ public class PaddedBufferedBlockCipher
if (leftOver == 0)
{
- return total - buf.length;
+ return Math.max(0, total - buf.length);
}
return total - leftOver;
diff --git a/core/src/main/java/org/bouncycastle/crypto/prng/drbg/CTRSP800DRBG.java b/core/src/main/java/org/bouncycastle/crypto/prng/drbg/CTRSP800DRBG.java
index 84fe4a40..5ab8f469 100644
--- a/core/src/main/java/org/bouncycastle/crypto/prng/drbg/CTRSP800DRBG.java
+++ b/core/src/main/java/org/bouncycastle/crypto/prng/drbg/CTRSP800DRBG.java
@@ -310,6 +310,16 @@ public class CTRSP800DRBG
}
/**
+ * Return the block size (in bits) of the DRBG.
+ *
+ * @return the number of bits produced on each internal round of the DRBG.
+ */
+ public int getBlockSize()
+ {
+ return _V.length * 8;
+ }
+
+ /**
* Populate a passed in array with random data.
*
* @param output output array for generated bits.
diff --git a/core/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java b/core/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java
index a5607d5a..4e1b881d 100644
--- a/core/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java
+++ b/core/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java
@@ -149,6 +149,16 @@ public class DualECSP800DRBG
}
/**
+ * Return the block size (in bits) of the DRBG.
+ *
+ * @return the number of bits produced on each internal round of the DRBG.
+ */
+ public int getBlockSize()
+ {
+ return _outlen * 8;
+ }
+
+ /**
* Populate a passed in array with random data.
*
* @param output output array for generated bits.
diff --git a/core/src/main/java/org/bouncycastle/crypto/prng/drbg/HMacSP800DRBG.java b/core/src/main/java/org/bouncycastle/crypto/prng/drbg/HMacSP800DRBG.java
index 3ddeaac6..f4ef2c45 100644
--- a/core/src/main/java/org/bouncycastle/crypto/prng/drbg/HMacSP800DRBG.java
+++ b/core/src/main/java/org/bouncycastle/crypto/prng/drbg/HMacSP800DRBG.java
@@ -88,6 +88,16 @@ public class HMacSP800DRBG
}
/**
+ * Return the block size (in bits) of the DRBG.
+ *
+ * @return the number of bits produced on each round of the DRBG.
+ */
+ public int getBlockSize()
+ {
+ return _V.length * 8;
+ }
+
+ /**
* Populate a passed in array with random data.
*
* @param output output array for generated bits.
diff --git a/core/src/main/java/org/bouncycastle/crypto/prng/drbg/HashSP800DRBG.java b/core/src/main/java/org/bouncycastle/crypto/prng/drbg/HashSP800DRBG.java
index 4ed57163..d6ab4f53 100644
--- a/core/src/main/java/org/bouncycastle/crypto/prng/drbg/HashSP800DRBG.java
+++ b/core/src/main/java/org/bouncycastle/crypto/prng/drbg/HashSP800DRBG.java
@@ -88,6 +88,16 @@ public class HashSP800DRBG
}
/**
+ * Return the block size (in bits) of the DRBG.
+ *
+ * @return the number of bits produced on each internal round of the DRBG.
+ */
+ public int getBlockSize()
+ {
+ return _digest.getDigestSize() * 8;
+ }
+
+ /**
* Populate a passed in array with random data.
*
* @param output output array for generated bits.
@@ -226,12 +236,17 @@ public class HashSP800DRBG
private byte[] hash(byte[] input)
{
- _digest.update(input, 0, input.length);
byte[] hash = new byte[_digest.getDigestSize()];
- _digest.doFinal(hash, 0);
+ doHash(input, hash);
return hash;
}
-
+
+ private void doHash(byte[] input, byte[] output)
+ {
+ _digest.update(input, 0, input.length);
+ _digest.doFinal(output, 0);
+ }
+
// 1. m = [requested_number_of_bits / outlen]
// 2. data = V.
// 3. W = the Null string.
@@ -251,10 +266,10 @@ public class HashSP800DRBG
byte[] W = new byte[lengthInBits / 8];
- byte[] dig;
+ byte[] dig = new byte[_digest.getDigestSize()];
for (int i = 0; i <= m; i++)
{
- dig = hash(data);
+ doHash(data, dig);
int bytesToCopy = ((W.length - i * dig.length) > dig.length)
? dig.length
diff --git a/core/src/main/java/org/bouncycastle/crypto/prng/drbg/SP80090DRBG.java b/core/src/main/java/org/bouncycastle/crypto/prng/drbg/SP80090DRBG.java
index 93bc8945..7a919f31 100644
--- a/core/src/main/java/org/bouncycastle/crypto/prng/drbg/SP80090DRBG.java
+++ b/core/src/main/java/org/bouncycastle/crypto/prng/drbg/SP80090DRBG.java
@@ -6,6 +6,13 @@ package org.bouncycastle.crypto.prng.drbg;
public interface SP80090DRBG
{
/**
+ * Return the block size of the DRBG.
+ *
+ * @return the block size (in bits) produced by each round of the DRBG.
+ */
+ int getBlockSize();
+
+ /**
* Populate a passed in array with random data.
*
* @param output output array for generated bits.
diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/DSADigestSigner.java b/core/src/main/java/org/bouncycastle/crypto/signers/DSADigestSigner.java
index 2e4c48d3..684eb9c0 100644
--- a/core/src/main/java/org/bouncycastle/crypto/signers/DSADigestSigner.java
+++ b/core/src/main/java/org/bouncycastle/crypto/signers/DSADigestSigner.java
@@ -5,9 +5,9 @@ import java.math.BigInteger;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Primitive;
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;
@@ -142,8 +142,8 @@ public class DSADigestSigner
throws IOException
{
ASN1EncodableVector v = new ASN1EncodableVector();
- v.add(new DERInteger(r));
- v.add(new DERInteger(s));
+ v.add(new ASN1Integer(r));
+ v.add(new ASN1Integer(s));
return new DERSequence(v).getEncoded(ASN1Encoding.DER);
}
@@ -156,8 +156,8 @@ public class DSADigestSigner
return new BigInteger[]
{
- ((DERInteger)s.getObjectAt(0)).getValue(),
- ((DERInteger)s.getObjectAt(1)).getValue()
+ ((ASN1Integer)s.getObjectAt(0)).getValue(),
+ ((ASN1Integer)s.getObjectAt(1)).getValue()
};
}
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/DSTU4145Signer.java b/core/src/main/java/org/bouncycastle/crypto/signers/DSTU4145Signer.java
index 0a3ef37f..d0b893a6 100644
--- a/core/src/main/java/org/bouncycastle/crypto/signers/DSTU4145Signer.java
+++ b/core/src/main/java/org/bouncycastle/crypto/signers/DSTU4145Signer.java
@@ -75,7 +75,7 @@ public class DSTU4145Signer
BigInteger d = ((ECPrivateKeyParameters)key).getD();
- ECMultiplier basePointMultiplier = new FixedPointCombMultiplier();
+ ECMultiplier basePointMultiplier = createBasePointMultiplier();
do
{
@@ -135,6 +135,11 @@ public class DSTU4145Signer
return fieldElement2Integer(n, y).compareTo(r) == 0;
}
+ protected ECMultiplier createBasePointMultiplier()
+ {
+ return new FixedPointCombMultiplier();
+ }
+
/**
* Generates random integer such, than its bit length is less than that of n
*/
diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java b/core/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java
index 26fd588e..8ea2a5b9 100644
--- a/core/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java
+++ b/core/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java
@@ -97,7 +97,7 @@ public class ECDSASigner
BigInteger r, s;
- ECMultiplier basePointMultiplier = new FixedPointCombMultiplier();
+ ECMultiplier basePointMultiplier = createBasePointMultiplier();
// 5.3.2
do // generate s
@@ -169,7 +169,7 @@ public class ECDSASigner
return v.equals(r);
}
- private BigInteger calculateE(BigInteger n, byte[] message)
+ protected BigInteger calculateE(BigInteger n, byte[] message)
{
int log2n = n.bitLength();
int messageBitLength = message.length * 8;
@@ -181,4 +181,9 @@ public class ECDSASigner
}
return e;
}
+
+ protected ECMultiplier createBasePointMultiplier()
+ {
+ return new FixedPointCombMultiplier();
+ }
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/ECGOST3410Signer.java b/core/src/main/java/org/bouncycastle/crypto/signers/ECGOST3410Signer.java
index 47dc6bd9..0ef88762 100644
--- a/core/src/main/java/org/bouncycastle/crypto/signers/ECGOST3410Signer.java
+++ b/core/src/main/java/org/bouncycastle/crypto/signers/ECGOST3410Signer.java
@@ -1,155 +1,160 @@
-package org.bouncycastle.crypto.signers;
-
-import org.bouncycastle.crypto.CipherParameters;
-import org.bouncycastle.crypto.DSA;
-import org.bouncycastle.crypto.params.ECDomainParameters;
-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.ECMultiplier;
-import org.bouncycastle.math.ec.ECPoint;
-import org.bouncycastle.math.ec.FixedPointCombMultiplier;
-
-import java.math.BigInteger;
-import java.security.SecureRandom;
-
-/**
- * GOST R 34.10-2001 Signature Algorithm
- */
-public class ECGOST3410Signer
- implements 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;
- }
- }
-
- /**
- * generate a signature for the given message using the key we were
- * initialised with. For conventional GOST3410 the message should be a GOST3411
- * hash of the message of interest.
- *
- * @param message the message that will be verified later.
- */
- public BigInteger[] generateSignature(
- byte[] message)
- {
- byte[] mRev = new byte[message.length]; // conversion is little-endian
- for (int i = 0; i != mRev.length; i++)
- {
- mRev[i] = message[mRev.length - 1 - i];
- }
-
- BigInteger e = new BigInteger(1, mRev);
-
- ECDomainParameters ec = key.getParameters();
- BigInteger n = ec.getN();
- BigInteger d = ((ECPrivateKeyParameters)key).getD();
-
- BigInteger r, s;
-
- ECMultiplier basePointMultiplier = new FixedPointCombMultiplier();
-
- do // generate s
- {
- BigInteger k;
- do // generate r
- {
- do
- {
- k = new BigInteger(n.bitLength(), random);
- }
- while (k.equals(ECConstants.ZERO));
-
- ECPoint p = basePointMultiplier.multiply(ec.getG(), k).normalize();
-
- r = p.getAffineXCoord().toBigInteger().mod(n);
- }
- while (r.equals(ECConstants.ZERO));
-
- s = (k.multiply(e)).add(d.multiply(r)).mod(n);
- }
- while (s.equals(ECConstants.ZERO));
-
- return new BigInteger[]{ r, s };
- }
-
- /**
- * return true if the value r and s represent a GOST3410 signature for
- * the passed in message (for standard GOST3410 the message should be
- * a GOST3411 hash of the real message to be verified).
- */
- public boolean verifySignature(
- byte[] message,
- BigInteger r,
- BigInteger s)
- {
- byte[] mRev = new byte[message.length]; // conversion is little-endian
- for (int i = 0; i != mRev.length; i++)
- {
- mRev[i] = message[mRev.length - 1 - i];
- }
-
- BigInteger e = new BigInteger(1, mRev);
- BigInteger n = key.getParameters().getN();
-
- // r in the range [1,n-1]
- if (r.compareTo(ECConstants.ONE) < 0 || r.compareTo(n) >= 0)
- {
- return false;
- }
-
- // s in the range [1,n-1]
- if (s.compareTo(ECConstants.ONE) < 0 || s.compareTo(n) >= 0)
- {
- return false;
- }
-
- BigInteger v = e.modInverse(n);
-
- BigInteger z1 = s.multiply(v).mod(n);
- BigInteger z2 = (n.subtract(r)).multiply(v).mod(n);
-
- ECPoint G = key.getParameters().getG(); // P
- ECPoint Q = ((ECPublicKeyParameters)key).getQ();
-
- ECPoint point = ECAlgorithms.sumOfTwoMultiplies(G, z1, Q, z2).normalize();
-
- // components must be bogus.
- if (point.isInfinity())
- {
- return false;
- }
-
- BigInteger R = point.getAffineXCoord().toBigInteger().mod(n);
-
- return R.equals(r);
- }
-}
+package org.bouncycastle.crypto.signers;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DSA;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+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.ECMultiplier;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.ec.FixedPointCombMultiplier;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * GOST R 34.10-2001 Signature Algorithm
+ */
+public class ECGOST3410Signer
+ implements 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;
+ }
+ }
+
+ /**
+ * generate a signature for the given message using the key we were
+ * initialised with. For conventional GOST3410 the message should be a GOST3411
+ * hash of the message of interest.
+ *
+ * @param message the message that will be verified later.
+ */
+ public BigInteger[] generateSignature(
+ byte[] message)
+ {
+ byte[] mRev = new byte[message.length]; // conversion is little-endian
+ for (int i = 0; i != mRev.length; i++)
+ {
+ mRev[i] = message[mRev.length - 1 - i];
+ }
+
+ BigInteger e = new BigInteger(1, mRev);
+
+ ECDomainParameters ec = key.getParameters();
+ BigInteger n = ec.getN();
+ BigInteger d = ((ECPrivateKeyParameters)key).getD();
+
+ BigInteger r, s;
+
+ ECMultiplier basePointMultiplier = createBasePointMultiplier();
+
+ do // generate s
+ {
+ BigInteger k;
+ do // generate r
+ {
+ do
+ {
+ k = new BigInteger(n.bitLength(), random);
+ }
+ while (k.equals(ECConstants.ZERO));
+
+ ECPoint p = basePointMultiplier.multiply(ec.getG(), k).normalize();
+
+ r = p.getAffineXCoord().toBigInteger().mod(n);
+ }
+ while (r.equals(ECConstants.ZERO));
+
+ s = (k.multiply(e)).add(d.multiply(r)).mod(n);
+ }
+ while (s.equals(ECConstants.ZERO));
+
+ return new BigInteger[]{ r, s };
+ }
+
+ /**
+ * return true if the value r and s represent a GOST3410 signature for
+ * the passed in message (for standard GOST3410 the message should be
+ * a GOST3411 hash of the real message to be verified).
+ */
+ public boolean verifySignature(
+ byte[] message,
+ BigInteger r,
+ BigInteger s)
+ {
+ byte[] mRev = new byte[message.length]; // conversion is little-endian
+ for (int i = 0; i != mRev.length; i++)
+ {
+ mRev[i] = message[mRev.length - 1 - i];
+ }
+
+ BigInteger e = new BigInteger(1, mRev);
+ BigInteger n = key.getParameters().getN();
+
+ // r in the range [1,n-1]
+ if (r.compareTo(ECConstants.ONE) < 0 || r.compareTo(n) >= 0)
+ {
+ return false;
+ }
+
+ // s in the range [1,n-1]
+ if (s.compareTo(ECConstants.ONE) < 0 || s.compareTo(n) >= 0)
+ {
+ return false;
+ }
+
+ BigInteger v = e.modInverse(n);
+
+ BigInteger z1 = s.multiply(v).mod(n);
+ BigInteger z2 = (n.subtract(r)).multiply(v).mod(n);
+
+ ECPoint G = key.getParameters().getG(); // P
+ ECPoint Q = ((ECPublicKeyParameters)key).getQ();
+
+ ECPoint point = ECAlgorithms.sumOfTwoMultiplies(G, z1, Q, z2).normalize();
+
+ // components must be bogus.
+ if (point.isInfinity())
+ {
+ return false;
+ }
+
+ BigInteger R = point.getAffineXCoord().toBigInteger().mod(n);
+
+ return R.equals(r);
+ }
+
+ protected ECMultiplier createBasePointMultiplier()
+ {
+ return new FixedPointCombMultiplier();
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/ECNRSigner.java b/core/src/main/java/org/bouncycastle/crypto/signers/ECNRSigner.java
index 72bbbcb4..3e839163 100644
--- a/core/src/main/java/org/bouncycastle/crypto/signers/ECNRSigner.java
+++ b/core/src/main/java/org/bouncycastle/crypto/signers/ECNRSigner.java
@@ -101,7 +101,7 @@ public class ECNRSigner
// BigInteger Vx = tempPair.getPublic().getW().getAffineX();
ECPublicKeyParameters V = (ECPublicKeyParameters)tempPair.getPublic(); // get temp's public key
- BigInteger Vx = V.getQ().normalize().getAffineXCoord().toBigInteger(); // get the point's x coordinate
+ BigInteger Vx = V.getQ().getAffineXCoord().toBigInteger(); // get the point's x coordinate
r = Vx.add(e).mod(n);
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java b/core/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java
index aaae0645..f34b18c2 100644
--- a/core/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java
+++ b/core/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java
@@ -48,6 +48,8 @@ public class RSADigestSigner
oidMap.put("SHA-256", NISTObjectIdentifiers.id_sha256);
oidMap.put("SHA-384", NISTObjectIdentifiers.id_sha384);
oidMap.put("SHA-512", NISTObjectIdentifiers.id_sha512);
+ oidMap.put("SHA-512/224", NISTObjectIdentifiers.id_sha512_224);
+ oidMap.put("SHA-512/256", NISTObjectIdentifiers.id_sha512_256);
oidMap.put("MD2", PKCSObjectIdentifiers.md2);
oidMap.put("MD4", PKCSObjectIdentifiers.md4);
diff --git a/core/src/main/java/org/bouncycastle/crypto/util/Pack.java b/core/src/main/java/org/bouncycastle/crypto/util/Pack.java
index f0da0bf0..e121e0f9 100644
--- a/core/src/main/java/org/bouncycastle/crypto/util/Pack.java
+++ b/core/src/main/java/org/bouncycastle/crypto/util/Pack.java
@@ -114,6 +114,15 @@ public abstract class Pack
}
}
+ public static void littleEndianToInt(byte[] bs, int bOff, int[] ns, int nOff, int count)
+ {
+ for (int i = 0; i < count; ++i)
+ {
+ ns[nOff + i] = littleEndianToInt(bs, bOff);
+ bOff += 4;
+ }
+ }
+
public static byte[] intToLittleEndian(int n)
{
byte[] bs = new byte[4];
diff --git a/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java b/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
index 9e342ff9..92684ecc 100644
--- a/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
+++ b/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
@@ -9,7 +9,6 @@ import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Primitive;
-import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.oiw.ElGamalParameter;
import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.DHParameter;
@@ -101,7 +100,7 @@ public class PrivateKeyFactory
}
else if (algId.getAlgorithm().equals(OIWObjectIdentifiers.elGamalAlgorithm))
{
- ElGamalParameter params = new ElGamalParameter((ASN1Sequence)algId.getParameters());
+ ElGamalParameter params = ElGamalParameter.getInstance(algId.getParameters());
ASN1Integer derX = (ASN1Integer)keyInfo.parsePrivateKey();
return new ElGamalPrivateKeyParameters(derX.getValue(), new ElGamalParameters(
diff --git a/core/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java b/core/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
index b52d9bc0..cb130954 100644
--- a/core/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
+++ b/core/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
@@ -10,7 +10,6 @@ import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
-import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.oiw.ElGamalParameter;
import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
@@ -136,7 +135,7 @@ public class PublicKeyFactory
}
else if (algId.getAlgorithm().equals(OIWObjectIdentifiers.elGamalAlgorithm))
{
- ElGamalParameter params = new ElGamalParameter((ASN1Sequence)algId.getParameters());
+ ElGamalParameter params = ElGamalParameter.getInstance(algId.getParameters());
ASN1Integer derY = (ASN1Integer)keyInfo.parsePublicKey();
return new ElGamalPublicKeyParameters(derY.getValue(), new ElGamalParameters(
diff --git a/core/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java b/core/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java
index 63ba1ac1..2d4a9708 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java
@@ -2,6 +2,8 @@ package org.bouncycastle.math.ec;
import java.math.BigInteger;
+import org.bouncycastle.math.ec.endo.ECEndomorphism;
+import org.bouncycastle.math.ec.endo.GLVEndomorphism;
import org.bouncycastle.math.field.FiniteField;
import org.bouncycastle.math.field.PolynomialExtensionField;
@@ -47,6 +49,12 @@ public class ECAlgorithms
imported[i] = importPoint(c, ps[i]);
}
+ ECEndomorphism endomorphism = c.getEndomorphism();
+ if (endomorphism instanceof GLVEndomorphism)
+ {
+ return implSumOfMultipliesGLV(imported, ks, (GLVEndomorphism)endomorphism);
+ }
+
return implSumOfMultiplies(imported, ks);
}
@@ -66,6 +74,12 @@ public class ECAlgorithms
}
}
+ ECEndomorphism endomorphism = cp.getEndomorphism();
+ if (endomorphism instanceof GLVEndomorphism)
+ {
+ return implSumOfMultipliesGLV(new ECPoint[]{ P, Q }, new BigInteger[]{ a, b }, (GLVEndomorphism)endomorphism);
+ }
+
return implShamirsTrickWNaf(P, a, Q, b);
}
@@ -178,23 +192,58 @@ public class ECAlgorithms
static ECPoint implShamirsTrickWNaf(ECPoint P, BigInteger k,
ECPoint Q, BigInteger l)
{
+ boolean negK = k.signum() < 0, negL = l.signum() < 0;
+
+ k = k.abs();
+ l = l.abs();
+
int widthP = Math.max(2, Math.min(16, WNafUtil.getWindowSize(k.bitLength())));
int widthQ = Math.max(2, Math.min(16, WNafUtil.getWindowSize(l.bitLength())));
WNafPreCompInfo infoP = WNafUtil.precompute(P, widthP, true);
WNafPreCompInfo infoQ = WNafUtil.precompute(Q, widthQ, true);
- ECPoint[] preCompP = infoP.getPreComp();
- ECPoint[] preCompQ = infoQ.getPreComp();
- ECPoint[] preCompNegP = infoP.getPreCompNeg();
- ECPoint[] preCompNegQ = infoQ.getPreCompNeg();
+ ECPoint[] preCompP = negK ? infoP.getPreCompNeg() : infoP.getPreComp();
+ ECPoint[] preCompQ = negL ? infoQ.getPreCompNeg() : infoQ.getPreComp();
+ ECPoint[] preCompNegP = negK ? infoP.getPreComp() : infoP.getPreCompNeg();
+ ECPoint[] preCompNegQ = negL ? infoQ.getPreComp() : infoQ.getPreCompNeg();
byte[] wnafP = WNafUtil.generateWindowNaf(widthP, k);
byte[] wnafQ = WNafUtil.generateWindowNaf(widthQ, l);
+ return implShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ, preCompNegQ, wnafQ);
+ }
+
+ static ECPoint implShamirsTrickWNaf(ECPoint P, BigInteger k, ECPointMap pointMapQ, BigInteger l)
+ {
+ boolean negK = k.signum() < 0, negL = l.signum() < 0;
+
+ k = k.abs();
+ l = l.abs();
+
+ int width = Math.max(2, Math.min(16, WNafUtil.getWindowSize(Math.max(k.bitLength(), l.bitLength()))));
+
+ ECPoint Q = WNafUtil.mapPointWithPrecomp(P, width, true, pointMapQ);
+ WNafPreCompInfo infoP = WNafUtil.getWNafPreCompInfo(P);
+ WNafPreCompInfo infoQ = WNafUtil.getWNafPreCompInfo(Q);
+
+ ECPoint[] preCompP = negK ? infoP.getPreCompNeg() : infoP.getPreComp();
+ ECPoint[] preCompQ = negL ? infoQ.getPreCompNeg() : infoQ.getPreComp();
+ ECPoint[] preCompNegP = negK ? infoP.getPreComp() : infoP.getPreCompNeg();
+ ECPoint[] preCompNegQ = negL ? infoQ.getPreComp() : infoQ.getPreCompNeg();
+
+ byte[] wnafP = WNafUtil.generateWindowNaf(width, k);
+ byte[] wnafQ = WNafUtil.generateWindowNaf(width, l);
+
+ return implShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ, preCompNegQ, wnafQ);
+ }
+
+ private static ECPoint implShamirsTrickWNaf(ECPoint[] preCompP, ECPoint[] preCompNegP, byte[] wnafP,
+ ECPoint[] preCompQ, ECPoint[] preCompNegQ, byte[] wnafQ)
+ {
int len = Math.max(wnafP.length, wnafQ.length);
- ECCurve curve = P.getCurve();
+ ECCurve curve = preCompP[0].getCurve();
ECPoint infinity = curve.getInfinity();
ECPoint R = infinity;
@@ -245,20 +294,90 @@ public class ECAlgorithms
static ECPoint implSumOfMultiplies(ECPoint[] ps, BigInteger[] ks)
{
int count = ps.length;
- int[] widths = new int[count];
+ boolean[] negs = new boolean[count];
WNafPreCompInfo[] infos = new WNafPreCompInfo[count];
byte[][] wnafs = new byte[count][];
- int len = 0;
for (int i = 0; i < count; ++i)
{
- widths[i] = Math.max(2, Math.min(16, WNafUtil.getWindowSize(ks[i].bitLength())));
- infos[i] = WNafUtil.precompute(ps[i], widths[i], true);
- wnafs[i] = WNafUtil.generateWindowNaf(widths[i], ks[i]);
+ BigInteger ki = ks[i]; negs[i] = ki.signum() < 0; ki = ki.abs();
+
+ int width = Math.max(2, Math.min(16, WNafUtil.getWindowSize(ki.bitLength())));
+ infos[i] = WNafUtil.precompute(ps[i], width, true);
+ wnafs[i] = WNafUtil.generateWindowNaf(width, ki);
+ }
+
+ return implSumOfMultiplies(negs, infos, wnafs);
+ }
+
+ static ECPoint implSumOfMultipliesGLV(ECPoint[] ps, BigInteger[] ks, GLVEndomorphism glvEndomorphism)
+ {
+ BigInteger n = ps[0].getCurve().getOrder();
+
+ int len = ps.length;
+
+ BigInteger[] abs = new BigInteger[len << 1];
+ for (int i = 0, j = 0; i < len; ++i)
+ {
+ BigInteger[] ab = glvEndomorphism.decomposeScalar(ks[i].mod(n));
+ abs[j++] = ab[0];
+ abs[j++] = ab[1];
+ }
+
+ ECPointMap pointMap = glvEndomorphism.getPointMap();
+ if (glvEndomorphism.hasEfficientPointMap())
+ {
+ return ECAlgorithms.implSumOfMultiplies(ps, pointMap, abs);
+ }
+
+ ECPoint[] pqs = new ECPoint[len << 1];
+ for (int i = 0, j = 0; i < len; ++i)
+ {
+ ECPoint p = ps[i], q = pointMap.map(p);
+ pqs[j++] = p;
+ pqs[j++] = q;
+ }
+
+ return ECAlgorithms.implSumOfMultiplies(pqs, abs);
+
+ }
+
+ static ECPoint implSumOfMultiplies(ECPoint[] ps, ECPointMap pointMap, BigInteger[] ks)
+ {
+ int halfCount = ps.length, fullCount = halfCount << 1;
+
+ boolean[] negs = new boolean[fullCount];
+ WNafPreCompInfo[] infos = new WNafPreCompInfo[fullCount];
+ byte[][] wnafs = new byte[fullCount][];
+
+ for (int i = 0; i < halfCount; ++i)
+ {
+ int j0 = i << 1, j1 = j0 + 1;
+
+ BigInteger kj0 = ks[j0]; negs[j0] = kj0.signum() < 0; kj0 = kj0.abs();
+ BigInteger kj1 = ks[j1]; negs[j1] = kj1.signum() < 0; kj1 = kj1.abs();
+
+ int width = Math.max(2, Math.min(16, WNafUtil.getWindowSize(Math.max(kj0.bitLength(), kj1.bitLength()))));
+
+ ECPoint P = ps[i], Q = WNafUtil.mapPointWithPrecomp(P, width, true, pointMap);
+ infos[j0] = WNafUtil.getWNafPreCompInfo(P);
+ infos[j1] = WNafUtil.getWNafPreCompInfo(Q);
+ wnafs[j0] = WNafUtil.generateWindowNaf(width, kj0);
+ wnafs[j1] = WNafUtil.generateWindowNaf(width, kj1);
+ }
+
+ return implSumOfMultiplies(negs, infos, wnafs);
+ }
+
+ private static ECPoint implSumOfMultiplies(boolean[] negs, WNafPreCompInfo[] infos, byte[][] wnafs)
+ {
+ int len = 0, count = wnafs.length;
+ for (int i = 0; i < count; ++i)
+ {
len = Math.max(len, wnafs[i].length);
}
- ECCurve curve = ps[0].getCurve();
+ ECCurve curve = infos[0].getPreComp()[0].getCurve();
ECPoint infinity = curve.getInfinity();
ECPoint R = infinity;
@@ -276,7 +395,7 @@ public class ECAlgorithms
{
int n = Math.abs(wi);
WNafPreCompInfo info = infos[j];
- ECPoint[] table = wi < 0 ? info.getPreCompNeg() : info.getPreComp();
+ ECPoint[] table = (wi < 0 == negs[j]) ? info.getPreComp() : info.getPreCompNeg();
r = r.add(table[n >>> 1]);
}
}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/ECCurve.java b/core/src/main/java/org/bouncycastle/math/ec/ECCurve.java
index 11cc2683..066c950b 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/ECCurve.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/ECCurve.java
@@ -4,6 +4,8 @@ import java.math.BigInteger;
import java.util.Hashtable;
import java.util.Random;
+import org.bouncycastle.math.ec.endo.ECEndomorphism;
+import org.bouncycastle.math.ec.endo.GLVEndomorphism;
import org.bouncycastle.math.field.FiniteField;
import org.bouncycastle.math.field.FiniteFields;
import org.bouncycastle.util.BigIntegers;
@@ -32,11 +34,13 @@ public abstract class ECCurve
public class Config
{
protected int coord;
+ protected ECEndomorphism endomorphism;
protected ECMultiplier multiplier;
- Config(int coord, ECMultiplier multiplier)
+ Config(int coord, ECEndomorphism endomorphism, ECMultiplier multiplier)
{
this.coord = coord;
+ this.endomorphism = endomorphism;
this.multiplier = multiplier;
}
@@ -46,6 +50,12 @@ public abstract class ECCurve
return this;
}
+ public Config setEndomorphism(ECEndomorphism endomorphism)
+ {
+ this.endomorphism = endomorphism;
+ return this;
+ }
+
public Config setMultiplier(ECMultiplier multiplier)
{
this.multiplier = multiplier;
@@ -66,6 +76,7 @@ public abstract class ECCurve
}
c.coord = coord;
+ c.endomorphism = endomorphism;
c.multiplier = multiplier;
return c;
@@ -77,6 +88,7 @@ public abstract class ECCurve
protected BigInteger order, cofactor;
protected int coord = COORD_AFFINE;
+ protected ECEndomorphism endomorphism = null;
protected ECMultiplier multiplier = null;
protected ECCurve(FiniteField field)
@@ -90,7 +102,7 @@ public abstract class ECCurve
public Config configure()
{
- return new Config(this.coord, this.multiplier);
+ return new Config(this.coord, this.endomorphism, this.multiplier);
}
public ECPoint createPoint(BigInteger x, BigInteger y)
@@ -111,8 +123,15 @@ public abstract class ECCurve
protected abstract ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression);
+ protected abstract ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression);
+
protected ECMultiplier createDefaultMultiplier()
{
+ if (endomorphism instanceof GLVEndomorphism)
+ {
+ return new GLVMultiplier(this, (GLVEndomorphism)endomorphism);
+ }
+
return new WNafL2RMultiplier();
}
@@ -257,6 +276,11 @@ public abstract class ECCurve
protected abstract ECPoint decompressPoint(int yTilde, BigInteger X1);
+ public ECEndomorphism getEndomorphism()
+ {
+ return endomorphism;
+ }
+
/**
* Sets the default <code>ECMultiplier</code>, unless already set.
*/
@@ -463,6 +487,11 @@ public abstract class ECCurve
return new ECPoint.Fp(this, x, y, withCompression);
}
+ protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+ {
+ return new ECPoint.Fp(this, x, y, zs, withCompression);
+ }
+
public ECPoint importPoint(ECPoint p)
{
if (this != p.getCurve() && this.getCoordinateSystem() == COORD_JACOBIAN && !p.isInfinity())
@@ -824,6 +853,11 @@ public abstract class ECCurve
return new ECPoint.F2m(this, x, y, withCompression);
}
+ protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+ {
+ return new ECPoint.F2m(this, x, y, zs, withCompression);
+ }
+
public ECPoint getInfinity()
{
return infinity;
diff --git a/core/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java b/core/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java
index 58a52b79..434287d9 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java
@@ -220,6 +220,11 @@ public abstract class ECFieldElement
*/
public ECFieldElement sqrt()
{
+ if (isZero() || isOne())
+ {
+ return this;
+ }
+
if (!q.testBit(0))
{
throw new RuntimeException("not done yet");
@@ -227,30 +232,45 @@ public abstract class ECFieldElement
// 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))
+
+ if (q.testBit(1)) // q == 4m + 3
{
- // z = g^(u+1) + p, p = 4u + 3
- ECFieldElement z = new Fp(q, r, x.modPow(q.shiftRight(2).add(ECConstants.ONE), q));
+ BigInteger e = q.shiftRight(2).add(ECConstants.ONE);
+ return checkSqrt(new Fp(q, r, x.modPow(e, q)));
+ }
+
+ if (q.testBit(2)) // q == 8m + 5
+ {
+ BigInteger t1 = x.modPow(q.shiftRight(3), q);
+ BigInteger t2 = modMult(t1, x);
+ BigInteger t3 = modMult(t2, t1);
- return z.square().equals(this) ? z : null;
+ if (t3.equals(ECConstants.ONE))
+ {
+ return checkSqrt(new Fp(q, r, t2));
+ }
+
+ // TODO This is constant and could be precomputed
+ BigInteger t4 = ECConstants.TWO.modPow(q.shiftRight(2), q);
+
+ BigInteger y = modMult(t2, t4);
+
+ return checkSqrt(new Fp(q, r, y));
}
- // p mod 4 == 1
- BigInteger qMinusOne = q.subtract(ECConstants.ONE);
+ // q == 8m + 1
- BigInteger legendreExponent = qMinusOne.shiftRight(1);
+ BigInteger legendreExponent = q.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 X = this.x;
BigInteger fourX = modDouble(modDouble(X));
+ BigInteger k = legendreExponent.add(ECConstants.ONE), qMinusOne = q.subtract(ECConstants.ONE);
+
BigInteger U, V;
Random rand = new Random();
do
@@ -261,7 +281,7 @@ public abstract class ECFieldElement
P = new BigInteger(q.bitLength(), rand);
}
while (P.compareTo(q) >= 0
- || !(modMult(P, P).subtract(fourX).modPow(legendreExponent, q).equals(qMinusOne)));
+ || !modReduce(P.multiply(P).subtract(fourX)).modPow(legendreExponent, q).equals(qMinusOne));
BigInteger[] result = lucasSequence(P, X, k);
U = result[0];
@@ -269,17 +289,7 @@ public abstract class ECFieldElement
if (modMult(V, V).equals(fourX))
{
- // Integer division by 2, mod q
- if (V.testBit(0))
- {
- V = V.add(q);
- }
-
- V = V.shiftRight(1);
-
- //assert modMult(V, V).equals(X);
-
- return new ECFieldElement.Fp(q, r, V);
+ return new ECFieldElement.Fp(q, r, modHalfAbs(V));
}
}
while (U.equals(ECConstants.ONE) || U.equals(qMinusOne));
@@ -287,6 +297,11 @@ public abstract class ECFieldElement
return null;
}
+ private ECFieldElement checkSqrt(ECFieldElement z)
+ {
+ return z.square().equals(this) ? z : null;
+ }
+
private BigInteger[] lucasSequence(
BigInteger P,
BigInteger Q,
@@ -361,6 +376,24 @@ public abstract class ECFieldElement
return _2x;
}
+ protected BigInteger modHalf(BigInteger x)
+ {
+ if (x.testBit(0))
+ {
+ x = q.add(x);
+ }
+ return x.shiftRight(1);
+ }
+
+ protected BigInteger modHalfAbs(BigInteger x)
+ {
+ if (x.testBit(0))
+ {
+ x = q.subtract(x);
+ }
+ return x.shiftRight(1);
+ }
+
protected BigInteger modInverse(BigInteger x)
{
int bits = getFieldSize();
diff --git a/core/src/main/java/org/bouncycastle/math/ec/ECPoint.java b/core/src/main/java/org/bouncycastle/math/ec/ECPoint.java
index 7bf2d336..2aa0fd21 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/ECPoint.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/ECPoint.java
@@ -284,6 +284,20 @@ public abstract class ECPoint
return this.withCompression;
}
+ public ECPoint scaleX(ECFieldElement scale)
+ {
+ return isInfinity()
+ ? this
+ : getCurve().createRawPoint(getRawXCoord().multiply(scale), getRawYCoord(), getRawZCoords(), this.withCompression);
+ }
+
+ public ECPoint scaleY(ECFieldElement scale)
+ {
+ return isInfinity()
+ ? this
+ : getCurve().createRawPoint(getRawXCoord(), getRawYCoord().multiply(scale), getRawZCoords(), this.withCompression);
+ }
+
public boolean equals(ECPoint other)
{
if (null == other)
@@ -1335,6 +1349,74 @@ public abstract class ECPoint
}
}
+ public ECPoint scaleX(ECFieldElement scale)
+ {
+ if (this.isInfinity())
+ {
+ return this;
+ }
+
+ int coord = this.getCurveCoordinateSystem();
+
+ switch (coord)
+ {
+ case ECCurve.COORD_LAMBDA_AFFINE:
+ {
+ // Y is actually Lambda (X + Y/X) here
+ ECFieldElement X = getRawXCoord(), L = getRawYCoord();
+
+ ECFieldElement X2 = X.multiply(scale);
+ ECFieldElement L2 = L.add(X).divide(scale).add(X2);
+
+ return getCurve().createRawPoint(X, L2, getRawZCoords(), this.withCompression);
+ }
+ case ECCurve.COORD_LAMBDA_PROJECTIVE:
+ {
+ // Y is actually Lambda (X + Y/X) here
+ ECFieldElement X = getRawXCoord(), L = getRawYCoord(), Z = getRawZCoords()[0];
+
+ // We scale the Z coordinate also, to avoid an inversion
+ ECFieldElement X2 = X.multiply(scale.square());
+ ECFieldElement L2 = L.add(X).add(X2);
+ ECFieldElement Z2 = Z.multiply(scale);
+
+ return getCurve().createRawPoint(X2, L2, new ECFieldElement[]{ Z2 }, this.withCompression);
+ }
+ default:
+ {
+ return super.scaleX(scale);
+ }
+ }
+ }
+
+ public ECPoint scaleY(ECFieldElement scale)
+ {
+ if (this.isInfinity())
+ {
+ return this;
+ }
+
+ int coord = this.getCurveCoordinateSystem();
+
+ switch (coord)
+ {
+ case ECCurve.COORD_LAMBDA_AFFINE:
+ case ECCurve.COORD_LAMBDA_PROJECTIVE:
+ {
+ ECFieldElement X = getRawXCoord(), L = getRawYCoord();
+
+ // Y is actually Lambda (X + Y/X) here
+ ECFieldElement L2 = L.add(X).multiply(scale).add(X);
+
+ return getCurve().createRawPoint(X, L2, getRawZCoords(), this.withCompression);
+ }
+ default:
+ {
+ return super.scaleY(scale);
+ }
+ }
+ }
+
protected boolean getCompressionYTilde()
{
ECFieldElement X = this.getRawXCoord();
diff --git a/core/src/main/java/org/bouncycastle/math/ec/ECPointMap.java b/core/src/main/java/org/bouncycastle/math/ec/ECPointMap.java
new file mode 100644
index 00000000..439e8daa
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/ECPointMap.java
@@ -0,0 +1,6 @@
+package org.bouncycastle.math.ec;
+
+public interface ECPointMap
+{
+ ECPoint map(ECPoint p);
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/FixedPointCombMultiplier.java b/core/src/main/java/org/bouncycastle/math/ec/FixedPointCombMultiplier.java
index 84fbf6a5..d2cc2e3b 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/FixedPointCombMultiplier.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/FixedPointCombMultiplier.java
@@ -20,8 +20,7 @@ public class FixedPointCombMultiplier extends AbstractECMultiplier
throw new IllegalStateException("fixed-point comb doesn't support scalars larger than the curve order");
}
- // TODO Call method to let subclasses select width
- int width = size > 257 ? 6 : 5;
+ int width = getWidthForCombSize(size);
FixedPointPreCompInfo info = FixedPointUtil.precompute(p, width);
ECPoint[] lookupTable = info.getPreComp();
@@ -49,4 +48,9 @@ public class FixedPointCombMultiplier extends AbstractECMultiplier
return R;
}
+
+ protected int getWidthForCombSize(int combSize)
+ {
+ return combSize > 257 ? 6 : 5;
+ }
}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/GLVMultiplier.java b/core/src/main/java/org/bouncycastle/math/ec/GLVMultiplier.java
new file mode 100644
index 00000000..09b83668
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/GLVMultiplier.java
@@ -0,0 +1,42 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.math.ec.endo.GLVEndomorphism;
+
+public class GLVMultiplier extends AbstractECMultiplier
+{
+ protected final ECCurve curve;
+ protected final GLVEndomorphism glvEndomorphism;
+
+ public GLVMultiplier(ECCurve curve, GLVEndomorphism glvEndomorphism)
+ {
+ if (curve == null || curve.getOrder() == null)
+ {
+ throw new IllegalArgumentException("Need curve with known group order");
+ }
+
+ this.curve = curve;
+ this.glvEndomorphism = glvEndomorphism;
+ }
+
+ protected ECPoint multiplyPositive(ECPoint p, BigInteger k)
+ {
+ if (!curve.equals(p.getCurve()))
+ {
+ throw new IllegalStateException();
+ }
+
+ BigInteger n = p.getCurve().getOrder();
+ BigInteger[] ab = glvEndomorphism.decomposeScalar(k.mod(n));
+ BigInteger a = ab[0], b = ab[1];
+
+ ECPointMap pointMap = glvEndomorphism.getPointMap();
+ if (glvEndomorphism.hasEfficientPointMap())
+ {
+ return ECAlgorithms.implShamirsTrickWNaf(p, a, pointMap, b);
+ }
+
+ return ECAlgorithms.implShamirsTrickWNaf(p, a, pointMap.map(p), b);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/Mod.java b/core/src/main/java/org/bouncycastle/math/ec/Mod.java
index 2ac6c465..0345af19 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/Mod.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/Mod.java
@@ -1,5 +1,9 @@
package org.bouncycastle.math.ec;
+import java.util.Random;
+
+import org.bouncycastle.crypto.util.Pack;
+
public abstract class Mod
{
public static void invert(int[] p, int[] x, int[] z)
@@ -70,6 +74,31 @@ public abstract class Mod
}
}
+ public static int[] random(int[] p)
+ {
+ int len = p.length;
+ Random rand = new Random();
+ int[] s = Nat.create(len);
+
+ int m = p[len - 1];
+ m |= m >>> 1;
+ m |= m >>> 2;
+ m |= m >>> 4;
+ m |= m >>> 8;
+ m |= m >>> 16;
+
+ do
+ {
+ byte[] bytes = new byte[len << 2];
+ rand. nextBytes(bytes);
+ Pack.bigEndianToInt(bytes, 0, s);
+ s[len - 1] &= m;
+ }
+ while (Nat.gte(len, s, p));
+
+ return s;
+ }
+
public static void subtract(int[] p, int[] x, int[] y, int[] z)
{
int len = p.length;
diff --git a/core/src/main/java/org/bouncycastle/math/ec/Nat.java b/core/src/main/java/org/bouncycastle/math/ec/Nat.java
index 6915b79b..9f85e8bc 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/Nat.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/Nat.java
@@ -20,6 +20,52 @@ public abstract class Nat
return (int)c;
}
+ public static int add33At(int len, int x, int[] z, int zPos)
+ {
+ // assert zPos <= (len - 2);
+ long c = (z[zPos + 0] & M) + (x & M);
+ z[zPos + 0] = (int)c;
+ c >>>= 32;
+ c += (z[zPos + 1] & M) + 1L;
+ z[zPos + 1] = (int)c;
+ c >>>= 32;
+ return c == 0 ? 0 : incAt(len, z, zPos + 2);
+ }
+
+ public static int add33At(int len, int x, int[] z, int zOff, int zPos)
+ {
+ // assert zPos <= (len - 2);
+ long c = (z[zOff + zPos] & M) + (x & M);
+ z[zOff + zPos] = (int)c;
+ c >>>= 32;
+ c += (z[zOff + zPos + 1] & M) + 1L;
+ z[zOff + zPos + 1] = (int)c;
+ c >>>= 32;
+ return c == 0 ? 0 : incAt(len, z, zOff, zPos + 2);
+ }
+
+ public static int add33To(int len, int x, int[] z)
+ {
+ long c = (z[0] & M) + (x & M);
+ z[0] = (int)c;
+ c >>>= 32;
+ c += (z[1] & M) + 1L;
+ z[1] = (int)c;
+ c >>>= 32;
+ return c == 0 ? 0 : incAt(len, z, 2);
+ }
+
+ public static int add33To(int len, int x, int[] z, int zOff)
+ {
+ long c = (z[zOff + 0] & M) + (x & M);
+ z[zOff + 0] = (int)c;
+ c >>>= 32;
+ c += (z[zOff + 1] & M) + 1L;
+ z[zOff + 1] = (int)c;
+ c >>>= 32;
+ return c == 0 ? 0 : incAt(len, z, zOff, 2);
+ }
+
public static int addBothTo(int len, int[] x, int[] y, int[] z)
{
long c = 0;
@@ -44,18 +90,62 @@ public abstract class Nat
return (int)c;
}
- // TODO Re-write to allow full range for x?
- public static int addDWord(int len, long x, int[] z, int zOff)
+ public static int addDWordAt(int len, long x, int[] z, int zPos)
{
- // assert zOff <= (len - 2);
- long c = x;
- c += (z[zOff + 0] & M);
+ // assert zPos <= (len - 2);
+ long c = (z[zPos + 0] & M) + (x & M);
+ z[zPos + 0] = (int)c;
+ c >>>= 32;
+ c += (z[zPos + 1] & M) + (x >>> 32);
+ z[zPos + 1] = (int)c;
+ c >>>= 32;
+ return c == 0 ? 0 : incAt(len, z, zPos + 2);
+ }
+
+ public static int addDWordAt(int len, long x, int[] z, int zOff, int zPos)
+ {
+ // assert zPos <= (len - 2);
+ long c = (z[zOff + zPos] & M) + (x & M);
+ z[zOff + zPos] = (int)c;
+ c >>>= 32;
+ c += (z[zOff + zPos + 1] & M) + (x >>> 32);
+ z[zOff + zPos + 1] = (int)c;
+ c >>>= 32;
+ return c == 0 ? 0 : incAt(len, z, zOff, zPos + 2);
+ }
+
+ public static int addDWordTo(int len, long x, int[] z)
+ {
+ long c = (z[0] & M) + (x & M);
+ z[0] = (int)c;
+ c >>>= 32;
+ c += (z[1] & M) + (x >>> 32);
+ z[1] = (int)c;
+ c >>>= 32;
+ return c == 0 ? 0 : incAt(len, z, 2);
+ }
+
+ public static int addDWordTo(int len, long x, int[] z, int zOff)
+ {
+ long c = (z[zOff + 0] & M) + (x & M);
z[zOff + 0] = (int)c;
c >>>= 32;
- c += (z[zOff + 1] & M);
+ c += (z[zOff + 1] & M) + (x >>> 32);
z[zOff + 1] = (int)c;
c >>>= 32;
- return c == 0 ? 0 : inc(len, z, zOff + 2);
+ return c == 0 ? 0 : incAt(len, z, zOff, 2);
+ }
+
+ public static int addTo(int len, int[] x, int[] z)
+ {
+ long c = 0;
+ for (int i = 0; i < len; ++i)
+ {
+ c += (x[i] & M) + (z[i] & M);
+ z[i] = (int)c;
+ c >>>= 32;
+ }
+ return (int)c;
}
public static int addTo(int len, int[] x, int xOff, int[] z, int zOff)
@@ -70,22 +160,38 @@ public abstract class Nat
return (int)c;
}
- public static int addWord(int len, int x, int[] z)
+ public static int addWordAt(int len, int x, int[] z, int zPos)
+ {
+ // assert zPos <= (len - 1);
+ long c = (x & M) + (z[zPos] & M);
+ z[zPos] = (int)c;
+ c >>>= 32;
+ return c == 0 ? 0 : incAt(len, z, zPos + 1);
+ }
+
+ public static int addWordAt(int len, int x, int[] z, int zOff, int zPos)
+ {
+ // assert zPos <= (len - 1);
+ long c = (x & M) + (z[zOff + zPos] & M);
+ z[zOff + zPos] = (int)c;
+ c >>>= 32;
+ return c == 0 ? 0 : incAt(len, z, zOff, zPos + 1);
+ }
+
+ public static int addWordTo(int len, int x, int[] z)
{
long c = (x & M) + (z[0] & M);
z[0] = (int)c;
c >>>= 32;
- return c == 0 ? 0 : inc(len, z, 1);
+ return c == 0 ? 0 : incAt(len, z, 1);
}
- public static int addWordExt(int len, int x, int[] zz, int zzOff)
+ public static int addWordTo(int len, int x, int[] z, int zOff)
{
- int extLen = len << 1;
- // assert zzOff <= (extLen - 1);
- long c = (x & M) + (zz[zzOff + 0] & M);
- zz[zzOff + 0] = (int)c;
+ long c = (x & M) + (z[zOff] & M);
+ z[zOff] = (int)c;
c >>>= 32;
- return c == 0 ? 0 : inc(extLen, zz, zzOff + 1);
+ return c == 0 ? 0 : incAt(len, z, zOff, 1);
}
public static int[] copy(int len, int[] x)
@@ -95,15 +201,53 @@ public abstract class Nat
return z;
}
+ public static void copy(int len, int[] x, int[] z)
+ {
+ System.arraycopy(x, 0, z, 0, len);
+ }
+
public static int[] create(int len)
{
return new int[len];
}
- public static int dec(int len, int[] z, int zOff)
+ public static int dec(int len, int[] z)
+ {
+ for (int i = 0; i < len; ++i)
+ {
+ if (--z[i] != -1)
+ {
+ return 0;
+ }
+ }
+ return -1;
+ }
+
+ public static int dec(int len, int[] x, int[] z)
+ {
+ int i = 0;
+ while (i < len)
+ {
+ int c = x[i] - 1;
+ z[i] = c;
+ ++i;
+ if (c != -1)
+ {
+ while (i < len)
+ {
+ z[i] = x[i];
+ ++i;
+ }
+ return 0;
+ }
+ }
+ return -1;
+ }
+
+ public static int decAt(int len, int[] z, int zPos)
{
- // assert zOff <= len;
- for (int i = zOff; i < len; ++i)
+ // assert zPos <= len;
+ for (int i = zPos; i < len; ++i)
{
if (--z[i] != -1)
{
@@ -113,6 +257,19 @@ public abstract class Nat
return -1;
}
+ public static int decAt(int len, int[] z, int zOff, int zPos)
+ {
+ // assert zPos <= len;
+ for (int i = zPos; i < len; ++i)
+ {
+ if (--z[zOff + i] != -1)
+ {
+ return 0;
+ }
+ }
+ return -1;
+ }
+
public static boolean eq(int len, int[] x, int[] y)
{
for (int i = len - 1; i >= 0; --i)
@@ -172,10 +329,43 @@ public abstract class Nat
return true;
}
- public static int inc(int len, int[] z, int zOff)
+ public static int inc(int len, int[] z)
+ {
+ for (int i = 0; i < len; ++i)
+ {
+ if (++z[i] != 0)
+ {
+ return 0;
+ }
+ }
+ return 1;
+ }
+
+ public static int inc(int len, int[] x, int[] z)
{
- // assert zOff <= len;
- for (int i = zOff; i < len; ++i)
+ int i = 0;
+ while (i < len)
+ {
+ int c = x[i] + 1;
+ z[i] = c;
+ ++i;
+ if (c != 0)
+ {
+ while (i < len)
+ {
+ z[i] = x[i];
+ ++i;
+ }
+ return 0;
+ }
+ }
+ return 1;
+ }
+
+ public static int incAt(int len, int[] z, int zPos)
+ {
+ // assert zPos <= len;
+ for (int i = zPos; i < len; ++i)
{
if (++z[i] != 0)
{
@@ -185,6 +375,19 @@ public abstract class Nat
return 1;
}
+ public static int incAt(int len, int[] z, int zOff, int zPos)
+ {
+ // assert zPos <= len;
+ for (int i = zPos; i < len; ++i)
+ {
+ if (++z[zOff + i] != 0)
+ {
+ return 0;
+ }
+ }
+ return 1;
+ }
+
public static boolean isOne(int len, int[] x)
{
if (x[0] != 1)
@@ -215,14 +418,51 @@ public abstract class Nat
public static void mul(int len, int[] x, int[] y, int[] zz)
{
- zz[len] = mulWord(len, x[0], y, zz, 0);
+ zz[len] = mulWord(len, x[0], y, zz);
for (int i = 1; i < len; ++i)
{
- zz[i + len] = mulWordAdd(len, x[i], y, zz, i);
+ zz[i + len] = mulWordAddTo(len, x[i], y, 0, zz, i);
}
}
+ public static void mul(int len, int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff)
+ {
+ zz[zzOff + len] = mulWord(len, x[xOff], y, yOff, zz, zzOff);
+
+ for (int i = 1; i < len; ++i)
+ {
+ zz[zzOff + i + len] = mulWordAddTo(len, x[xOff + i], y, yOff, zz, zzOff + i);
+ }
+ }
+
+ public static int mulAddTo(int len, int[] x, int[] y, int[] zz)
+ {
+ long zc = 0;
+ for (int i = 0; i < len; ++i)
+ {
+ long c = mulWordAddTo(len, x[i], y, 0, zz, i) & M;
+ c += zc + (zz[i + len] & M);
+ zz[i + len] = (int)c;
+ zc = c >>> 32;
+ }
+ return (int)zc;
+ }
+
+ public static int mulAddTo(int len, int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff)
+ {
+ long zc = 0;
+ for (int i = 0; i < len; ++i)
+ {
+ long c = mulWordAddTo(len, x[xOff + i], y, yOff, zz, zzOff) & M;
+ c += zc + (zz[zzOff + len] & M);
+ zz[zzOff + len] = (int)c;
+ zc = c >>> 32;
+ ++zzOff;
+ }
+ return (int)zc;
+ }
+
public static int mul31BothAdd(int len, int a, int[] x, int b, int[] y, int[] z, int zOff)
{
long c = 0, aVal = a & M, bVal = b & M;
@@ -237,13 +477,27 @@ public abstract class Nat
return (int)c;
}
- public static int mulWord(int len, int x, int[] y, int[] z, int zOff)
+ public static int mulWord(int len, int x, int[] y, int[] z)
{
long c = 0, xVal = x & M;
int i = 0;
do
{
c += xVal * (y[i] & M);
+ z[i] = (int)c;
+ c >>>= 32;
+ }
+ while (++i < len);
+ return (int)c;
+ }
+
+ public static int mulWord(int len, int x, int[] y, int yOff, int[] z, int zOff)
+ {
+ long c = 0, xVal = x & M;
+ int i = 0;
+ do
+ {
+ c += xVal * (y[yOff + i] & M);
z[zOff + i] = (int)c;
c >>>= 32;
}
@@ -251,13 +505,13 @@ public abstract class Nat
return (int)c;
}
- public static int mulWordAdd(int len, int x, int[] y, int[] z, int zOff)
+ public static int mulWordAddTo(int len, int x, int[] y, int yOff, int[] z, int zOff)
{
long c = 0, xVal = x & M;
int i = 0;
do
{
- c += xVal * (y[i] & M) + (z[zOff + i] & M);
+ c += xVal * (y[yOff + i] & M) + (z[zOff + i] & M);
z[zOff + i] = (int)c;
c >>>= 32;
}
@@ -265,20 +519,20 @@ public abstract class Nat
return (int)c;
}
- public static int mulWordDwordAdd(int len, int x, long y, int[] z, int zOff)
+ public static int mulWordDwordAddAt(int len, int x, long y, int[] z, int zPos)
{
- // assert zOff <= (len - 3);
+ // assert zPos <= (len - 3);
long c = 0, xVal = x & M;
- c += xVal * (y & M) + (z[zOff + 0] & M);
- z[zOff + 0] = (int)c;
+ c += xVal * (y & M) + (z[zPos + 0] & M);
+ z[zPos + 0] = (int)c;
c >>>= 32;
- c += xVal * (y >>> 32) + (z[zOff + 1] & M);
- z[zOff + 1] = (int)c;
+ c += xVal * (y >>> 32) + (z[zPos + 1] & M);
+ z[zPos + 1] = (int)c;
c >>>= 32;
- c += (z[zOff + 2] & M);
- z[zOff + 2] = (int)c;
+ c += (z[zPos + 2] & M);
+ z[zPos + 2] = (int)c;
c >>>= 32;
- return c == 0 ? 0 : inc(len, z, zOff + 3);
+ return c == 0 ? 0 : incAt(len, z, zPos + 3);
}
public static int shiftDownBit(int len, int[] z, int c)
@@ -293,6 +547,18 @@ public abstract class Nat
return c << 31;
}
+ public static int shiftDownBit(int len, int[] z, int zOff, int c)
+ {
+ int i = len;
+ while (--i >= 0)
+ {
+ int next = z[zOff + i];
+ z[zOff + i] = (next >>> 1) | (c << 31);
+ c = next;
+ }
+ return c << 31;
+ }
+
public static int shiftDownBit(int len, int[] x, int c, int[] z)
{
int i = len;
@@ -305,6 +571,18 @@ public abstract class Nat
return c << 31;
}
+ public static int shiftDownBit(int len, int[] x, int xOff, int c, int[] z, int zOff)
+ {
+ int i = len;
+ while (--i >= 0)
+ {
+ int next = x[xOff + i];
+ z[zOff + i] = (next >>> 1) | (c << 31);
+ c = next;
+ }
+ return c << 31;
+ }
+
public static int shiftDownBits(int len, int[] z, int bits, int c)
{
// assert bits > 0 && bits < 32;
@@ -318,19 +596,45 @@ public abstract class Nat
return c << -bits;
}
- public static int shiftDownBits(int len, int[] x, int xOff, int bits, int c, int[] z)
+ public static int shiftDownBits(int len, int[] z, int zOff, int bits, int c)
{
// assert bits > 0 && bits < 32;
int i = len;
while (--i >= 0)
{
- int next = x[xOff + i];
+ int next = z[zOff + i];
+ z[zOff + i] = (next >>> bits) | (c << -bits);
+ c = next;
+ }
+ return c << -bits;
+ }
+
+ public static int shiftDownBits(int len, int[] x, int bits, int c, int[] z)
+ {
+// assert bits > 0 && bits < 32;
+ int i = len;
+ while (--i >= 0)
+ {
+ int next = x[i];
z[i] = (next >>> bits) | (c << -bits);
c = next;
}
return c << -bits;
}
+ public static int shiftDownBits(int len, int[] x, int xOff, int bits, int c, int[] z, int zOff)
+ {
+// assert bits > 0 && bits < 32;
+ int i = len;
+ while (--i >= 0)
+ {
+ int next = x[xOff + i];
+ z[zOff + i] = (next >>> bits) | (c << -bits);
+ c = next;
+ }
+ return c << -bits;
+ }
+
public static int shiftDownWord(int len, int[] z, int c)
{
int i = len;
@@ -354,6 +658,17 @@ public abstract class Nat
return c >>> 31;
}
+ public static int shiftUpBit(int len, int[] z, int zOff, int c)
+ {
+ for (int i = 0; i < len; ++i)
+ {
+ int next = z[zOff + i];
+ z[zOff + i] = (next << 1) | (c >>> 31);
+ c = next;
+ }
+ return c >>> 31;
+ }
+
public static int shiftUpBit(int len, int[] x, int c, int[] z)
{
for (int i = 0; i < len; ++i)
@@ -365,12 +680,12 @@ public abstract class Nat
return c >>> 31;
}
- public static int shiftUpBit(int len, int[] x, int xOff, int c, int[] z)
+ public static int shiftUpBit(int len, int[] x, int xOff, int c, int[] z, int zOff)
{
for (int i = 0; i < len; ++i)
{
int next = x[xOff + i];
- z[i] = (next << 1) | (c >>> 31);
+ z[zOff + i] = (next << 1) | (c >>> 31);
c = next;
}
return c >>> 31;
@@ -388,6 +703,18 @@ public abstract class Nat
return c >>> -bits;
}
+ public static int shiftUpBits(int len, int[] z, int zOff, int bits, int c)
+ {
+// assert bits > 0 && bits < 32;
+ for (int i = 0; i < len; ++i)
+ {
+ int next = z[zOff + i];
+ z[zOff + i] = (next << bits) | (c >>> -bits);
+ c = next;
+ }
+ return c >>> -bits;
+ }
+
public static int shiftUpBits(int len, int[] x, int bits, int c, int[] z)
{
// assert bits > 0 && bits < 32;
@@ -400,6 +727,18 @@ public abstract class Nat
return c >>> -bits;
}
+ public static int shiftUpBits(int len, int[] x, int xOff, int bits, int c, int[] z, int zOff)
+ {
+// assert bits > 0 && bits < 32;
+ for (int i = 0; i < len; ++i)
+ {
+ int next = x[xOff + i];
+ z[zOff + i] = (next << bits) | (c >>> -bits);
+ c = next;
+ }
+ return c >>> -bits;
+ }
+
public static void square(int len, int[] x, int[] zz)
{
int extLen = len << 1;
@@ -417,28 +756,66 @@ public abstract class Nat
for (int i = 1; i < len; ++i)
{
- c = squareWordAddExt(len, x, i, zz);
- addWordExt(len, c, zz, i << 1);
+ c = squareWordAdd(x, i, zz);
+ addWordAt(extLen, c, zz, i << 1);
}
shiftUpBit(extLen, zz, x[0] << 31);
}
- public static int squareWordAddExt(int len, int[] x, int xPos, int[] zz)
+ public static void square(int len, int[] x, int xOff, int[] zz, int zzOff)
+ {
+ int extLen = len << 1;
+ int c = 0;
+ int j = len, k = extLen;
+ do
+ {
+ long xVal = (x[xOff + --j] & M);
+ long p = xVal * xVal;
+ zz[zzOff + --k] = (c << 31) | (int)(p >>> 33);
+ zz[zzOff + --k] = (int)(p >>> 1);
+ c = (int)p;
+ }
+ while (j > 0);
+
+ for (int i = 1; i < len; ++i)
+ {
+ c = squareWordAdd(x, xOff, i, zz, zzOff);
+ addWordAt(extLen, c, zz, zzOff, i << 1);
+ }
+
+ shiftUpBit(extLen, zz, zzOff, x[xOff] << 31);
+ }
+
+ public static int squareWordAdd(int[] x, int xPos, int[] z)
{
- // assert xPos > 0 && xPos < len;
long c = 0, xVal = x[xPos] & M;
int i = 0;
do
{
- c += xVal * (x[i] & M) + (zz[xPos + i] & M);
- zz[xPos + i] = (int)c;
+ c += xVal * (x[i] & M) + (z[xPos + i] & M);
+ z[xPos + i] = (int)c;
c >>>= 32;
}
while (++i < xPos);
return (int)c;
}
+ public static int squareWordAdd(int[] x, int xOff, int xPos, int[] z, int zOff)
+ {
+ long c = 0, xVal = x[xOff + xPos] & M;
+ int i = 0;
+ do
+ {
+ c += xVal * (x[xOff + i] & M) + (z[xPos + zOff] & M);
+ z[xPos + zOff] = (int)c;
+ c >>>= 32;
+ ++zOff;
+ }
+ while (++i < xPos);
+ return (int)c;
+ }
+
public static int sub(int len, int[] x, int[] y, int[] z)
{
long c = 0;
@@ -451,6 +828,64 @@ public abstract class Nat
return (int)c;
}
+ public static int sub(int len, int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
+ {
+ long c = 0;
+ for (int i = 0; i < len; ++i)
+ {
+ c += (x[xOff + i] & M) - (y[yOff + i] & M);
+ z[zOff + i] = (int)c;
+ c >>= 32;
+ }
+ return (int)c;
+ }
+
+ public static int sub33At(int len, int x, int[] z, int zPos)
+ {
+ // assert zPos <= (len - 2);
+ long c = (z[zPos + 0] & M) - (x & M);
+ z[zPos + 0] = (int)c;
+ c >>= 32;
+ c += (z[zPos + 1] & M) - 1;
+ z[zPos + 1] = (int)c;
+ c >>= 32;
+ return c == 0 ? 0 : decAt(len, z, zPos + 2);
+ }
+
+ public static int sub33At(int len, int x, int[] z, int zOff, int zPos)
+ {
+ // assert zPos <= (len - 2);
+ long c = (z[zOff + zPos] & M) - (x & M);
+ z[zOff + zPos] = (int)c;
+ c >>= 32;
+ c += (z[zOff + zPos + 1] & M) - 1;
+ z[zOff + zPos + 1] = (int)c;
+ c >>= 32;
+ return c == 0 ? 0 : decAt(len, z, zOff, zPos + 2);
+ }
+
+ public static int sub33From(int len, int x, int[] z)
+ {
+ long c = (z[0] & M) - (x & M);
+ z[0] = (int)c;
+ c >>= 32;
+ c += (z[1] & M) - 1;
+ z[1] = (int)c;
+ c >>= 32;
+ return c == 0 ? 0 : decAt(len, z, 2);
+ }
+
+ public static int sub33From(int len, int x, int[] z, int zOff)
+ {
+ long c = (z[zOff + 0] & M) - (x & M);
+ z[zOff + 0] = (int)c;
+ c >>= 32;
+ c += (z[zOff + 1] & M) - 1;
+ z[zOff + 1] = (int)c;
+ c >>= 32;
+ return c == 0 ? 0 : decAt(len, z, zOff, 2);
+ }
+
public static int subBothFrom(int len, int[] x, int[] y, int[] z)
{
long c = 0;
@@ -475,18 +910,62 @@ public abstract class Nat
return (int)c;
}
- // TODO Re-write to allow full range for x?
- public static int subDWord(int len, long x, int[] z)
+ public static int subDWordAt(int len, long x, int[] z, int zPos)
{
- // assert 0 <= (len - 2);
- long c = -x;
- c += (z[0] & M);
+ // assert zPos <= (len - 2);
+ long c = (z[zPos + 0] & M) - (x & M);
+ z[zPos + 0] = (int)c;
+ c >>= 32;
+ c += (z[zPos + 1] & M) - (x >>> 32);
+ z[zPos + 1] = (int)c;
+ c >>= 32;
+ return c == 0 ? 0 : decAt(len, z, zPos + 2);
+ }
+
+ public static int subDWordAt(int len, long x, int[] z, int zOff, int zPos)
+ {
+ // assert zPos <= (len - 2);
+ long c = (z[zOff + zPos] & M) - (x & M);
+ z[zOff + zPos] = (int)c;
+ c >>= 32;
+ c += (z[zOff + zPos + 1] & M) - (x >>> 32);
+ z[zOff + zPos + 1] = (int)c;
+ c >>= 32;
+ return c == 0 ? 0 : decAt(len, z, zOff, zPos + 2);
+ }
+
+ public static int subDWordFrom(int len, long x, int[] z)
+ {
+ long c = (z[0] & M) - (x & M);
z[0] = (int)c;
c >>= 32;
- c += (z[1] & M);
+ c += (z[1] & M) - (x >>> 32);
z[1] = (int)c;
c >>= 32;
- return c == 0 ? 0 : dec(len, z, 2);
+ return c == 0 ? 0 : decAt(len, z, 2);
+ }
+
+ public static int subDWordFrom(int len, long x, int[] z, int zOff)
+ {
+ long c = (z[zOff + 0] & M) - (x & M);
+ z[zOff + 0] = (int)c;
+ c >>= 32;
+ c += (z[zOff + 1] & M) - (x >>> 32);
+ z[zOff + 1] = (int)c;
+ c >>= 32;
+ return c == 0 ? 0 : decAt(len, z, zOff, 2);
+ }
+
+ public static int subFrom(int len, int[] x, int[] z)
+ {
+ long c = 0;
+ for (int i = 0; i < len; ++i)
+ {
+ c += (z[i] & M) - (x[i] & M);
+ z[i] = (int)c;
+ c >>= 32;
+ }
+ return (int)c;
}
public static int subFrom(int len, int[] x, int xOff, int[] z, int zOff)
@@ -501,6 +980,40 @@ public abstract class Nat
return (int)c;
}
+ public static int subWordAt(int len, int x, int[] z, int zPos)
+ {
+ // assert zPos <= (len - 1);
+ long c = (z[zPos] & M) - (x & M);
+ z[zPos] = (int)c;
+ c >>= 32;
+ return c == 0 ? 0 : decAt(len, z, zPos + 1);
+ }
+
+ public static int subWordAt(int len, int x, int[] z, int zOff, int zPos)
+ {
+ // assert zPos <= (len - 1);
+ long c = (z[zOff + zPos] & M) - (x & M);
+ z[zOff + zPos] = (int)c;
+ c >>= 32;
+ return c == 0 ? 0 : decAt(len, z, zOff, zPos + 1);
+ }
+
+ public static int subWordFrom(int len, int x, int[] z)
+ {
+ long c = (z[0] & M) - (x & M);
+ z[0] = (int)c;
+ c >>= 32;
+ return c == 0 ? 0 : decAt(len, z, 1);
+ }
+
+ public static int subWordFrom(int len, int x, int[] z, int zOff)
+ {
+ long c = (z[zOff + 0] & M) - (x & M);
+ z[zOff + 0] = (int)c;
+ c >>= 32;
+ return c == 0 ? 0 : decAt(len, z, zOff, 1);
+ }
+
public static BigInteger toBigInteger(int len, int[] x)
{
byte[] bs = new byte[len << 2];
diff --git a/core/src/main/java/org/bouncycastle/math/ec/ScaleXPointMap.java b/core/src/main/java/org/bouncycastle/math/ec/ScaleXPointMap.java
new file mode 100644
index 00000000..099f5fb3
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/ScaleXPointMap.java
@@ -0,0 +1,16 @@
+package org.bouncycastle.math.ec;
+
+public class ScaleXPointMap implements ECPointMap
+{
+ protected final ECFieldElement scale;
+
+ public ScaleXPointMap(ECFieldElement scale)
+ {
+ this.scale = scale;
+ }
+
+ public ECPoint map(ECPoint p)
+ {
+ return p.scaleX(scale);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/ScaleYPointMap.java b/core/src/main/java/org/bouncycastle/math/ec/ScaleYPointMap.java
new file mode 100644
index 00000000..a7a87904
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/ScaleYPointMap.java
@@ -0,0 +1,16 @@
+package org.bouncycastle.math.ec;
+
+public class ScaleYPointMap implements ECPointMap
+{
+ protected final ECFieldElement scale;
+
+ public ScaleYPointMap(ECFieldElement scale)
+ {
+ this.scale = scale;
+ }
+
+ public ECPoint map(ECPoint p)
+ {
+ return p.scaleY(scale);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/WNafUtil.java b/core/src/main/java/org/bouncycastle/math/ec/WNafUtil.java
index f8020314..e1868f4d 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/WNafUtil.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/WNafUtil.java
@@ -6,7 +6,10 @@ public abstract class WNafUtil
{
public static final String PRECOMP_NAME = "bc_wnaf";
- private static int[] DEFAULT_WINDOW_SIZE_CUTOFFS = new int[]{ 13, 41, 121, 337, 897, 2305 };
+ private static final int[] DEFAULT_WINDOW_SIZE_CUTOFFS = new int[]{ 13, 41, 121, 337, 897, 2305 };
+
+ private static final byte[] EMPTY_BYTES = new byte[0];
+ private static final int[] EMPTY_INTS = new int[0];
public static int[] generateCompactNaf(BigInteger k)
{
@@ -14,30 +17,35 @@ public abstract class WNafUtil
{
throw new IllegalArgumentException("'k' must have bitlength < 2^16");
}
+ if (k.signum() == 0)
+ {
+ return EMPTY_INTS;
+ }
BigInteger _3k = k.shiftLeft(1).add(k);
- int digits = _3k.bitLength() - 1;
- int[] naf = new int[(digits + 1) >> 1];
+ int bits = _3k.bitLength();
+ int[] naf = new int[bits >> 1];
- int length = 0, zeroes = 0;
- for (int i = 1; i <= digits; ++i)
- {
- boolean _3kBit = _3k.testBit(i);
- boolean kBit = k.testBit(i);
+ BigInteger diff = _3k.xor(k);
- if (_3kBit == kBit)
+ int highBit = bits - 1, length = 0, zeroes = 0;
+ for (int i = 1; i < highBit; ++i)
+ {
+ if (!diff.testBit(i))
{
++zeroes;
+ continue;
}
- else
- {
- int digit = kBit ? -1 : 1;
- naf[length++] = (digit << 16) | zeroes;
- zeroes = 0;
- }
+
+ int digit = k.testBit(i) ? -1 : 1;
+ naf[length++] = (digit << 16) | zeroes;
+ zeroes = 1;
+ ++i;
}
+ naf[length++] = (1 << 16) | zeroes;
+
if (naf.length > length)
{
naf = trim(naf, length);
@@ -61,6 +69,10 @@ public abstract class WNafUtil
{
throw new IllegalArgumentException("'k' must have bitlength < 2^16");
}
+ if (k.signum() == 0)
+ {
+ return EMPTY_INTS;
+ }
int[] wnaf = new int[k.bitLength() / width + 1];
@@ -171,19 +183,29 @@ public abstract class WNafUtil
public static byte[] generateNaf(BigInteger k)
{
+ if (k.signum() == 0)
+ {
+ return EMPTY_BYTES;
+ }
+
BigInteger _3k = k.shiftLeft(1).add(k);
int digits = _3k.bitLength() - 1;
byte[] naf = new byte[digits];
- for (int i = 1; i <= digits; ++i)
- {
- boolean _3kBit = _3k.testBit(i);
- boolean kBit = k.testBit(i);
+ BigInteger diff = _3k.xor(k);
- naf[i - 1] = (byte)(_3kBit == kBit ? 0 : kBit ? -1 : 1);
+ for (int i = 1; i < digits; ++i)
+ {
+ if (diff.testBit(i))
+ {
+ naf[i - 1] = (byte)(k.testBit(i) ? -1 : 1);
+ ++i;
+ }
}
+ naf[digits - 1] = 1;
+
return naf;
}
@@ -210,6 +232,10 @@ public abstract class WNafUtil
{
throw new IllegalArgumentException("'width' must be in the range [2, 8]");
}
+ if (k.signum() == 0)
+ {
+ return EMPTY_BYTES;
+ }
byte[] wnaf = new byte[k.bitLength() + 1];
@@ -257,6 +283,11 @@ public abstract class WNafUtil
return wnaf;
}
+ public static WNafPreCompInfo getWNafPreCompInfo(ECPoint p)
+ {
+ return getWNafPreCompInfo(p.getCurve().getPreCompInfo(p, PRECOMP_NAME));
+ }
+
public static WNafPreCompInfo getWNafPreCompInfo(PreCompInfo preCompInfo)
{
if ((preCompInfo != null) && (preCompInfo instanceof WNafPreCompInfo))
@@ -298,6 +329,45 @@ public abstract class WNafUtil
return w + 2;
}
+ public static ECPoint mapPointWithPrecomp(ECPoint p, int width, boolean includeNegated,
+ ECPointMap pointMap)
+ {
+ ECCurve c = p.getCurve();
+ WNafPreCompInfo wnafPreCompP = precompute(p, width, includeNegated);
+
+ ECPoint q = pointMap.map(p);
+ WNafPreCompInfo wnafPreCompQ = getWNafPreCompInfo(c.getPreCompInfo(q, PRECOMP_NAME));
+
+ ECPoint twiceP = wnafPreCompP.getTwice();
+ if (twiceP != null)
+ {
+ ECPoint twiceQ = pointMap.map(twiceP);
+ wnafPreCompQ.setTwice(twiceQ);
+ }
+
+ ECPoint[] preCompP = wnafPreCompP.getPreComp();
+ ECPoint[] preCompQ = new ECPoint[preCompP.length];
+ for (int i = 0; i < preCompP.length; ++i)
+ {
+ preCompQ[i] = pointMap.map(preCompP[i]);
+ }
+ wnafPreCompQ.setPreComp(preCompQ);
+
+ if (includeNegated)
+ {
+ ECPoint[] preCompNegQ = new ECPoint[preCompQ.length];
+ for (int i = 0; i < preCompNegQ.length; ++i)
+ {
+ preCompNegQ[i] = preCompQ[i].negate();
+ }
+ wnafPreCompQ.setPreCompNeg(preCompNegQ);
+ }
+
+ c.setPreCompInfo(q, PRECOMP_NAME, wnafPreCompQ);
+
+ return q;
+ }
+
public static WNafPreCompInfo precompute(ECPoint p, int width, boolean includeNegated)
{
ECCurve c = p.getCurve();
@@ -324,7 +394,7 @@ public abstract class WNafUtil
ECPoint twiceP = wnafPreCompInfo.getTwice();
if (twiceP == null)
{
- twiceP = preComp[0].twice().normalize();
+ twiceP = preComp[0].twice();
wnafPreCompInfo.setTwice(twiceP);
}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519.java b/core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519.java
new file mode 100644
index 00000000..87802847
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519.java
@@ -0,0 +1,105 @@
+package org.bouncycastle.math.ec.custom.djb;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECFieldElement;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.ec.custom.sec.Nat256;
+import org.bouncycastle.math.field.FiniteFields;
+import org.bouncycastle.util.encoders.Hex;
+
+public class Curve25519 extends ECCurve
+{
+ public static final BigInteger q = Nat256.toBigInteger(Curve25519Field.P);
+
+ private static final int Curve25519_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED;
+
+ protected Curve25519Point infinity;
+
+ public Curve25519()
+ {
+ super(FiniteFields.getPrimeField(q));
+
+ this.infinity = new Curve25519Point(this, null, null);
+
+ this.a = fromBigInteger(new BigInteger(1,
+ Hex.decode("2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA984914A144")));
+ this.b = fromBigInteger(new BigInteger(1,
+ Hex.decode("7B425ED097B425ED097B425ED097B425ED097B425ED097B4260B5E9C7710C864")));
+ this.order = new BigInteger(1, Hex.decode("1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED"));
+ this.cofactor = BigInteger.valueOf(8);
+
+ this.coord = Curve25519_DEFAULT_COORDS;
+ }
+
+ protected ECCurve cloneCurve()
+ {
+ return new Curve25519();
+ }
+
+ public boolean supportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_JACOBIAN_MODIFIED:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public BigInteger getQ()
+ {
+ return q;
+ }
+
+ public int getFieldSize()
+ {
+ return q.bitLength();
+ }
+
+ public ECFieldElement fromBigInteger(BigInteger x)
+ {
+ return new Curve25519FieldElement(x);
+ }
+
+ protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)
+ {
+ return new Curve25519Point(this, x, y, withCompression);
+ }
+
+ protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+ {
+ return new Curve25519Point(this, x, y, zs, withCompression);
+ }
+
+ protected ECPoint decompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement x = fromBigInteger(X1);
+ ECFieldElement alpha = x.square().add(getA()).multiply(x).add(getB());
+ 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");
+ }
+
+ if (beta.testBitZero() != (yTilde == 1))
+ {
+ // Use the other root
+ beta = beta.negate();
+ }
+
+ return new Curve25519Point(this, x, beta, true);
+ }
+
+ public ECPoint getInfinity()
+ {
+ return infinity;
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Curve25519Field.java b/core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519Field.java
index 5cf9fea8..663e2fb3 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Curve25519Field.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519Field.java
@@ -1,11 +1,14 @@
-package org.bouncycastle.math.ec.custom.sec;
+package org.bouncycastle.math.ec.custom.djb;
import java.math.BigInteger;
import org.bouncycastle.math.ec.Nat;
+import org.bouncycastle.math.ec.custom.sec.Nat256;
public class Curve25519Field
{
+ private static final long M = 0xFFFFFFFFL;
+
// 2^255 - 2^4 - 2^1 - 1
static final int[] P = new int[]{ 0xFFFFFFED, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0x7FFFFFFF };
@@ -20,38 +23,34 @@ public class Curve25519Field
Nat256.add(x, y, z);
if (Nat256.gte(z, P))
{
- Nat256.addWord(PInv, z, 0);
- z[7] &= P7;
+ addPInvTo(z);
}
}
public static void addExt(int[] xx, int[] yy, int[] zz)
{
- Nat256.addExt(xx, yy, zz);
- if (Nat256.gteExt(zz, PExt))
+ Nat.add(16, xx, yy, zz);
+ if (Nat.gte(16, zz, PExt))
{
- Nat256.subExt(zz, PExt, zz);
+ subPExtFrom(zz);
}
}
public static void addOne(int[] x, int[] z)
{
- Nat256.copy(x, z);
- Nat256.inc(z, 0);
+ Nat.inc(8, x, z);
if (Nat256.gte(z, P))
{
- Nat256.addWord(PInv, z, 0);
- z[7] &= P7;
+ addPInvTo(z);
}
}
public static int[] fromBigInteger(BigInteger x)
{
int[] z = Nat256.fromBigInteger(x);
- if (Nat256.gte(z, P))
+ while (Nat256.gte(z, P))
{
- Nat256.addWord(PInv, z, 0);
- z[7] &= P7;
+ Nat256.subFrom(P, z);
}
return z;
}
@@ -93,16 +92,15 @@ public class Curve25519Field
// assert xx[15] >>> 30 == 0;
int xx07 = xx[7];
- Nat.shiftUpBit(8, xx, 8, xx07, z);
+ Nat.shiftUpBit(8, xx, 8, xx07, z, 0);
int c = Nat256.mulByWordAddTo(PInv, xx, z) << 1;
int z07 = z[7];
z[7] = z07 & P7;
c += (z07 >>> 31) - (xx07 >>> 31);
- Nat256.addWord(c * PInv, z, 0);
+ Nat.addWordTo(8, c * PInv, z);
if (Nat256.gte(z, P))
{
- Nat256.addWord(PInv, z, 0);
- z[7] &= P7;
+ addPInvTo(z);
}
}
@@ -133,27 +131,83 @@ public class Curve25519Field
int c = Nat256.sub(x, y, z);
if (c != 0)
{
- Nat256.subWord(PInv, z, 0);
- z[7] &= P7;
+ subPInvFrom(z);
}
}
public static void subtractExt(int[] xx, int[] yy, int[] zz)
{
- int c = Nat256.subExt(xx, yy, zz);
+ int c = Nat.sub(16, xx, yy, zz);
if (c != 0)
{
- Nat256.addExt(zz, PExt, zz);
+ addPExtTo(zz);
}
}
public static void twice(int[] x, int[] z)
{
- Nat256.shiftUpBit(x, 0, z);
+ Nat.shiftUpBit(8, x, 0, z);
if (Nat256.gte(z, P))
{
- Nat256.addWord(PInv, z, 0);
- z[7] &= P7;
+ addPInvTo(z);
+ }
+ }
+
+ private static void addPExtTo(int[] zz)
+ {
+ long c = (zz[0] & M) + (PExt[0] & M);
+ zz[0] = (int)c;
+ c >>= 32;
+
+ int i = 1 - (int)c;
+ i = (i << 3) - i;
+
+ while (++i < 16)
+ {
+ c += (zz[i] & M) + (PExt[i] & M);
+ zz[i] = (int)c;
+ c >>= 32;
+ }
+ }
+
+ private static void subPExtFrom(int[] zz)
+ {
+ long c = (zz[0] & M) - (PExt[0] & M);
+ zz[0] = (int)c;
+ c >>= 32;
+
+ int i = 1 + (int)c;
+ i = (i << 3) - i;
+
+ while (++i < 16)
+ {
+ c += (zz[i] & M) - (PExt[i] & M);
+ zz[i] = (int)c;
+ c >>= 32;
+ }
+ }
+
+ private static void addPInvTo(int[] z)
+ {
+ long c = (z[0] & M) + PInv;
+ z[0] = (int)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ Nat.incAt(8, z, 1);
+ }
+ z[7] &= P7;
+ }
+
+ private static void subPInvFrom(int[] z)
+ {
+ long c = (z[0] & M) - PInv;
+ z[0] = (int)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ Nat.decAt(8, z, 1);
}
+ z[7] &= P7;
}
}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519FieldElement.java b/core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519FieldElement.java
new file mode 100644
index 00000000..6e3d9cfa
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519FieldElement.java
@@ -0,0 +1,234 @@
+package org.bouncycastle.math.ec.custom.djb;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.math.ec.ECFieldElement;
+import org.bouncycastle.math.ec.Mod;
+import org.bouncycastle.math.ec.custom.sec.Nat256;
+import org.bouncycastle.util.Arrays;
+
+public class Curve25519FieldElement extends ECFieldElement
+{
+ public static final BigInteger Q = Curve25519.q;
+
+ // Calculated as ECConstants.TWO.modPow(Q.shiftRight(2), Q)
+ private static final int[] PRECOMP_POW2 = new int[]{ 0x4a0ea0b0, 0xc4ee1b27, 0xad2fe478, 0x2f431806,
+ 0x3dfbd7a7, 0x2b4d0099, 0x4fc1df0b, 0x2b832480 };
+
+ protected int[] x;
+
+ public Curve25519FieldElement(BigInteger x)
+ {
+ if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0)
+ {
+ throw new IllegalArgumentException("x value invalid for Curve25519FieldElement");
+ }
+
+ this.x = Curve25519Field.fromBigInteger(x);
+ }
+
+ public Curve25519FieldElement()
+ {
+ this.x = Nat256.create();
+ }
+
+ protected Curve25519FieldElement(int[] x)
+ {
+ this.x = x;
+ }
+
+ public boolean isZero()
+ {
+ return Nat256.isZero(x);
+ }
+
+ public boolean isOne()
+ {
+ return Nat256.isOne(x);
+ }
+
+ public boolean testBitZero()
+ {
+ return Nat256.getBit(x, 0) == 1;
+ }
+
+ public BigInteger toBigInteger()
+ {
+ return Nat256.toBigInteger(x);
+ }
+
+ public String getFieldName()
+ {
+ return "Curve25519Field";
+ }
+
+ public int getFieldSize()
+ {
+ return Q.bitLength();
+ }
+
+ public ECFieldElement add(ECFieldElement b)
+ {
+ int[] z = Nat256.create();
+ Curve25519Field.add(x, ((Curve25519FieldElement)b).x, z);
+ return new Curve25519FieldElement(z);
+ }
+
+ public ECFieldElement addOne()
+ {
+ int[] z = Nat256.create();
+ Curve25519Field.addOne(x, z);
+ return new Curve25519FieldElement(z);
+ }
+
+ public ECFieldElement subtract(ECFieldElement b)
+ {
+ int[] z = Nat256.create();
+ Curve25519Field.subtract(x, ((Curve25519FieldElement)b).x, z);
+ return new Curve25519FieldElement(z);
+ }
+
+ public ECFieldElement multiply(ECFieldElement b)
+ {
+ int[] z = Nat256.create();
+ Curve25519Field.multiply(x, ((Curve25519FieldElement)b).x, z);
+ return new Curve25519FieldElement(z);
+ }
+
+ public ECFieldElement divide(ECFieldElement b)
+ {
+// return multiply(b.invert());
+ int[] z = Nat256.create();
+ Mod.invert(Curve25519Field.P, ((Curve25519FieldElement)b).x, z);
+ Curve25519Field.multiply(z, x, z);
+ return new Curve25519FieldElement(z);
+ }
+
+ public ECFieldElement negate()
+ {
+ int[] z = Nat256.create();
+ Curve25519Field.negate(x, z);
+ return new Curve25519FieldElement(z);
+ }
+
+ public ECFieldElement square()
+ {
+ int[] z = Nat256.create();
+ Curve25519Field.square(x, z);
+ return new Curve25519FieldElement(z);
+ }
+
+ public ECFieldElement invert()
+ {
+// return new Curve25519FieldElement(toBigInteger().modInverse(Q));
+ int[] z = Nat256.create();
+ Mod.invert(Curve25519Field.P, x, z);
+ return new Curve25519FieldElement(z);
+ }
+
+ /**
+ * return a sqrt root - the routine verifies that the calculation returns the right value - if
+ * none exists it returns null.
+ */
+ public ECFieldElement sqrt()
+ {
+ /*
+ * Q == 8m + 5, so we use Pocklington's method for this case.
+ *
+ * First, raise this element to the exponent 2^252 - 2^1 (i.e. m + 1)
+ *
+ * Breaking up the exponent's binary representation into "repunits", we get:
+ * { 251 1s } { 1 0s }
+ *
+ * Therefore we need an addition chain containing 251 (the lengths of the repunits)
+ * We use: 1, 2, 3, 4, 7, 11, 15, 30, 60, 120, 131, [251]
+ */
+
+ int[] x1 = this.x;
+ if (Nat256.isZero(x1) || Nat256.isOne(x1))
+ {
+ return this;
+ }
+
+ int[] x2 = Nat256.create();
+ Curve25519Field.square(x1, x2);
+ Curve25519Field.multiply(x2, x1, x2);
+ int[] x3 = x2;
+ Curve25519Field.square(x2, x3);
+ Curve25519Field.multiply(x3, x1, x3);
+ int[] x4 = Nat256.create();
+ Curve25519Field.square(x3, x4);
+ Curve25519Field.multiply(x4, x1, x4);
+ int[] x7 = Nat256.create();
+ Curve25519Field.squareN(x4, 3, x7);
+ Curve25519Field.multiply(x7, x3, x7);
+ int[] x11 = x3;
+ Curve25519Field.squareN(x7, 4, x11);
+ Curve25519Field.multiply(x11, x4, x11);
+ int[] x15 = x7;
+ Curve25519Field.squareN(x11, 4, x15);
+ Curve25519Field.multiply(x15, x4, x15);
+ int[] x30 = x4;
+ Curve25519Field.squareN(x15, 15, x30);
+ Curve25519Field.multiply(x30, x15, x30);
+ int[] x60 = x15;
+ Curve25519Field.squareN(x30, 30, x60);
+ Curve25519Field.multiply(x60, x30, x60);
+ int[] x120 = x30;
+ Curve25519Field.squareN(x60, 60, x120);
+ Curve25519Field.multiply(x120, x60, x120);
+ int[] x131 = x60;
+ Curve25519Field.squareN(x120, 11, x131);
+ Curve25519Field.multiply(x131, x11, x131);
+ int[] x251 = x11;
+ Curve25519Field.squareN(x131, 120, x251);
+ Curve25519Field.multiply(x251, x120, x251);
+
+ int[] t1 = x251;
+ Curve25519Field.square(t1, t1);
+
+ int[] t2 = x120;
+ Curve25519Field.square(t1, t2);
+
+ if (Nat256.eq(x1, t2))
+ {
+ return new Curve25519FieldElement(t1);
+ }
+
+ /*
+ * If the first guess is incorrect, we multiply by a precomputed power of 2 to get the second guess,
+ * which is ((4x)^(m + 1))/2 mod Q
+ */
+ Curve25519Field.multiply(t1, PRECOMP_POW2, t1);
+
+ Curve25519Field.square(t1, t2);
+
+ if (Nat256.eq(x1, t2))
+ {
+ return new Curve25519FieldElement(t1);
+ }
+
+ return null;
+ }
+
+ public boolean equals(Object other)
+ {
+ if (other == this)
+ {
+ return true;
+ }
+
+ if (!(other instanceof Curve25519FieldElement))
+ {
+ return false;
+ }
+
+ Curve25519FieldElement o = (Curve25519FieldElement)other;
+ return Nat256.eq(x, o.x);
+ }
+
+ public int hashCode()
+ {
+ return Q.hashCode() ^ Arrays.hashCode(x, 0, 8);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519Point.java b/core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519Point.java
new file mode 100644
index 00000000..2913af99
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519Point.java
@@ -0,0 +1,304 @@
+package org.bouncycastle.math.ec.custom.djb;
+
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECFieldElement;
+import org.bouncycastle.math.ec.ECPoint;
+
+public class Curve25519Point 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
+ *
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public Curve25519Point(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
+ *
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)}
+ */
+ public Curve25519Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
+ {
+ super(curve, x, y);
+
+ if ((x == null) != (y == null))
+ {
+ throw new IllegalArgumentException("Exactly one of the field elements is null");
+ }
+
+ this.withCompression = withCompression;
+ }
+
+ Curve25519Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+ {
+ super(curve, x, y, zs);
+
+ this.withCompression = withCompression;
+ }
+
+ protected ECPoint detach()
+ {
+ return new Curve25519Point(null, getAffineXCoord(), getAffineYCoord());
+ }
+
+ protected boolean getCompressionYTilde()
+ {
+ return this.getAffineYCoord().testBitZero();
+ }
+
+ public ECFieldElement getZCoord(int index)
+ {
+ if (index == 1)
+ {
+ return getJacobianModifiedW();
+ }
+
+ return super.getZCoord(index);
+ }
+
+ // B.3 pg 62
+ public ECPoint add(ECPoint b)
+ {
+ if (this.isInfinity())
+ {
+ return b;
+ }
+ if (b.isInfinity())
+ {
+ return this;
+ }
+ if (this == b)
+ {
+ return twice();
+ }
+
+ ECCurve curve = this.getCurve();
+
+ ECFieldElement X1 = this.x, Y1 = this.y;
+ ECFieldElement X2 = b.getXCoord(), Y2 = b.getYCoord();
+
+ ECFieldElement Z1 = this.zs[0];
+ ECFieldElement Z2 = b.getZCoord(0);
+
+ boolean Z1IsOne = Z1.isOne();
+
+ ECFieldElement Z1Squared, U2, S2;
+ if (Z1IsOne)
+ {
+ Z1Squared = Z1; U2 = X2; S2 = Y2;
+ }
+ else
+ {
+ Z1Squared = Z1.square();
+ U2 = Z1Squared.multiply(X2);
+ ECFieldElement Z1Cubed = Z1Squared.multiply(Z1);
+ S2 = Z1Cubed.multiply(Y2);
+ }
+
+ boolean Z2IsOne = Z2.isOne();
+ ECFieldElement Z2Squared, U1, S1;
+ if (Z2IsOne)
+ {
+ Z2Squared = Z2; U1 = X1; S1 = Y1;
+ }
+ else
+ {
+ Z2Squared = Z2.square();
+ U1 = Z2Squared.multiply(X1);
+ ECFieldElement Z2Cubed = Z2Squared.multiply(Z2);
+ S1 = Z2Cubed.multiply(Y1);
+ }
+
+ ECFieldElement H = U1.subtract(U2);
+ ECFieldElement R = S1.subtract(S2);
+
+ // Check if b == this or b == -this
+ if (H.isZero())
+ {
+ if (R.isZero())
+ {
+ // this == b, i.e. this must be doubled
+ return this.twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return curve.getInfinity();
+ }
+
+ ECFieldElement HSquared = H.square();
+ ECFieldElement G = HSquared.multiply(H);
+ ECFieldElement V = HSquared.multiply(U1);
+
+ ECFieldElement X3 = R.square().add(G).subtract(two(V));
+ ECFieldElement Y3 = V.subtract(X3).multiplyMinusProduct(R, G, S1);
+
+ ECFieldElement Z3 = H;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.multiply(Z1);
+ }
+ if (!Z2IsOne)
+ {
+ Z3 = Z3.multiply(Z2);
+ }
+
+ ECFieldElement Z3Squared = (Z3 == H) ? HSquared : null;
+
+ // TODO If the result will only be used in a subsequent addition, we don't need W3
+ ECFieldElement W3 = calculateJacobianModifiedW(Z3, Z3Squared);
+
+ ECFieldElement[] zs = new ECFieldElement[]{ Z3, W3 };
+
+ return new Curve25519Point(curve, X3, Y3, zs, this.withCompression);
+ }
+
+ // B.3 pg 62
+ public ECPoint twice()
+ {
+ if (this.isInfinity())
+ {
+ return this;
+ }
+
+ ECCurve curve = this.getCurve();
+
+ ECFieldElement Y1 = this.y;
+ if (Y1.isZero())
+ {
+ return curve.getInfinity();
+ }
+
+ return twiceJacobianModified(true);
+ }
+
+ public ECPoint twicePlus(ECPoint b)
+ {
+ if (this == b)
+ {
+ return threeTimes();
+ }
+ if (this.isInfinity())
+ {
+ return b;
+ }
+ if (b.isInfinity())
+ {
+ return twice();
+ }
+
+ ECFieldElement Y1 = this.y;
+ if (Y1.isZero())
+ {
+ return b;
+ }
+
+ return twiceJacobianModified(false).add(b);
+ }
+
+ public ECPoint threeTimes()
+ {
+ if (this.isInfinity())
+ {
+ return this;
+ }
+
+ ECFieldElement Y1 = this.y;
+ if (Y1.isZero())
+ {
+ return this;
+ }
+
+ return twiceJacobianModified(false).add(this);
+ }
+
+ protected ECFieldElement two(ECFieldElement x)
+ {
+ return x.add(x);
+ }
+
+ protected ECFieldElement three(ECFieldElement x)
+ {
+ return two(x).add(x);
+ }
+
+ // 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()
+ {
+ if (this.isInfinity())
+ {
+ return this;
+ }
+
+ return new Curve25519Point(this.getCurve(), this.x, this.y.negate(), this.zs, this.withCompression);
+ }
+
+ protected ECFieldElement calculateJacobianModifiedW(ECFieldElement Z, ECFieldElement ZSquared)
+ {
+ ECFieldElement a4 = this.getCurve().getA();
+ if (Z.isOne())
+ {
+ return a4;
+ }
+
+ if (ZSquared == null)
+ {
+ ZSquared = Z.square();
+ }
+
+ return ZSquared.square().multiply(a4);
+ }
+
+ protected ECFieldElement getJacobianModifiedW()
+ {
+ ECFieldElement W = this.zs[1];
+ if (W == null)
+ {
+ // NOTE: Rarely, twicePlus will result in the need for a lazy W1 calculation here
+ this.zs[1] = W = calculateJacobianModifiedW(this.zs[0], null);
+ }
+ return W;
+ }
+
+ protected Curve25519Point twiceJacobianModified(boolean calculateW)
+ {
+ ECFieldElement X1 = this.x, Y1 = this.y, Z1 = this.zs[0], W1 = getJacobianModifiedW();
+
+ ECFieldElement X1Squared = X1.square();
+ ECFieldElement M = three(X1Squared).add(W1);
+ ECFieldElement _2Y1 = two(Y1);
+ ECFieldElement _2Y1Squared = _2Y1.multiply(Y1);
+ ECFieldElement S = two(X1.multiply(_2Y1Squared));
+ ECFieldElement X3 = M.square().subtract(two(S));
+ ECFieldElement _4T = _2Y1Squared.square();
+ ECFieldElement _8T = two(_4T);
+ ECFieldElement Y3 = M.multiply(S.subtract(X3)).subtract(_8T);
+ ECFieldElement W3 = calculateW ? two(_8T.multiply(W1)) : null;
+ ECFieldElement Z3 = Z1.isOne() ? _2Y1 : _2Y1.multiply(Z1);
+
+ return new Curve25519Point(this.getCurve(), X3, Y3, new ECFieldElement[]{ Z3, W3 }, this.withCompression);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat192.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat192.java
index 6351a64c..c622350a 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat192.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat192.java
@@ -3,6 +3,7 @@ package org.bouncycastle.math.ec.custom.sec;
import java.math.BigInteger;
import org.bouncycastle.crypto.util.Pack;
+import org.bouncycastle.math.ec.Nat;
public abstract class Nat192
{
@@ -56,64 +57,92 @@ public abstract class Nat192
return (int)c;
}
- // TODO Re-write to allow full range for x?
- public static int addDWord(long x, int[] z, int zOff)
+ public static int addTo(int[] x, int[] z)
{
- // assert zOff <= 4;
- long c = x;
- c += (z[zOff + 0] & M);
- z[zOff + 0] = (int)c;
+ long c = 0;
+ c += (x[0] & M) + (z[0] & M);
+ z[0] = (int)c;
c >>>= 32;
- c += (z[zOff + 1] & M);
- z[zOff + 1] = (int)c;
+ c += (x[1] & M) + (z[1] & M);
+ z[1] = (int)c;
+ c >>>= 32;
+ c += (x[2] & M) + (z[2] & M);
+ z[2] = (int)c;
+ c >>>= 32;
+ c += (x[3] & M) + (z[3] & M);
+ z[3] = (int)c;
+ c >>>= 32;
+ c += (x[4] & M) + (z[4] & M);
+ z[4] = (int)c;
+ c >>>= 32;
+ c += (x[5] & M) + (z[5] & M);
+ z[5] = (int)c;
c >>>= 32;
- return c == 0 ? 0 : inc(z, zOff + 2);
+ return (int)c;
}
- public static int addExt(int[] xx, int[] yy, int[] zz)
+ public static int addTo(int[] x, int xOff, int[] z, int zOff, int cIn)
{
- long c = 0;
- for (int i = 0; i < 12; ++i)
- {
- c += (xx[i] & M) + (yy[i] & M);
- zz[i] = (int)c;
- c >>>= 32;
- }
+ long c = cIn & M;
+ c += (x[xOff + 0] & M) + (z[zOff + 0] & M);
+ z[zOff + 0] = (int)c;
+ c >>>= 32;
+ c += (x[xOff + 1] & M) + (z[zOff + 1] & M);
+ z[zOff + 1] = (int)c;
+ c >>>= 32;
+ c += (x[xOff + 2] & M) + (z[zOff + 2] & M);
+ z[zOff + 2] = (int)c;
+ c >>>= 32;
+ c += (x[xOff + 3] & M) + (z[zOff + 3] & M);
+ z[zOff + 3] = (int)c;
+ c >>>= 32;
+ c += (x[xOff + 4] & M) + (z[zOff + 4] & M);
+ z[zOff + 4] = (int)c;
+ c >>>= 32;
+ c += (x[xOff + 5] & M) + (z[zOff + 5] & M);
+ z[zOff + 5] = (int)c;
+ c >>>= 32;
return (int)c;
}
- public static int addToExt(int[] x, int xOff, int[] zz, int zzOff)
+ public static int addToEachOther(int[] u, int uOff, int[] v, int vOff)
{
- // assert zzOff <= 6;
long c = 0;
- c += (x[xOff + 0] & M) + (zz[zzOff + 0] & M);
- zz[zzOff + 0] = (int)c;
+ c += (u[uOff + 0] & M) + (v[vOff + 0] & M);
+ u[uOff + 0] = (int)c;
+ v[vOff + 0] = (int)c;
c >>>= 32;
- c += (x[xOff + 1] & M) + (zz[zzOff + 1] & M);
- zz[zzOff + 1] = (int)c;
+ c += (u[uOff + 1] & M) + (v[vOff + 1] & M);
+ u[uOff + 1] = (int)c;
+ v[vOff + 1] = (int)c;
c >>>= 32;
- c += (x[xOff + 2] & M) + (zz[zzOff + 2] & M);
- zz[zzOff + 2] = (int)c;
+ c += (u[uOff + 2] & M) + (v[vOff + 2] & M);
+ u[uOff + 2] = (int)c;
+ v[vOff + 2] = (int)c;
c >>>= 32;
- c += (x[xOff + 3] & M) + (zz[zzOff + 3] & M);
- zz[zzOff + 3] = (int)c;
+ c += (u[uOff + 3] & M) + (v[vOff + 3] & M);
+ u[uOff + 3] = (int)c;
+ v[vOff + 3] = (int)c;
c >>>= 32;
- c += (x[xOff + 4] & M) + (zz[zzOff + 4] & M);
- zz[zzOff + 4] = (int)c;
+ c += (u[uOff + 4] & M) + (v[vOff + 4] & M);
+ u[uOff + 4] = (int)c;
+ v[vOff + 4] = (int)c;
c >>>= 32;
- c += (x[xOff + 5] & M) + (zz[zzOff + 5] & M);
- zz[zzOff + 5] = (int)c;
+ c += (u[uOff + 5] & M) + (v[vOff + 5] & M);
+ u[uOff + 5] = (int)c;
+ v[vOff + 5] = (int)c;
c >>>= 32;
return (int)c;
}
- public static int addWordExt(int x, int[] zz, int zzOff)
+ public static void copy(int[] x, int[] z)
{
- // assert zzOff <= 11;
- long c = (x & M) + (zz[zzOff + 0] & M);
- zz[zzOff + 0] = (int)c;
- c >>>= 32;
- return c == 0 ? 0 : incExt(zz, zzOff + 1);
+ z[0] = x[0];
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ z[4] = x[4];
+ z[5] = x[5];
}
public static int[] create()
@@ -126,17 +155,30 @@ public abstract class Nat192
return new int[12];
}
- public static int dec(int[] z, int zOff)
+ public static boolean diff(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
{
- // assert zOff <= 6;
- for (int i = zOff; i < 6; ++i)
+ boolean pos = gte(x, xOff, y, yOff);
+ if (pos)
+ {
+ sub(x, xOff, y, yOff, z, zOff);
+ }
+ else
{
- if (--z[i] != -1)
+ sub(y, yOff, x, xOff, z, zOff);
+ }
+ return pos;
+ }
+
+ public static boolean eq(int[] x, int[] y)
+ {
+ for (int i = 5; i >= 0; --i)
+ {
+ if (x[i] != y[i])
{
- return 0;
+ return false;
}
}
- return -1;
+ return true;
}
public static int[] fromBigInteger(BigInteger x)
@@ -185,46 +227,20 @@ public abstract class Nat192
return true;
}
- public static boolean gteExt(int[] xx, int[] yy)
+ public static boolean gte(int[] x, int xOff, int[] y, int yOff)
{
- for (int i = 11; i >= 0; --i)
+ for (int i = 5; i >= 0; --i)
{
- int xx_i = xx[i] ^ Integer.MIN_VALUE;
- int yy_i = yy[i] ^ Integer.MIN_VALUE;
- if (xx_i < yy_i)
+ int x_i = x[xOff + i] ^ Integer.MIN_VALUE;
+ int y_i = y[yOff + i] ^ Integer.MIN_VALUE;
+ if (x_i < y_i)
return false;
- if (xx_i > yy_i)
+ if (x_i > y_i)
return true;
}
return true;
}
- public static int inc(int[] z, int zOff)
- {
- // assert zOff <= 6;
- for (int i = zOff; i < 6; ++i)
- {
- if (++z[i] != 0)
- {
- return 0;
- }
- }
- return 1;
- }
-
- public static int incExt(int[] zz, int zzOff)
- {
- // assert zzOff <= 12;
- for (int i = zzOff; i < 12; ++i)
- {
- if (++zz[i] != 0)
- {
- return 0;
- }
- }
- return 1;
- }
-
public static boolean isOne(int[] x)
{
if (x[0] != 1)
@@ -253,18 +269,6 @@ public abstract class Nat192
return true;
}
- public static boolean isZeroExt(int[] xx)
- {
- for (int i = 0; i < 12; ++i)
- {
- if (xx[i] != 0)
- {
- return false;
- }
- }
- return true;
- }
-
public static void mul(int[] x, int[] y, int[] zz)
{
long y_0 = y[0] & M;
@@ -322,39 +326,171 @@ public abstract class Nat192
}
}
- public static long mul33AddExt(int w, int[] xx, int xxOff, int[] yy, int yyOff, int[] zz, int zzOff)
+ public static void mul(int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff)
{
- // assert x >>> 31 == 0;
- // assert xxOff <= 6;
- // assert yyOff <= 6;
- // assert zzOff <= 6;
+ long y_0 = y[yOff + 0] & M;
+ long y_1 = y[yOff + 1] & M;
+ long y_2 = y[yOff + 2] & M;
+ long y_3 = y[yOff + 3] & M;
+ long y_4 = y[yOff + 4] & M;
+ long y_5 = y[yOff + 5] & M;
+
+ {
+ long c = 0, x_0 = x[xOff + 0] & M;
+ c += x_0 * y_0;
+ zz[zzOff + 0] = (int)c;
+ c >>>= 32;
+ c += x_0 * y_1;
+ zz[zzOff + 1] = (int)c;
+ c >>>= 32;
+ c += x_0 * y_2;
+ zz[zzOff + 2] = (int)c;
+ c >>>= 32;
+ c += x_0 * y_3;
+ zz[zzOff + 3] = (int)c;
+ c >>>= 32;
+ c += x_0 * y_4;
+ zz[zzOff + 4] = (int)c;
+ c >>>= 32;
+ c += x_0 * y_5;
+ zz[zzOff + 5] = (int)c;
+ c >>>= 32;
+ zz[zzOff + 6] = (int)c;
+ }
+
+ for (int i = 1; i < 6; ++i)
+ {
+ ++zzOff;
+ long c = 0, x_i = x[xOff + i] & M;
+ c += x_i * y_0 + (zz[zzOff + 0] & M);
+ zz[zzOff + 0] = (int)c;
+ c >>>= 32;
+ c += x_i * y_1 + (zz[zzOff + 1] & M);
+ zz[zzOff + 1] = (int)c;
+ c >>>= 32;
+ c += x_i * y_2 + (zz[zzOff + 2] & M);
+ zz[zzOff + 2] = (int)c;
+ c >>>= 32;
+ c += x_i * y_3 + (zz[zzOff + 3] & M);
+ zz[zzOff + 3] = (int)c;
+ c >>>= 32;
+ c += x_i * y_4 + (zz[zzOff + 4] & M);
+ zz[zzOff + 4] = (int)c;
+ c >>>= 32;
+ c += x_i * y_5 + (zz[zzOff + 5] & M);
+ zz[zzOff + 5] = (int)c;
+ c >>>= 32;
+ zz[zzOff + 6] = (int)c;
+ }
+ }
+
+ public static int mulAddTo(int[] x, int[] y, int[] zz)
+ {
+ long y_0 = y[0] & M;
+ long y_1 = y[1] & M;
+ long y_2 = y[2] & M;
+ long y_3 = y[3] & M;
+ long y_4 = y[4] & M;
+ long y_5 = y[5] & M;
+
+ long zc = 0;
+ for (int i = 0; i < 6; ++i)
+ {
+ long c = 0, x_i = x[i] & M;
+ c += x_i * y_0 + (zz[i + 0] & M);
+ zz[i + 0] = (int)c;
+ c >>>= 32;
+ c += x_i * y_1 + (zz[i + 1] & M);
+ zz[i + 1] = (int)c;
+ c >>>= 32;
+ c += x_i * y_2 + (zz[i + 2] & M);
+ zz[i + 2] = (int)c;
+ c >>>= 32;
+ c += x_i * y_3 + (zz[i + 3] & M);
+ zz[i + 3] = (int)c;
+ c >>>= 32;
+ c += x_i * y_4 + (zz[i + 4] & M);
+ zz[i + 4] = (int)c;
+ c >>>= 32;
+ c += x_i * y_5 + (zz[i + 5] & M);
+ zz[i + 5] = (int)c;
+ c >>>= 32;
+ c += zc + (zz[i + 6] & M);
+ zz[i + 6] = (int)c;
+ zc = c >>> 32;
+ }
+ return (int)zc;
+ }
+
+ public static int mulAddTo(int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff)
+ {
+ long y_0 = y[yOff + 0] & M;
+ long y_1 = y[yOff + 1] & M;
+ long y_2 = y[yOff + 2] & M;
+ long y_3 = y[yOff + 3] & M;
+ long y_4 = y[yOff + 4] & M;
+ long y_5 = y[yOff + 5] & M;
+
+ long zc = 0;
+ for (int i = 0; i < 6; ++i)
+ {
+ long c = 0, x_i = x[xOff + i] & M;
+ c += x_i * y_0 + (zz[zzOff + 0] & M);
+ zz[zzOff + 0] = (int)c;
+ c >>>= 32;
+ c += x_i * y_1 + (zz[zzOff + 1] & M);
+ zz[zzOff + 1] = (int)c;
+ c >>>= 32;
+ c += x_i * y_2 + (zz[zzOff + 2] & M);
+ zz[zzOff + 2] = (int)c;
+ c >>>= 32;
+ c += x_i * y_3 + (zz[zzOff + 3] & M);
+ zz[zzOff + 3] = (int)c;
+ c >>>= 32;
+ c += x_i * y_4 + (zz[zzOff + 4] & M);
+ zz[zzOff + 4] = (int)c;
+ c >>>= 32;
+ c += x_i * y_5 + (zz[zzOff + 5] & M);
+ zz[zzOff + 5] = (int)c;
+ c >>>= 32;
+ c += zc + (zz[zzOff + 6] & M);
+ zz[zzOff + 6] = (int)c;
+ zc = c >>> 32;
+ ++zzOff;
+ }
+ return (int)zc;
+ }
+
+ public static long mul33Add(int w, int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
+ {
+ // assert w >>> 31 == 0;
long c = 0, wVal = w & M;
- long xx00 = xx[xxOff + 0] & M;
- c += wVal * xx00 + (yy[yyOff + 0] & M);
- zz[zzOff + 0] = (int)c;
+ long x0 = x[xOff + 0] & M;
+ c += wVal * x0 + (y[yOff + 0] & M);
+ z[zOff + 0] = (int)c;
c >>>= 32;
- long xx01 = xx[xxOff + 1] & M;
- c += wVal * xx01 + xx00 + (yy[yyOff + 1] & M);
- zz[zzOff + 1] = (int)c;
+ long x1 = x[xOff + 1] & M;
+ c += wVal * x1 + x0 + (y[yOff + 1] & M);
+ z[zOff + 1] = (int)c;
c >>>= 32;
- long xx02 = xx[xxOff + 2] & M;
- c += wVal * xx02 + xx01 + (yy[yyOff + 2] & M);
- zz[zzOff + 2] = (int)c;
+ long x2 = x[xOff + 2] & M;
+ c += wVal * x2 + x1 + (y[yOff + 2] & M);
+ z[zOff + 2] = (int)c;
c >>>= 32;
- long xx03 = xx[xxOff + 3] & M;
- c += wVal * xx03 + xx02 + (yy[yyOff + 3] & M);
- zz[zzOff + 3] = (int)c;
+ long x3 = x[xOff + 3] & M;
+ c += wVal * x3 + x2 + (y[yOff + 3] & M);
+ z[zOff + 3] = (int)c;
c >>>= 32;
- long xx04 = xx[xxOff + 4] & M;
- c += wVal * xx04 + xx03 + (yy[yyOff + 4] & M);
- zz[zzOff + 4] = (int)c;
+ long x4 = x[xOff + 4] & M;
+ c += wVal * x4 + x3 + (y[yOff + 4] & M);
+ z[zOff + 4] = (int)c;
c >>>= 32;
- long xx05 = xx[xxOff + 5] & M;
- c += wVal * xx05 + xx04 + (yy[yyOff + 5] & M);
- zz[zzOff + 5] = (int)c;
+ long x5 = x[xOff + 5] & M;
+ c += wVal * x5 + x4 + (y[yOff + 5] & M);
+ z[zOff + 5] = (int)c;
c >>>= 32;
- c += xx05;
+ c += x5;
return c;
}
@@ -404,7 +540,25 @@ public abstract class Nat192
c += (z[zOff + 3] & M);
z[zOff + 3] = (int)c;
c >>>= 32;
- return c == 0 ? 0 : inc(z, zOff + 4);
+ return c == 0 ? 0 : Nat.incAt(6, z, zOff, 4);
+ }
+
+ public static int mul33WordAdd(int x, int y, int[] z, int zOff)
+ {
+ // assert x >>> 31 == 0;
+ // assert zOff <= 3;
+
+ long c = 0, xVal = x & M, yVal = y & M;
+ c += yVal * xVal + (z[zOff + 0] & M);
+ z[zOff + 0] = (int)c;
+ c >>>= 32;
+ c += yVal + (z[zOff + 1] & M);
+ z[zOff + 1] = (int)c;
+ c >>>= 32;
+ c += (z[zOff + 2] & M);
+ z[zOff + 2] = (int)c;
+ c >>>= 32;
+ return c == 0 ? 0 : Nat.incAt(6, z, zOff, 3);
}
public static int mulWordDwordAdd(int x, long y, int[] z, int zOff)
@@ -420,102 +574,31 @@ public abstract class Nat192
c += (z[zOff + 2] & M);
z[zOff + 2] = (int)c;
c >>>= 32;
- return c == 0 ? 0 : inc(z, zOff + 3);
+ return c == 0 ? 0 : Nat.incAt(6, z, zOff, 3);
}
- public static int mulWordExt(int x, int[] y, int[] zz, int zzOff)
+ public static int mulWord(int x, int[] y, int[] z, int zOff)
{
- // assert zzOff <= 6;
long c = 0, xVal = x & M;
int i = 0;
do
{
c += xVal * (y[i] & M);
- zz[zzOff + i] = (int)c;
+ z[zOff + i] = (int)c;
c >>>= 32;
}
while (++i < 6);
return (int)c;
}
- public static int shiftDownBit(int[] x, int xLen, int c)
- {
- int i = xLen;
- while (--i >= 0)
- {
- int next = x[i];
- x[i] = (next >>> 1) | (c << 31);
- c = next;
- }
- return c << 31;
- }
-
- public static int shiftDownBit(int[] x, int c, int[] z)
- {
- int i = 6;
- while (--i >= 0)
- {
- int next = x[i];
- z[i] = (next >>> 1) | (c << 31);
- c = next;
- }
- return c << 31;
- }
-
- public static int shiftDownBits(int[] x, int xLen, int bits, int c)
- {
-// assert bits > 0 && bits < 32;
- int i = xLen;
- while (--i >= 0)
- {
- int next = x[i];
- x[i] = (next >>> bits) | (c << -bits);
- c = next;
- }
- return c << -bits;
- }
-
- public static int shiftDownWord(int[] x, int xLen, int c)
- {
- int i = xLen;
- while (--i >= 0)
- {
- int next = x[i];
- x[i] = c;
- c = next;
- }
- return c;
- }
-
- public static int shiftUpBit(int[] x, int xLen, int c)
- {
- for (int i = 0; i < xLen; ++i)
- {
- int next = x[i];
- x[i] = (next << 1) | (c >>> 31);
- c = next;
- }
- return c >>> 31;
- }
-
- public static int shiftUpBit(int[] x, int c, int[] z)
- {
- for (int i = 0; i < 6; ++i)
- {
- int next = x[i];
- z[i] = (next << 1) | (c >>> 31);
- c = next;
- }
- return c >>> 31;
- }
-
public static void square(int[] x, int[] zz)
{
long x_0 = x[0] & M;
long zz_1;
+ int c = 0, w;
{
- int c = 0, i = 5, j = 12;
+ int i = 5, j = 12;
do
{
long xVal = (x[i--] & M);
@@ -529,7 +612,8 @@ public abstract class Nat192
{
long p = x_0 * x_0;
zz_1 = ((c << 31) & M) | (p >>> 33);
- zz[0] = (int)(p >>> 1);
+ zz[0] = (int)p;
+ c = (int)(p >>> 32) & 1;
}
}
@@ -538,7 +622,9 @@ public abstract class Nat192
{
zz_1 += x_1 * x_0;
- zz[1] = (int)zz_1;
+ w = (int)zz_1;
+ zz[1] = (w << 1) | c;
+ c = w >>> 31;
zz_2 += zz_1 >>> 32;
}
@@ -547,7 +633,9 @@ public abstract class Nat192
long zz_4 = zz[4] & M;
{
zz_2 += x_2 * x_0;
- zz[2] = (int)zz_2;
+ w = (int)zz_2;
+ zz[2] = (w << 1) | c;
+ c = w >>> 31;
zz_3 += (zz_2 >>> 32) + x_2 * x_1;
zz_4 += zz_3 >>> 32;
zz_3 &= M;
@@ -558,7 +646,9 @@ public abstract class Nat192
long zz_6 = zz[6] & M;
{
zz_3 += x_3 * x_0;
- zz[3] = (int)zz_3;
+ w = (int)zz_3;
+ zz[3] = (w << 1) | c;
+ c = w >>> 31;
zz_4 += (zz_3 >>> 32) + x_3 * x_1;
zz_5 += (zz_4 >>> 32) + x_3 * x_2;
zz_4 &= M;
@@ -571,7 +661,9 @@ public abstract class Nat192
long zz_8 = zz[8] & M;
{
zz_4 += x_4 * x_0;
- zz[4] = (int)zz_4;
+ w = (int)zz_4;
+ zz[4] = (w << 1) | c;
+ c = w >>> 31;
zz_5 += (zz_4 >>> 32) + x_4 * x_1;
zz_6 += (zz_5 >>> 32) + x_4 * x_2;
zz_5 &= M;
@@ -586,7 +678,9 @@ public abstract class Nat192
long zz_10 = zz[10] & M;
{
zz_5 += x_5 * x_0;
- zz[5] = (int)zz_5;
+ w = (int)zz_5;
+ zz[5] = (w << 1) | c;
+ c = w >>> 31;
zz_6 += (zz_5 >>> 32) + x_5 * x_1;
zz_7 += (zz_6 >>> 32) + x_5 * x_2;
zz_8 += (zz_7 >>> 32) + x_5 * x_3;
@@ -594,29 +688,139 @@ public abstract class Nat192
zz_10 += zz_9 >>> 32;
}
- zz[6] = (int)zz_6;
- zz[7] = (int)zz_7;
- zz[8] = (int)zz_8;
- zz[9] = (int)zz_9;
- zz[10] = (int)zz_10;
- zz[11] += (int)(zz_10 >>> 32);
+ w = (int)zz_6;
+ zz[6] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_7;
+ zz[7] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_8;
+ zz[8] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_9;
+ zz[9] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_10;
+ zz[10] = (w << 1) | c;
+ c = w >>> 31;
+ w = zz[11] + (int)(zz_10 >> 32);
+ zz[11] = (w << 1) | c;
+ }
+
+ public static void square(int[] x, int xOff, int[] zz, int zzOff)
+ {
+ long x_0 = x[xOff + 0] & M;
+ long zz_1;
- shiftUpBit(zz, 12, (int)x_0 << 31);
- }
+ int c = 0, w;
+ {
+ int i = 5, j = 12;
+ do
+ {
+ long xVal = (x[xOff + i--] & M);
+ long p = xVal * xVal;
+ zz[zzOff + --j] = (c << 31) | (int)(p >>> 33);
+ zz[zzOff + --j] = (int)(p >>> 1);
+ c = (int)p;
+ }
+ while (i > 0);
+
+ {
+ long p = x_0 * x_0;
+ zz_1 = ((c << 31) & M) | (p >>> 33);
+ zz[zzOff + 0] = (int)p;
+ c = (int)(p >>> 32) & 1;
+ }
+ }
+
+ long x_1 = x[xOff + 1] & M;
+ long zz_2 = zz[zzOff + 2] & M;
- public static int squareWordAddExt(int[] x, int xPos, int[] zz)
- {
- // assert xPos > 0 && xPos < 6;
- long c = 0, xVal = x[xPos] & M;
- int i = 0;
- do
{
- c += xVal * (x[i] & M) + (zz[xPos + i] & M);
- zz[xPos + i] = (int)c;
- c >>>= 32;
+ zz_1 += x_1 * x_0;
+ w = (int)zz_1;
+ zz[zzOff + 1] = (w << 1) | c;
+ c = w >>> 31;
+ zz_2 += zz_1 >>> 32;
}
- while (++i < xPos);
- return (int)c;
+
+ long x_2 = x[xOff + 2] & M;
+ long zz_3 = zz[zzOff + 3] & M;
+ long zz_4 = zz[zzOff + 4] & M;
+ {
+ zz_2 += x_2 * x_0;
+ w = (int)zz_2;
+ zz[zzOff + 2] = (w << 1) | c;
+ c = w >>> 31;
+ zz_3 += (zz_2 >>> 32) + x_2 * x_1;
+ zz_4 += zz_3 >>> 32;
+ zz_3 &= M;
+ }
+
+ long x_3 = x[xOff + 3] & M;
+ long zz_5 = zz[zzOff + 5] & M;
+ long zz_6 = zz[zzOff + 6] & M;
+ {
+ zz_3 += x_3 * x_0;
+ w = (int)zz_3;
+ zz[zzOff + 3] = (w << 1) | c;
+ c = w >>> 31;
+ zz_4 += (zz_3 >>> 32) + x_3 * x_1;
+ zz_5 += (zz_4 >>> 32) + x_3 * x_2;
+ zz_4 &= M;
+ zz_6 += zz_5 >>> 32;
+ zz_5 &= M;
+ }
+
+ long x_4 = x[xOff + 4] & M;
+ long zz_7 = zz[zzOff + 7] & M;
+ long zz_8 = zz[zzOff + 8] & M;
+ {
+ zz_4 += x_4 * x_0;
+ w = (int)zz_4;
+ zz[zzOff + 4] = (w << 1) | c;
+ c = w >>> 31;
+ zz_5 += (zz_4 >>> 32) + x_4 * x_1;
+ zz_6 += (zz_5 >>> 32) + x_4 * x_2;
+ zz_5 &= M;
+ zz_7 += (zz_6 >>> 32) + x_4 * x_3;
+ zz_6 &= M;
+ zz_8 += zz_7 >>> 32;
+ zz_7 &= M;
+ }
+
+ long x_5 = x[xOff + 5] & M;
+ long zz_9 = zz[zzOff + 9] & M;
+ long zz_10 = zz[zzOff + 10] & M;
+ {
+ zz_5 += x_5 * x_0;
+ w = (int)zz_5;
+ zz[zzOff + 5] = (w << 1) | c;
+ c = w >>> 31;
+ zz_6 += (zz_5 >>> 32) + x_5 * x_1;
+ zz_7 += (zz_6 >>> 32) + x_5 * x_2;
+ zz_8 += (zz_7 >>> 32) + x_5 * x_3;
+ zz_9 += (zz_8 >>> 32) + x_5 * x_4;
+ zz_10 += zz_9 >>> 32;
+ }
+
+ w = (int)zz_6;
+ zz[zzOff + 6] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_7;
+ zz[zzOff + 7] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_8;
+ zz[zzOff + 8] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_9;
+ zz[zzOff + 9] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_10;
+ zz[zzOff + 10] = (w << 1) | c;
+ c = w >>> 31;
+ w = zz[zzOff + 11] + (int)(zz_10 >> 32);
+ zz[zzOff + 11] = (w << 1) | c;
}
public static int sub(int[] x, int[] y, int[] z)
@@ -643,6 +847,30 @@ public abstract class Nat192
return (int)c;
}
+ public static int sub(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
+ {
+ long c = 0;
+ c += (x[xOff + 0] & M) - (y[yOff + 0] & M);
+ z[zOff + 0] = (int)c;
+ c >>= 32;
+ c += (x[xOff + 1] & M) - (y[yOff + 1] & M);
+ z[zOff + 1] = (int)c;
+ c >>= 32;
+ c += (x[xOff + 2] & M) - (y[yOff + 2] & M);
+ z[zOff + 2] = (int)c;
+ c >>= 32;
+ c += (x[xOff + 3] & M) - (y[yOff + 3] & M);
+ z[zOff + 3] = (int)c;
+ c >>= 32;
+ c += (x[xOff + 4] & M) - (y[yOff + 4] & M);
+ z[zOff + 4] = (int)c;
+ c >>= 32;
+ c += (x[xOff + 5] & M) - (y[yOff + 5] & M);
+ z[zOff + 5] = (int)c;
+ c >>= 32;
+ return (int)c;
+ }
+
public static int subBothFrom(int[] x, int[] y, int[] z)
{
long c = 0;
@@ -667,52 +895,50 @@ public abstract class Nat192
return (int)c;
}
- // TODO Re-write to allow full range for x?
- public static int subDWord(long x, int[] z)
+ public static int subFrom(int[] x, int[] z)
{
- long c = -x;
- c += (z[0] & M);
+ long c = 0;
+ c += (z[0] & M) - (x[0] & M);
z[0] = (int)c;
c >>= 32;
- c += (z[1] & M);
+ c += (z[1] & M) - (x[1] & M);
z[1] = (int)c;
c >>= 32;
- return c == 0 ? 0 : dec(z, 2);
- }
-
- public static int subExt(int[] xx, int[] yy, int[] zz)
- {
- long c = 0;
- for (int i = 0; i < 12; ++i)
- {
- c += (xx[i] & M) - (yy[i] & M);
- zz[i] = (int)c;
- c >>= 32;
- }
+ c += (z[2] & M) - (x[2] & M);
+ z[2] = (int)c;
+ c >>= 32;
+ c += (z[3] & M) - (x[3] & M);
+ z[3] = (int)c;
+ c >>= 32;
+ c += (z[4] & M) - (x[4] & M);
+ z[4] = (int)c;
+ c >>= 32;
+ c += (z[5] & M) - (x[5] & M);
+ z[5] = (int)c;
+ c >>= 32;
return (int)c;
}
- public static int subFromExt(int[] x, int xOff, int[] zz, int zzOff)
+ public static int subFrom(int[] x, int xOff, int[] z, int zOff)
{
- // assert zzOff <= 6;
long c = 0;
- c += (zz[zzOff + 0] & M) - (x[xOff + 0] & M);
- zz[zzOff + 0] = (int)c;
+ c += (z[zOff + 0] & M) - (x[xOff + 0] & M);
+ z[zOff + 0] = (int)c;
c >>= 32;
- c += (zz[zzOff + 1] & M) - (x[xOff + 1] & M);
- zz[zzOff + 1] = (int)c;
+ c += (z[zOff + 1] & M) - (x[xOff + 1] & M);
+ z[zOff + 1] = (int)c;
c >>= 32;
- c += (zz[zzOff + 2] & M) - (x[xOff + 2] & M);
- zz[zzOff + 2] = (int)c;
+ c += (z[zOff + 2] & M) - (x[xOff + 2] & M);
+ z[zOff + 2] = (int)c;
c >>= 32;
- c += (zz[zzOff + 3] & M) - (x[xOff + 3] & M);
- zz[zzOff + 3] = (int)c;
+ c += (z[zOff + 3] & M) - (x[xOff + 3] & M);
+ z[zOff + 3] = (int)c;
c >>= 32;
- c += (zz[zzOff + 4] & M) - (x[xOff + 4] & M);
- zz[zzOff + 4] = (int)c;
+ c += (z[zOff + 4] & M) - (x[xOff + 4] & M);
+ z[zOff + 4] = (int)c;
c >>= 32;
- c += (zz[zzOff + 5] & M) - (x[xOff + 5] & M);
- zz[zzOff + 5] = (int)c;
+ c += (z[zOff + 5] & M) - (x[xOff + 5] & M);
+ z[zOff + 5] = (int)c;
c >>= 32;
return (int)c;
}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat224.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat224.java
new file mode 100644
index 00000000..8f1a66dc
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat224.java
@@ -0,0 +1,1183 @@
+package org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.crypto.util.Pack;
+import org.bouncycastle.math.ec.Nat;
+
+public abstract class Nat224
+{
+ private static final long M = 0xFFFFFFFFL;
+
+ public static int add(int[] x, int[] y, int[] z)
+ {
+ long c = 0;
+ c += (x[0] & M) + (y[0] & M);
+ z[0] = (int)c;
+ c >>>= 32;
+ c += (x[1] & M) + (y[1] & M);
+ z[1] = (int)c;
+ c >>>= 32;
+ c += (x[2] & M) + (y[2] & M);
+ z[2] = (int)c;
+ c >>>= 32;
+ c += (x[3] & M) + (y[3] & M);
+ z[3] = (int)c;
+ c >>>= 32;
+ c += (x[4] & M) + (y[4] & M);
+ z[4] = (int)c;
+ c >>>= 32;
+ c += (x[5] & M) + (y[5] & M);
+ z[5] = (int)c;
+ c >>>= 32;
+ c += (x[6] & M) + (y[6] & M);
+ z[6] = (int)c;
+ c >>>= 32;
+ return (int)c;
+ }
+
+ public static int add(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
+ {
+ long c = 0;
+ c += (x[xOff + 0] & M) + (y[yOff + 0] & M);
+ z[zOff + 0] = (int)c;
+ c >>>= 32;
+ c += (x[xOff + 1] & M) + (y[yOff + 1] & M);
+ z[zOff + 1] = (int)c;
+ c >>>= 32;
+ c += (x[xOff + 2] & M) + (y[yOff + 2] & M);
+ z[zOff + 2] = (int)c;
+ c >>>= 32;
+ c += (x[xOff + 3] & M) + (y[yOff + 3] & M);
+ z[zOff + 3] = (int)c;
+ c >>>= 32;
+ c += (x[xOff + 4] & M) + (y[yOff + 4] & M);
+ z[zOff + 4] = (int)c;
+ c >>>= 32;
+ c += (x[xOff + 5] & M) + (y[yOff + 5] & M);
+ z[zOff + 5] = (int)c;
+ c >>>= 32;
+ c += (x[xOff + 6] & M) + (y[yOff + 6] & M);
+ z[zOff + 6] = (int)c;
+ c >>>= 32;
+ return (int)c;
+ }
+
+ public static int addBothTo(int[] x, int[] y, int[] z)
+ {
+ long c = 0;
+ c += (x[0] & M) + (y[0] & M) + (z[0] & M);
+ z[0] = (int)c;
+ c >>>= 32;
+ c += (x[1] & M) + (y[1] & M) + (z[1] & M);
+ z[1] = (int)c;
+ c >>>= 32;
+ c += (x[2] & M) + (y[2] & M) + (z[2] & M);
+ z[2] = (int)c;
+ c >>>= 32;
+ c += (x[3] & M) + (y[3] & M) + (z[3] & M);
+ z[3] = (int)c;
+ c >>>= 32;
+ c += (x[4] & M) + (y[4] & M) + (z[4] & M);
+ z[4] = (int)c;
+ c >>>= 32;
+ c += (x[5] & M) + (y[5] & M) + (z[5] & M);
+ z[5] = (int)c;
+ c >>>= 32;
+ c += (x[6] & M) + (y[6] & M) + (z[6] & M);
+ z[6] = (int)c;
+ c >>>= 32;
+ return (int)c;
+ }
+
+ public static int addBothTo(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
+ {
+ long c = 0;
+ c += (x[xOff + 0] & M) + (y[yOff + 0] & M) + (z[zOff + 0] & M);
+ z[zOff + 0] = (int)c;
+ c >>>= 32;
+ c += (x[xOff + 1] & M) + (y[yOff + 1] & M) + (z[zOff + 1] & M);
+ z[zOff + 1] = (int)c;
+ c >>>= 32;
+ c += (x[xOff + 2] & M) + (y[yOff + 2] & M) + (z[zOff + 2] & M);
+ z[zOff + 2] = (int)c;
+ c >>>= 32;
+ c += (x[xOff + 3] & M) + (y[yOff + 3] & M) + (z[zOff + 3] & M);
+ z[zOff + 3] = (int)c;
+ c >>>= 32;
+ c += (x[xOff + 4] & M) + (y[yOff + 4] & M) + (z[zOff + 4] & M);
+ z[zOff + 4] = (int)c;
+ c >>>= 32;
+ c += (x[xOff + 5] & M) + (y[yOff + 5] & M) + (z[zOff + 5] & M);
+ z[zOff + 5] = (int)c;
+ c >>>= 32;
+ c += (x[xOff + 6] & M) + (y[yOff + 6] & M) + (z[zOff + 6] & M);
+ z[zOff + 6] = (int)c;
+ c >>>= 32;
+ return (int)c;
+ }
+
+ public static int addTo(int[] x, int[] z)
+ {
+ long c = 0;
+ c += (x[0] & M) + (z[0] & M);
+ z[0] = (int)c;
+ c >>>= 32;
+ c += (x[1] & M) + (z[1] & M);
+ z[1] = (int)c;
+ c >>>= 32;
+ c += (x[2] & M) + (z[2] & M);
+ z[2] = (int)c;
+ c >>>= 32;
+ c += (x[3] & M) + (z[3] & M);
+ z[3] = (int)c;
+ c >>>= 32;
+ c += (x[4] & M) + (z[4] & M);
+ z[4] = (int)c;
+ c >>>= 32;
+ c += (x[5] & M) + (z[5] & M);
+ z[5] = (int)c;
+ c >>>= 32;
+ c += (x[6] & M) + (z[6] & M);
+ z[6] = (int)c;
+ c >>>= 32;
+ return (int)c;
+ }
+
+ public static int addTo(int[] x, int xOff, int[] z, int zOff, int cIn)
+ {
+ long c = cIn & M;
+ c += (x[xOff + 0] & M) + (z[zOff + 0] & M);
+ z[zOff + 0] = (int)c;
+ c >>>= 32;
+ c += (x[xOff + 1] & M) + (z[zOff + 1] & M);
+ z[zOff + 1] = (int)c;
+ c >>>= 32;
+ c += (x[xOff + 2] & M) + (z[zOff + 2] & M);
+ z[zOff + 2] = (int)c;
+ c >>>= 32;
+ c += (x[xOff + 3] & M) + (z[zOff + 3] & M);
+ z[zOff + 3] = (int)c;
+ c >>>= 32;
+ c += (x[xOff + 4] & M) + (z[zOff + 4] & M);
+ z[zOff + 4] = (int)c;
+ c >>>= 32;
+ c += (x[xOff + 5] & M) + (z[zOff + 5] & M);
+ z[zOff + 5] = (int)c;
+ c >>>= 32;
+ c += (x[xOff + 6] & M) + (z[zOff + 6] & M);
+ z[zOff + 6] = (int)c;
+ c >>>= 32;
+ return (int)c;
+ }
+
+ public static int addToEachOther(int[] u, int uOff, int[] v, int vOff)
+ {
+ long c = 0;
+ c += (u[uOff + 0] & M) + (v[vOff + 0] & M);
+ u[uOff + 0] = (int)c;
+ v[vOff + 0] = (int)c;
+ c >>>= 32;
+ c += (u[uOff + 1] & M) + (v[vOff + 1] & M);
+ u[uOff + 1] = (int)c;
+ v[vOff + 1] = (int)c;
+ c >>>= 32;
+ c += (u[uOff + 2] & M) + (v[vOff + 2] & M);
+ u[uOff + 2] = (int)c;
+ v[vOff + 2] = (int)c;
+ c >>>= 32;
+ c += (u[uOff + 3] & M) + (v[vOff + 3] & M);
+ u[uOff + 3] = (int)c;
+ v[vOff + 3] = (int)c;
+ c >>>= 32;
+ c += (u[uOff + 4] & M) + (v[vOff + 4] & M);
+ u[uOff + 4] = (int)c;
+ v[vOff + 4] = (int)c;
+ c >>>= 32;
+ c += (u[uOff + 5] & M) + (v[vOff + 5] & M);
+ u[uOff + 5] = (int)c;
+ v[vOff + 5] = (int)c;
+ c >>>= 32;
+ c += (u[uOff + 6] & M) + (v[vOff + 6] & M);
+ u[uOff + 6] = (int)c;
+ v[vOff + 6] = (int)c;
+ c >>>= 32;
+ return (int)c;
+ }
+
+ public static void copy(int[] x, int[] z)
+ {
+ z[0] = x[0];
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ z[4] = x[4];
+ z[5] = x[5];
+ z[6] = x[6];
+ }
+
+ public static int[] create()
+ {
+ return new int[7];
+ }
+
+ public static int[] createExt()
+ {
+ return new int[14];
+ }
+
+ public static boolean diff(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
+ {
+ boolean pos = gte(x, xOff, y, yOff);
+ if (pos)
+ {
+ sub(x, xOff, y, yOff, z, zOff);
+ }
+ else
+ {
+ sub(y, yOff, x, xOff, z, zOff);
+ }
+ return pos;
+ }
+
+ public static boolean eq(int[] x, int[] y)
+ {
+ for (int i = 6; i >= 0; --i)
+ {
+ if (x[i] != y[i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static int[] fromBigInteger(BigInteger x)
+ {
+ if (x.signum() < 0 || x.bitLength() > 224)
+ {
+ throw new IllegalArgumentException();
+ }
+
+ int[] z = create();
+ int i = 0;
+ while (x.signum() != 0)
+ {
+ z[i++] = x.intValue();
+ x = x.shiftRight(32);
+ }
+ return z;
+ }
+
+ public static int getBit(int[] x, int bit)
+ {
+ if (bit == 0)
+ {
+ return x[0] & 1;
+ }
+ int w = bit >> 5;
+ if (w < 0 || w >= 7)
+ {
+ return 0;
+ }
+ int b = bit & 31;
+ return (x[w] >>> b) & 1;
+ }
+
+ public static boolean gte(int[] x, int[] y)
+ {
+ for (int i = 6; i >= 0; --i)
+ {
+ int x_i = x[i] ^ Integer.MIN_VALUE;
+ int y_i = y[i] ^ Integer.MIN_VALUE;
+ if (x_i < y_i)
+ return false;
+ if (x_i > y_i)
+ return true;
+ }
+ return true;
+ }
+
+ public static boolean gte(int[] x, int xOff, int[] y, int yOff)
+ {
+ for (int i = 6; i >= 0; --i)
+ {
+ int x_i = x[xOff + i] ^ Integer.MIN_VALUE;
+ int y_i = y[yOff + i] ^ Integer.MIN_VALUE;
+ if (x_i < y_i)
+ return false;
+ if (x_i > y_i)
+ return true;
+ }
+ return true;
+ }
+
+ public static boolean isOne(int[] x)
+ {
+ if (x[0] != 1)
+ {
+ return false;
+ }
+ for (int i = 1; i < 7; ++i)
+ {
+ if (x[i] != 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static boolean isZero(int[] x)
+ {
+ for (int i = 0; i < 7; ++i)
+ {
+ if (x[i] != 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static void mul(int[] x, int[] y, int[] zz)
+ {
+ long y_0 = y[0] & M;
+ long y_1 = y[1] & M;
+ long y_2 = y[2] & M;
+ long y_3 = y[3] & M;
+ long y_4 = y[4] & M;
+ long y_5 = y[5] & M;
+ long y_6 = y[6] & M;
+
+ {
+ long c = 0, x_0 = x[0] & M;
+ c += x_0 * y_0;
+ zz[0] = (int)c;
+ c >>>= 32;
+ c += x_0 * y_1;
+ zz[1] = (int)c;
+ c >>>= 32;
+ c += x_0 * y_2;
+ zz[2] = (int)c;
+ c >>>= 32;
+ c += x_0 * y_3;
+ zz[3] = (int)c;
+ c >>>= 32;
+ c += x_0 * y_4;
+ zz[4] = (int)c;
+ c >>>= 32;
+ c += x_0 * y_5;
+ zz[5] = (int)c;
+ c >>>= 32;
+ c += x_0 * y_6;
+ zz[6] = (int)c;
+ c >>>= 32;
+ zz[7] = (int)c;
+ }
+
+ for (int i = 1; i < 7; ++i)
+ {
+ long c = 0, x_i = x[i] & M;
+ c += x_i * y_0 + (zz[i + 0] & M);
+ zz[i + 0] = (int)c;
+ c >>>= 32;
+ c += x_i * y_1 + (zz[i + 1] & M);
+ zz[i + 1] = (int)c;
+ c >>>= 32;
+ c += x_i * y_2 + (zz[i + 2] & M);
+ zz[i + 2] = (int)c;
+ c >>>= 32;
+ c += x_i * y_3 + (zz[i + 3] & M);
+ zz[i + 3] = (int)c;
+ c >>>= 32;
+ c += x_i * y_4 + (zz[i + 4] & M);
+ zz[i + 4] = (int)c;
+ c >>>= 32;
+ c += x_i * y_5 + (zz[i + 5] & M);
+ zz[i + 5] = (int)c;
+ c >>>= 32;
+ c += x_i * y_6 + (zz[i + 6] & M);
+ zz[i + 6] = (int)c;
+ c >>>= 32;
+ zz[i + 7] = (int)c;
+ }
+ }
+
+ public static void mul(int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff)
+ {
+ long y_0 = y[yOff + 0] & M;
+ long y_1 = y[yOff + 1] & M;
+ long y_2 = y[yOff + 2] & M;
+ long y_3 = y[yOff + 3] & M;
+ long y_4 = y[yOff + 4] & M;
+ long y_5 = y[yOff + 5] & M;
+ long y_6 = y[yOff + 6] & M;
+
+ {
+ long c = 0, x_0 = x[xOff + 0] & M;
+ c += x_0 * y_0;
+ zz[zzOff + 0] = (int)c;
+ c >>>= 32;
+ c += x_0 * y_1;
+ zz[zzOff + 1] = (int)c;
+ c >>>= 32;
+ c += x_0 * y_2;
+ zz[zzOff + 2] = (int)c;
+ c >>>= 32;
+ c += x_0 * y_3;
+ zz[zzOff + 3] = (int)c;
+ c >>>= 32;
+ c += x_0 * y_4;
+ zz[zzOff + 4] = (int)c;
+ c >>>= 32;
+ c += x_0 * y_5;
+ zz[zzOff + 5] = (int)c;
+ c >>>= 32;
+ c += x_0 * y_6;
+ zz[zzOff + 6] = (int)c;
+ c >>>= 32;
+ zz[zzOff + 7] = (int)c;
+ }
+
+ for (int i = 1; i < 7; ++i)
+ {
+ ++zzOff;
+ long c = 0, x_i = x[xOff + i] & M;
+ c += x_i * y_0 + (zz[zzOff + 0] & M);
+ zz[zzOff + 0] = (int)c;
+ c >>>= 32;
+ c += x_i * y_1 + (zz[zzOff + 1] & M);
+ zz[zzOff + 1] = (int)c;
+ c >>>= 32;
+ c += x_i * y_2 + (zz[zzOff + 2] & M);
+ zz[zzOff + 2] = (int)c;
+ c >>>= 32;
+ c += x_i * y_3 + (zz[zzOff + 3] & M);
+ zz[zzOff + 3] = (int)c;
+ c >>>= 32;
+ c += x_i * y_4 + (zz[zzOff + 4] & M);
+ zz[zzOff + 4] = (int)c;
+ c >>>= 32;
+ c += x_i * y_5 + (zz[zzOff + 5] & M);
+ zz[zzOff + 5] = (int)c;
+ c >>>= 32;
+ c += x_i * y_6 + (zz[zzOff + 6] & M);
+ zz[zzOff + 6] = (int)c;
+ c >>>= 32;
+ zz[zzOff + 7] = (int)c;
+ }
+ }
+
+ public static int mulAddTo(int[] x, int[] y, int[] zz)
+ {
+ long y_0 = y[0] & M;
+ long y_1 = y[1] & M;
+ long y_2 = y[2] & M;
+ long y_3 = y[3] & M;
+ long y_4 = y[4] & M;
+ long y_5 = y[5] & M;
+ long y_6 = y[6] & M;
+
+ long zc = 0;
+ for (int i = 0; i < 7; ++i)
+ {
+ long c = 0, x_i = x[i] & M;
+ c += x_i * y_0 + (zz[i + 0] & M);
+ zz[i + 0] = (int)c;
+ c >>>= 32;
+ c += x_i * y_1 + (zz[i + 1] & M);
+ zz[i + 1] = (int)c;
+ c >>>= 32;
+ c += x_i * y_2 + (zz[i + 2] & M);
+ zz[i + 2] = (int)c;
+ c >>>= 32;
+ c += x_i * y_3 + (zz[i + 3] & M);
+ zz[i + 3] = (int)c;
+ c >>>= 32;
+ c += x_i * y_4 + (zz[i + 4] & M);
+ zz[i + 4] = (int)c;
+ c >>>= 32;
+ c += x_i * y_5 + (zz[i + 5] & M);
+ zz[i + 5] = (int)c;
+ c >>>= 32;
+ c += x_i * y_6 + (zz[i + 6] & M);
+ zz[i + 6] = (int)c;
+ c >>>= 32;
+ c += zc + (zz[i + 7] & M);
+ zz[i + 7] = (int)c;
+ zc = c >>> 32;
+ }
+ return (int)zc;
+ }
+
+ public static int mulAddTo(int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff)
+ {
+ long y_0 = y[yOff + 0] & M;
+ long y_1 = y[yOff + 1] & M;
+ long y_2 = y[yOff + 2] & M;
+ long y_3 = y[yOff + 3] & M;
+ long y_4 = y[yOff + 4] & M;
+ long y_5 = y[yOff + 5] & M;
+ long y_6 = y[yOff + 6] & M;
+
+ long zc = 0;
+ for (int i = 0; i < 7; ++i)
+ {
+ long c = 0, x_i = x[xOff + i] & M;
+ c += x_i * y_0 + (zz[zzOff + 0] & M);
+ zz[zzOff + 0] = (int)c;
+ c >>>= 32;
+ c += x_i * y_1 + (zz[zzOff + 1] & M);
+ zz[zzOff + 1] = (int)c;
+ c >>>= 32;
+ c += x_i * y_2 + (zz[zzOff + 2] & M);
+ zz[zzOff + 2] = (int)c;
+ c >>>= 32;
+ c += x_i * y_3 + (zz[zzOff + 3] & M);
+ zz[zzOff + 3] = (int)c;
+ c >>>= 32;
+ c += x_i * y_4 + (zz[zzOff + 4] & M);
+ zz[zzOff + 4] = (int)c;
+ c >>>= 32;
+ c += x_i * y_5 + (zz[zzOff + 5] & M);
+ zz[zzOff + 5] = (int)c;
+ c >>>= 32;
+ c += x_i * y_6 + (zz[zzOff + 6] & M);
+ zz[zzOff + 6] = (int)c;
+ c >>>= 32;
+ c += zc + (zz[zzOff + 7] & M);
+ zz[zzOff + 7] = (int)c;
+ zc = c >>> 32;
+ ++zzOff;
+ }
+ return (int)zc;
+ }
+
+ public static long mul33Add(int w, int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
+ {
+ // assert w >>> 31 == 0;
+
+ long c = 0, wVal = w & M;
+ long x0 = x[xOff + 0] & M;
+ c += wVal * x0 + (y[yOff + 0] & M);
+ z[zOff + 0] = (int)c;
+ c >>>= 32;
+ long x1 = x[xOff + 1] & M;
+ c += wVal * x1 + x0 + (y[yOff + 1] & M);
+ z[zOff + 1] = (int)c;
+ c >>>= 32;
+ long x2 = x[xOff + 2] & M;
+ c += wVal * x2 + x1 + (y[yOff + 2] & M);
+ z[zOff + 2] = (int)c;
+ c >>>= 32;
+ long x3 = x[xOff + 3] & M;
+ c += wVal * x3 + x2 + (y[yOff + 3] & M);
+ z[zOff + 3] = (int)c;
+ c >>>= 32;
+ long x4 = x[xOff + 4] & M;
+ c += wVal * x4 + x3 + (y[yOff + 4] & M);
+ z[zOff + 4] = (int)c;
+ c >>>= 32;
+ long x5 = x[xOff + 5] & M;
+ c += wVal * x5 + x4 + (y[yOff + 5] & M);
+ z[zOff + 5] = (int)c;
+ c >>>= 32;
+ long x6 = x[xOff + 6] & M;
+ c += wVal * x6 + x5 + (y[yOff + 6] & M);
+ z[zOff + 6] = (int)c;
+ c >>>= 32;
+ c += x6;
+ return c;
+ }
+
+ public static int mulByWord(int x, int[] z)
+ {
+ long c = 0, xVal = x & M;
+ c += xVal * (z[0] & M);
+ z[0] = (int)c;
+ c >>>= 32;
+ c += xVal * (z[1] & M);
+ z[1] = (int)c;
+ c >>>= 32;
+ c += xVal * (z[2] & M);
+ z[2] = (int)c;
+ c >>>= 32;
+ c += xVal * (z[3] & M);
+ z[3] = (int)c;
+ c >>>= 32;
+ c += xVal * (z[4] & M);
+ z[4] = (int)c;
+ c >>>= 32;
+ c += xVal * (z[5] & M);
+ z[5] = (int)c;
+ c >>>= 32;
+ c += xVal * (z[6] & M);
+ z[6] = (int)c;
+ c >>>= 32;
+ return (int)c;
+ }
+
+ public static int mulByWordAddTo(int x, int[] y, int[] z)
+ {
+ long c = 0, xVal = x & M;
+ c += xVal * (z[0] & M) + (y[0] & M);
+ z[0] = (int)c;
+ c >>>= 32;
+ c += xVal * (z[1] & M) + (y[1] & M);
+ z[1] = (int)c;
+ c >>>= 32;
+ c += xVal * (z[2] & M) + (y[2] & M);
+ z[2] = (int)c;
+ c >>>= 32;
+ c += xVal * (z[3] & M) + (y[3] & M);
+ z[3] = (int)c;
+ c >>>= 32;
+ c += xVal * (z[4] & M) + (y[4] & M);
+ z[4] = (int)c;
+ c >>>= 32;
+ c += xVal * (z[5] & M) + (y[5] & M);
+ z[5] = (int)c;
+ c >>>= 32;
+ c += xVal * (z[6] & M) + (y[6] & M);
+ z[6] = (int)c;
+ c >>>= 32;
+ return (int)c;
+ }
+
+ public static int mulWordAddTo(int x, int[] y, int yOff, int[] z, int zOff)
+ {
+ long c = 0, xVal = x & M;
+ c += xVal * (y[yOff + 0] & M) + (z[zOff + 0] & M);
+ z[zOff + 0] = (int)c;
+ c >>>= 32;
+ c += xVal * (y[yOff + 1] & M) + (z[zOff + 1] & M);
+ z[zOff + 1] = (int)c;
+ c >>>= 32;
+ c += xVal * (y[yOff + 2] & M) + (z[zOff + 2] & M);
+ z[zOff + 2] = (int)c;
+ c >>>= 32;
+ c += xVal * (y[yOff + 3] & M) + (z[zOff + 3] & M);
+ z[zOff + 3] = (int)c;
+ c >>>= 32;
+ c += xVal * (y[yOff + 4] & M) + (z[zOff + 4] & M);
+ z[zOff + 4] = (int)c;
+ c >>>= 32;
+ c += xVal * (y[yOff + 5] & M) + (z[zOff + 5] & M);
+ z[zOff + 5] = (int)c;
+ c >>>= 32;
+ c += xVal * (y[yOff + 6] & M) + (z[zOff + 6] & M);
+ z[zOff + 6] = (int)c;
+ c >>>= 32;
+ return (int)c;
+ }
+
+ public static int mul33DWordAdd(int x, long y, int[] z, int zOff)
+ {
+ // assert x >>> 31 == 0;
+ // assert zOff <= 3;
+
+ long c = 0, xVal = x & M;
+ long y00 = y & M;
+ c += xVal * y00 + (z[zOff + 0] & M);
+ z[zOff + 0] = (int)c;
+ c >>>= 32;
+ long y01 = y >>> 32;
+ c += xVal * y01 + y00 + (z[zOff + 1] & M);
+ z[zOff + 1] = (int)c;
+ c >>>= 32;
+ c += y01 + (z[zOff + 2] & M);
+ z[zOff + 2] = (int)c;
+ c >>>= 32;
+ c += (z[zOff + 3] & M);
+ z[zOff + 3] = (int)c;
+ c >>>= 32;
+ return c == 0 ? 0 : Nat.incAt(7, z, zOff, 4);
+ }
+
+ public static int mul33WordAdd(int x, int y, int[] z, int zOff)
+ {
+ // assert x >>> 31 == 0;
+ // assert zOff <= 4;
+
+ long c = 0, xVal = x & M, yVal = y & M;
+ c += yVal * xVal + (z[zOff + 0] & M);
+ z[zOff + 0] = (int)c;
+ c >>>= 32;
+ c += yVal + (z[zOff + 1] & M);
+ z[zOff + 1] = (int)c;
+ c >>>= 32;
+ c += (z[zOff + 2] & M);
+ z[zOff + 2] = (int)c;
+ c >>>= 32;
+ return c == 0 ? 0 : Nat.incAt(7, z, zOff, 3);
+ }
+
+ public static int mulWordDwordAdd(int x, long y, int[] z, int zOff)
+ {
+ // assert zOff <= 4;
+ long c = 0, xVal = x & M;
+ c += xVal * (y & M) + (z[zOff + 0] & M);
+ z[zOff + 0] = (int)c;
+ c >>>= 32;
+ c += xVal * (y >>> 32) + (z[zOff + 1] & M);
+ z[zOff + 1] = (int)c;
+ c >>>= 32;
+ c += (z[zOff + 2] & M);
+ z[zOff + 2] = (int)c;
+ c >>>= 32;
+ return c == 0 ? 0 : Nat.incAt(7, z, zOff, 3);
+ }
+
+ public static int mulWord(int x, int[] y, int[] z, int zOff)
+ {
+ long c = 0, xVal = x & M;
+ int i = 0;
+ do
+ {
+ c += xVal * (y[i] & M);
+ z[zOff + i] = (int)c;
+ c >>>= 32;
+ }
+ while (++i < 7);
+ return (int)c;
+ }
+
+ public static void square(int[] x, int[] zz)
+ {
+ long x_0 = x[0] & M;
+ long zz_1;
+
+ int c = 0, w;
+ {
+ int i = 6, j = 14;
+ do
+ {
+ long xVal = (x[i--] & M);
+ long p = xVal * xVal;
+ zz[--j] = (c << 31) | (int)(p >>> 33);
+ zz[--j] = (int)(p >>> 1);
+ c = (int)p;
+ }
+ while (i > 0);
+
+ {
+ long p = x_0 * x_0;
+ zz_1 = ((c << 31) & M) | (p >>> 33);
+ zz[0] = (int)p;
+ c = (int)(p >>> 32) & 1;
+ }
+ }
+
+ long x_1 = x[1] & M;
+ long zz_2 = zz[2] & M;
+
+ {
+ zz_1 += x_1 * x_0;
+ w = (int)zz_1;
+ zz[1] = (w << 1) | c;
+ c = w >>> 31;
+ zz_2 += zz_1 >>> 32;
+ }
+
+ long x_2 = x[2] & M;
+ long zz_3 = zz[3] & M;
+ long zz_4 = zz[4] & M;
+ {
+ zz_2 += x_2 * x_0;
+ w = (int)zz_2;
+ zz[2] = (w << 1) | c;
+ c = w >>> 31;
+ zz_3 += (zz_2 >>> 32) + x_2 * x_1;
+ zz_4 += zz_3 >>> 32;
+ zz_3 &= M;
+ }
+
+ long x_3 = x[3] & M;
+ long zz_5 = zz[5] & M;
+ long zz_6 = zz[6] & M;
+ {
+ zz_3 += x_3 * x_0;
+ w = (int)zz_3;
+ zz[3] = (w << 1) | c;
+ c = w >>> 31;
+ zz_4 += (zz_3 >>> 32) + x_3 * x_1;
+ zz_5 += (zz_4 >>> 32) + x_3 * x_2;
+ zz_4 &= M;
+ zz_6 += zz_5 >>> 32;
+ zz_5 &= M;
+ }
+
+ long x_4 = x[4] & M;
+ long zz_7 = zz[7] & M;
+ long zz_8 = zz[8] & M;
+ {
+ zz_4 += x_4 * x_0;
+ w = (int)zz_4;
+ zz[4] = (w << 1) | c;
+ c = w >>> 31;
+ zz_5 += (zz_4 >>> 32) + x_4 * x_1;
+ zz_6 += (zz_5 >>> 32) + x_4 * x_2;
+ zz_5 &= M;
+ zz_7 += (zz_6 >>> 32) + x_4 * x_3;
+ zz_6 &= M;
+ zz_8 += zz_7 >>> 32;
+ zz_7 &= M;
+ }
+
+ long x_5 = x[5] & M;
+ long zz_9 = zz[9] & M;
+ long zz_10 = zz[10] & M;
+ {
+ zz_5 += x_5 * x_0;
+ w = (int)zz_5;
+ zz[5] = (w << 1) | c;
+ c = w >>> 31;
+ zz_6 += (zz_5 >>> 32) + x_5 * x_1;
+ zz_7 += (zz_6 >>> 32) + x_5 * x_2;
+ zz_6 &= M;
+ zz_8 += (zz_7 >>> 32) + x_5 * x_3;
+ zz_7 &= M;
+ zz_9 += (zz_8 >>> 32) + x_5 * x_4;
+ zz_8 &= M;
+ zz_10 += zz_9 >>> 32;
+ zz_9 &= M;
+ }
+
+ long x_6 = x[6] & M;
+ long zz_11 = zz[11] & M;
+ long zz_12 = zz[12] & M;
+ {
+ zz_6 += x_6 * x_0;
+ w = (int)zz_6;
+ zz[6] = (w << 1) | c;
+ c = w >>> 31;
+ zz_7 += (zz_6 >>> 32) + x_6 * x_1;
+ zz_8 += (zz_7 >>> 32) + x_6 * x_2;
+ zz_9 += (zz_8 >>> 32) + x_6 * x_3;
+ zz_10 += (zz_9 >>> 32) + x_6 * x_4;
+ zz_11 += (zz_10 >>> 32) + x_6 * x_5;
+ zz_12 += zz_11 >>> 32;
+ }
+
+ w = (int)zz_7;
+ zz[7] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_8;
+ zz[8] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_9;
+ zz[9] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_10;
+ zz[10] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_11;
+ zz[11] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_12;
+ zz[12] = (w << 1) | c;
+ c = w >>> 31;
+ w = zz[13] + (int)(zz_12 >> 32);
+ zz[13] = (w << 1) | c;
+ }
+
+ public static void square(int[] x, int xOff, int[] zz, int zzOff)
+ {
+ long x_0 = x[xOff + 0] & M;
+ long zz_1;
+
+ int c = 0, w;
+ {
+ int i = 6, j = 14;
+ do
+ {
+ long xVal = (x[xOff + i--] & M);
+ long p = xVal * xVal;
+ zz[zzOff + --j] = (c << 31) | (int)(p >>> 33);
+ zz[zzOff + --j] = (int)(p >>> 1);
+ c = (int)p;
+ }
+ while (i > 0);
+
+ {
+ long p = x_0 * x_0;
+ zz_1 = ((c << 31) & M) | (p >>> 33);
+ zz[zzOff + 0] = (int)p;
+ c = (int)(p >>> 32) & 1;
+ }
+ }
+
+ long x_1 = x[xOff + 1] & M;
+ long zz_2 = zz[zzOff + 2] & M;
+
+ {
+ zz_1 += x_1 * x_0;
+ w = (int)zz_1;
+ zz[zzOff + 1] = (w << 1) | c;
+ c = w >>> 31;
+ zz_2 += zz_1 >>> 32;
+ }
+
+ long x_2 = x[xOff + 2] & M;
+ long zz_3 = zz[zzOff + 3] & M;
+ long zz_4 = zz[zzOff + 4] & M;
+ {
+ zz_2 += x_2 * x_0;
+ w = (int)zz_2;
+ zz[zzOff + 2] = (w << 1) | c;
+ c = w >>> 31;
+ zz_3 += (zz_2 >>> 32) + x_2 * x_1;
+ zz_4 += zz_3 >>> 32;
+ zz_3 &= M;
+ }
+
+ long x_3 = x[xOff + 3] & M;
+ long zz_5 = zz[zzOff + 5] & M;
+ long zz_6 = zz[zzOff + 6] & M;
+ {
+ zz_3 += x_3 * x_0;
+ w = (int)zz_3;
+ zz[zzOff + 3] = (w << 1) | c;
+ c = w >>> 31;
+ zz_4 += (zz_3 >>> 32) + x_3 * x_1;
+ zz_5 += (zz_4 >>> 32) + x_3 * x_2;
+ zz_4 &= M;
+ zz_6 += zz_5 >>> 32;
+ zz_5 &= M;
+ }
+
+ long x_4 = x[xOff + 4] & M;
+ long zz_7 = zz[zzOff + 7] & M;
+ long zz_8 = zz[zzOff + 8] & M;
+ {
+ zz_4 += x_4 * x_0;
+ w = (int)zz_4;
+ zz[zzOff + 4] = (w << 1) | c;
+ c = w >>> 31;
+ zz_5 += (zz_4 >>> 32) + x_4 * x_1;
+ zz_6 += (zz_5 >>> 32) + x_4 * x_2;
+ zz_5 &= M;
+ zz_7 += (zz_6 >>> 32) + x_4 * x_3;
+ zz_6 &= M;
+ zz_8 += zz_7 >>> 32;
+ zz_7 &= M;
+ }
+
+ long x_5 = x[xOff + 5] & M;
+ long zz_9 = zz[zzOff + 9] & M;
+ long zz_10 = zz[zzOff + 10] & M;
+ {
+ zz_5 += x_5 * x_0;
+ w = (int)zz_5;
+ zz[zzOff + 5] = (w << 1) | c;
+ c = w >>> 31;
+ zz_6 += (zz_5 >>> 32) + x_5 * x_1;
+ zz_7 += (zz_6 >>> 32) + x_5 * x_2;
+ zz_6 &= M;
+ zz_8 += (zz_7 >>> 32) + x_5 * x_3;
+ zz_7 &= M;
+ zz_9 += (zz_8 >>> 32) + x_5 * x_4;
+ zz_8 &= M;
+ zz_10 += zz_9 >>> 32;
+ zz_9 &= M;
+ }
+
+ long x_6 = x[xOff + 6] & M;
+ long zz_11 = zz[zzOff + 11] & M;
+ long zz_12 = zz[zzOff + 12] & M;
+ {
+ zz_6 += x_6 * x_0;
+ w = (int)zz_6;
+ zz[zzOff + 6] = (w << 1) | c;
+ c = w >>> 31;
+ zz_7 += (zz_6 >>> 32) + x_6 * x_1;
+ zz_8 += (zz_7 >>> 32) + x_6 * x_2;
+ zz_9 += (zz_8 >>> 32) + x_6 * x_3;
+ zz_10 += (zz_9 >>> 32) + x_6 * x_4;
+ zz_11 += (zz_10 >>> 32) + x_6 * x_5;
+ zz_12 += zz_11 >>> 32;
+ }
+
+ w = (int)zz_7;
+ zz[zzOff + 7] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_8;
+ zz[zzOff + 8] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_9;
+ zz[zzOff + 9] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_10;
+ zz[zzOff + 10] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_11;
+ zz[zzOff + 11] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_12;
+ zz[zzOff + 12] = (w << 1) | c;
+ c = w >>> 31;
+ w = zz[zzOff + 13] + (int)(zz_12 >> 32);
+ zz[zzOff + 13] = (w << 1) | c;
+ }
+
+ public static int sub(int[] x, int[] y, int[] z)
+ {
+ long c = 0;
+ c += (x[0] & M) - (y[0] & M);
+ z[0] = (int)c;
+ c >>= 32;
+ c += (x[1] & M) - (y[1] & M);
+ z[1] = (int)c;
+ c >>= 32;
+ c += (x[2] & M) - (y[2] & M);
+ z[2] = (int)c;
+ c >>= 32;
+ c += (x[3] & M) - (y[3] & M);
+ z[3] = (int)c;
+ c >>= 32;
+ c += (x[4] & M) - (y[4] & M);
+ z[4] = (int)c;
+ c >>= 32;
+ c += (x[5] & M) - (y[5] & M);
+ z[5] = (int)c;
+ c >>= 32;
+ c += (x[6] & M) - (y[6] & M);
+ z[6] = (int)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int sub(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
+ {
+ long c = 0;
+ c += (x[xOff + 0] & M) - (y[yOff + 0] & M);
+ z[zOff + 0] = (int)c;
+ c >>= 32;
+ c += (x[xOff + 1] & M) - (y[yOff + 1] & M);
+ z[zOff + 1] = (int)c;
+ c >>= 32;
+ c += (x[xOff + 2] & M) - (y[yOff + 2] & M);
+ z[zOff + 2] = (int)c;
+ c >>= 32;
+ c += (x[xOff + 3] & M) - (y[yOff + 3] & M);
+ z[zOff + 3] = (int)c;
+ c >>= 32;
+ c += (x[xOff + 4] & M) - (y[yOff + 4] & M);
+ z[zOff + 4] = (int)c;
+ c >>= 32;
+ c += (x[xOff + 5] & M) - (y[yOff + 5] & M);
+ z[zOff + 5] = (int)c;
+ c >>= 32;
+ c += (x[xOff + 6] & M) - (y[yOff + 6] & M);
+ z[zOff + 6] = (int)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int subBothFrom(int[] x, int[] y, int[] z)
+ {
+ long c = 0;
+ c += (z[0] & M) - (x[0] & M) - (y[0] & M);
+ z[0] = (int)c;
+ c >>= 32;
+ c += (z[1] & M) - (x[1] & M) - (y[1] & M);
+ z[1] = (int)c;
+ c >>= 32;
+ c += (z[2] & M) - (x[2] & M) - (y[2] & M);
+ z[2] = (int)c;
+ c >>= 32;
+ c += (z[3] & M) - (x[3] & M) - (y[3] & M);
+ z[3] = (int)c;
+ c >>= 32;
+ c += (z[4] & M) - (x[4] & M) - (y[4] & M);
+ z[4] = (int)c;
+ c >>= 32;
+ c += (z[5] & M) - (x[5] & M) - (y[5] & M);
+ z[5] = (int)c;
+ c >>= 32;
+ c += (z[6] & M) - (x[6] & M) - (y[6] & M);
+ z[6] = (int)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int subFrom(int[] x, int[] z)
+ {
+ long c = 0;
+ c += (z[0] & M) - (x[0] & M);
+ z[0] = (int)c;
+ c >>= 32;
+ c += (z[1] & M) - (x[1] & M);
+ z[1] = (int)c;
+ c >>= 32;
+ c += (z[2] & M) - (x[2] & M);
+ z[2] = (int)c;
+ c >>= 32;
+ c += (z[3] & M) - (x[3] & M);
+ z[3] = (int)c;
+ c >>= 32;
+ c += (z[4] & M) - (x[4] & M);
+ z[4] = (int)c;
+ c >>= 32;
+ c += (z[5] & M) - (x[5] & M);
+ z[5] = (int)c;
+ c >>= 32;
+ c += (z[6] & M) - (x[6] & M);
+ z[6] = (int)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int subFrom(int[] x, int xOff, int[] z, int zOff)
+ {
+ long c = 0;
+ c += (z[zOff + 0] & M) - (x[xOff + 0] & M);
+ z[zOff + 0] = (int)c;
+ c >>= 32;
+ c += (z[zOff + 1] & M) - (x[xOff + 1] & M);
+ z[zOff + 1] = (int)c;
+ c >>= 32;
+ c += (z[zOff + 2] & M) - (x[xOff + 2] & M);
+ z[zOff + 2] = (int)c;
+ c >>= 32;
+ c += (z[zOff + 3] & M) - (x[xOff + 3] & M);
+ z[zOff + 3] = (int)c;
+ c >>= 32;
+ c += (z[zOff + 4] & M) - (x[xOff + 4] & M);
+ z[zOff + 4] = (int)c;
+ c >>= 32;
+ c += (z[zOff + 5] & M) - (x[xOff + 5] & M);
+ z[zOff + 5] = (int)c;
+ c >>= 32;
+ c += (z[zOff + 6] & M) - (x[xOff + 6] & M);
+ z[zOff + 6] = (int)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static BigInteger toBigInteger(int[] x)
+ {
+ byte[] bs = new byte[28];
+ for (int i = 0; i < 7; ++i)
+ {
+ int x_i = x[i];
+ if (x_i != 0)
+ {
+ Pack.intToBigEndian(x_i, bs, (6 - i) << 2);
+ }
+ }
+ return new BigInteger(1, bs);
+ }
+
+ public static void zero(int[] z)
+ {
+ z[0] = 0;
+ z[1] = 0;
+ z[2] = 0;
+ z[3] = 0;
+ z[4] = 0;
+ z[5] = 0;
+ z[6] = 0;
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat256.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat256.java
index 6a228fdb..6947317b 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat256.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat256.java
@@ -3,6 +3,7 @@ package org.bouncycastle.math.ec.custom.sec;
import java.math.BigInteger;
import org.bouncycastle.crypto.util.Pack;
+import org.bouncycastle.math.ec.Nat;
public abstract class Nat256
{
@@ -128,29 +129,33 @@ public abstract class Nat256
return (int)c;
}
- // TODO Re-write to allow full range for x?
- public static int addDWord(long x, int[] z, int zOff)
+ public static int addTo(int[] x, int[] z)
{
- // assert zOff <= 6;
- long c = x;
- c += (z[zOff + 0] & M);
- z[zOff + 0] = (int)c;
+ long c = 0;
+ c += (x[0] & M) + (z[0] & M);
+ z[0] = (int)c;
c >>>= 32;
- c += (z[zOff + 1] & M);
- z[zOff + 1] = (int)c;
+ c += (x[1] & M) + (z[1] & M);
+ z[1] = (int)c;
+ c >>>= 32;
+ c += (x[2] & M) + (z[2] & M);
+ z[2] = (int)c;
+ c >>>= 32;
+ c += (x[3] & M) + (z[3] & M);
+ z[3] = (int)c;
+ c >>>= 32;
+ c += (x[4] & M) + (z[4] & M);
+ z[4] = (int)c;
+ c >>>= 32;
+ c += (x[5] & M) + (z[5] & M);
+ z[5] = (int)c;
+ c >>>= 32;
+ c += (x[6] & M) + (z[6] & M);
+ z[6] = (int)c;
+ c >>>= 32;
+ c += (x[7] & M) + (z[7] & M);
+ z[7] = (int)c;
c >>>= 32;
- return c == 0 ? 0 : inc(z, zOff + 2);
- }
-
- public static int addExt(int[] xx, int[] yy, int[] zz)
- {
- long c = 0;
- for (int i = 0; i < 16; ++i)
- {
- c += (xx[i] & M) + (yy[i] & M);
- zz[i] = (int)c;
- c >>>= 32;
- }
return (int)c;
}
@@ -222,24 +227,6 @@ public abstract class Nat256
return (int)c;
}
- public static int addWord(int x, int[] z, int zOff)
- {
- // assert zzOff <= 7;
- long c = (x & M) + (z[zOff + 0] & M);
- z[zOff + 0] = (int)c;
- c >>>= 32;
- return c == 0 ? 0 : inc(z, zOff + 1);
- }
-
- public static int addWordExt(int x, int[] zz, int zzOff)
- {
- // assert zzOff <= 15;
- long c = (x & M) + (zz[zzOff + 0] & M);
- zz[zzOff + 0] = (int)c;
- c >>>= 32;
- return c == 0 ? 0 : incExt(zz, zzOff + 1);
- }
-
public static void copy(int[] x, int[] z)
{
z[0] = x[0];
@@ -262,32 +249,6 @@ public abstract class Nat256
return new int[16];
}
- public static int dec(int[] z, int zOff)
- {
- // assert zOff <= 8;
- for (int i = zOff; i < 8; ++i)
- {
- if (--z[i] != -1)
- {
- return 0;
- }
- }
- return -1;
- }
-
- public static int decExt(int[] zz, int zzOff)
- {
- // assert zOff <= 16;
- for (int i = zzOff; i < 16; ++i)
- {
- if (--zz[i] != -1)
- {
- return 0;
- }
- }
- return -1;
- }
-
public static boolean diff(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
{
boolean pos = gte(x, xOff, y, yOff);
@@ -302,6 +263,18 @@ public abstract class Nat256
return pos;
}
+ public static boolean eq(int[] x, int[] y)
+ {
+ for (int i = 7; i >= 0; --i)
+ {
+ if (x[i] != y[i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
public static int[] fromBigInteger(BigInteger x)
{
if (x.signum() < 0 || x.bitLength() > 256)
@@ -362,46 +335,6 @@ public abstract class Nat256
return true;
}
- public static boolean gteExt(int[] xx, int[] yy)
- {
- for (int i = 15; i >= 0; --i)
- {
- int xx_i = xx[i] ^ Integer.MIN_VALUE;
- int yy_i = yy[i] ^ Integer.MIN_VALUE;
- if (xx_i < yy_i)
- return false;
- if (xx_i > yy_i)
- return true;
- }
- return true;
- }
-
- public static int inc(int[] z, int zOff)
- {
- // assert zOff <= 8;
- for (int i = zOff; i < 8; ++i)
- {
- if (++z[i] != 0)
- {
- return 0;
- }
- }
- return 1;
- }
-
- public static int incExt(int[] zz, int zzOff)
- {
- // assert zzOff <= 16;
- for (int i = zzOff; i < 16; ++i)
- {
- if (++zz[i] != 0)
- {
- return 0;
- }
- }
- return 1;
- }
-
public static boolean isOne(int[] x)
{
if (x[0] != 1)
@@ -430,18 +363,6 @@ public abstract class Nat256
return true;
}
- public static boolean isZeroExt(int[] xx)
- {
- for (int i = 0; i < 16; ++i)
- {
- if (xx[i] != 0)
- {
- return false;
- }
- }
- return true;
- }
-
public static void mul(int[] x, int[] y, int[] zz)
{
long y_0 = y[0] & M;
@@ -585,7 +506,53 @@ public abstract class Nat256
}
}
- public static int mulAdd(int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff)
+ public static int mulAddTo(int[] x, int[] y, int[] zz)
+ {
+ long y_0 = y[0] & M;
+ long y_1 = y[1] & M;
+ long y_2 = y[2] & M;
+ long y_3 = y[3] & M;
+ long y_4 = y[4] & M;
+ long y_5 = y[5] & M;
+ long y_6 = y[6] & M;
+ long y_7 = y[7] & M;
+
+ long zc = 0;
+ for (int i = 0; i < 8; ++i)
+ {
+ long c = 0, x_i = x[i] & M;
+ c += x_i * y_0 + (zz[i + 0] & M);
+ zz[i + 0] = (int)c;
+ c >>>= 32;
+ c += x_i * y_1 + (zz[i + 1] & M);
+ zz[i + 1] = (int)c;
+ c >>>= 32;
+ c += x_i * y_2 + (zz[i + 2] & M);
+ zz[i + 2] = (int)c;
+ c >>>= 32;
+ c += x_i * y_3 + (zz[i + 3] & M);
+ zz[i + 3] = (int)c;
+ c >>>= 32;
+ c += x_i * y_4 + (zz[i + 4] & M);
+ zz[i + 4] = (int)c;
+ c >>>= 32;
+ c += x_i * y_5 + (zz[i + 5] & M);
+ zz[i + 5] = (int)c;
+ c >>>= 32;
+ c += x_i * y_6 + (zz[i + 6] & M);
+ zz[i + 6] = (int)c;
+ c >>>= 32;
+ c += x_i * y_7 + (zz[i + 7] & M);
+ zz[i + 7] = (int)c;
+ c >>>= 32;
+ c += zc + (zz[i + 8] & M);
+ zz[i + 8] = (int)c;
+ zc = c >>> 32;
+ }
+ return (int)zc;
+ }
+
+ public static int mulAddTo(int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff)
{
long y_0 = y[yOff + 0] & M;
long y_1 = y[yOff + 1] & M;
@@ -632,47 +599,44 @@ public abstract class Nat256
return (int)zc;
}
- public static long mul33AddExt(int w, int[] xx, int xxOff, int[] yy, int yyOff, int[] zz, int zzOff)
+ public static long mul33Add(int w, int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
{
- // assert x >>> 31 == 0;
- // assert xxOff <= 8;
- // assert yyOff <= 8;
- // assert zzOff <= 8;
+ // assert w >>> 31 == 0;
long c = 0, wVal = w & M;
- long xx00 = xx[xxOff + 0] & M;
- c += wVal * xx00 + (yy[yyOff + 0] & M);
- zz[zzOff + 0] = (int)c;
+ long x0 = x[xOff + 0] & M;
+ c += wVal * x0 + (y[yOff + 0] & M);
+ z[zOff + 0] = (int)c;
c >>>= 32;
- long xx01 = xx[xxOff + 1] & M;
- c += wVal * xx01 + xx00 + (yy[yyOff + 1] & M);
- zz[zzOff + 1] = (int)c;
+ long x1 = x[xOff + 1] & M;
+ c += wVal * x1 + x0 + (y[yOff + 1] & M);
+ z[zOff + 1] = (int)c;
c >>>= 32;
- long xx02 = xx[xxOff + 2] & M;
- c += wVal * xx02 + xx01 + (yy[yyOff + 2] & M);
- zz[zzOff + 2] = (int)c;
+ long x2 = x[xOff + 2] & M;
+ c += wVal * x2 + x1 + (y[yOff + 2] & M);
+ z[zOff + 2] = (int)c;
c >>>= 32;
- long xx03 = xx[xxOff + 3] & M;
- c += wVal * xx03 + xx02 + (yy[yyOff + 3] & M);
- zz[zzOff + 3] = (int)c;
+ long x3 = x[xOff + 3] & M;
+ c += wVal * x3 + x2 + (y[yOff + 3] & M);
+ z[zOff + 3] = (int)c;
c >>>= 32;
- long xx04 = xx[xxOff + 4] & M;
- c += wVal * xx04 + xx03 + (yy[yyOff + 4] & M);
- zz[zzOff + 4] = (int)c;
+ long x4 = x[xOff + 4] & M;
+ c += wVal * x4 + x3 + (y[yOff + 4] & M);
+ z[zOff + 4] = (int)c;
c >>>= 32;
- long xx05 = xx[xxOff + 5] & M;
- c += wVal * xx05 + xx04 + (yy[yyOff + 5] & M);
- zz[zzOff + 5] = (int)c;
+ long x5 = x[xOff + 5] & M;
+ c += wVal * x5 + x4 + (y[yOff + 5] & M);
+ z[zOff + 5] = (int)c;
c >>>= 32;
- long xx06 = xx[xxOff + 6] & M;
- c += wVal * xx06 + xx05 + (yy[yyOff + 6] & M);
- zz[zzOff + 6] = (int)c;
+ long x6 = x[xOff + 6] & M;
+ c += wVal * x6 + x5 + (y[yOff + 6] & M);
+ z[zOff + 6] = (int)c;
c >>>= 32;
- long xx07 = xx[xxOff + 7] & M;
- c += wVal * xx07 + xx06 + (yy[yyOff + 7] & M);
- zz[zzOff + 7] = (int)c;
+ long x7 = x[xOff + 7] & M;
+ c += wVal * x7 + x6 + (y[yOff + 7] & M);
+ z[zOff + 7] = (int)c;
c >>>= 32;
- c += xx07;
+ c += x7;
return c;
}
@@ -786,7 +750,25 @@ public abstract class Nat256
c += (z[zOff + 3] & M);
z[zOff + 3] = (int)c;
c >>>= 32;
- return c == 0 ? 0 : inc(z, zOff + 4);
+ return c == 0 ? 0 : Nat.incAt(8, z, zOff, 4);
+ }
+
+ public static int mul33WordAdd(int x, int y, int[] z, int zOff)
+ {
+ // assert x >>> 31 == 0;
+ // assert zOff <= 5;
+
+ long c = 0, xVal = x & M, yVal = y & M;
+ c += yVal * xVal + (z[zOff + 0] & M);
+ z[zOff + 0] = (int)c;
+ c >>>= 32;
+ c += yVal + (z[zOff + 1] & M);
+ z[zOff + 1] = (int)c;
+ c >>>= 32;
+ c += (z[zOff + 2] & M);
+ z[zOff + 2] = (int)c;
+ c >>>= 32;
+ return c == 0 ? 0 : Nat.incAt(8, z, zOff, 3);
}
public static int mulWordDwordAdd(int x, long y, int[] z, int zOff)
@@ -802,113 +784,31 @@ public abstract class Nat256
c += (z[zOff + 2] & M);
z[zOff + 2] = (int)c;
c >>>= 32;
- return c == 0 ? 0 : inc(z, zOff + 3);
+ return c == 0 ? 0 : Nat.incAt(8, z, zOff, 3);
}
- public static int mulWordExt(int x, int[] y, int[] zz, int zzOff)
+ public static int mulWord(int x, int[] y, int[] z, int zOff)
{
- // assert zzOff <= 8;
long c = 0, xVal = x & M;
int i = 0;
do
{
c += xVal * (y[i] & M);
- zz[zzOff + i] = (int)c;
+ z[zOff + i] = (int)c;
c >>>= 32;
}
while (++i < 8);
return (int)c;
}
- public static int shiftDownBit(int[] x, int xLen, int c)
- {
- int i = xLen;
- while (--i >= 0)
- {
- int next = x[i];
- x[i] = (next >>> 1) | (c << 31);
- c = next;
- }
- return c << 31;
- }
-
- public static int shiftDownBit(int[] x, int c, int[] z)
- {
- int i = 8;
- while (--i >= 0)
- {
- int next = x[i];
- z[i] = (next >>> 1) | (c << 31);
- c = next;
- }
- return c << 31;
- }
-
- public static int shiftDownBits(int[] x, int xLen, int bits, int c)
- {
-// assert bits > 0 && bits < 32;
- int i = xLen;
- while (--i >= 0)
- {
- int next = x[i];
- x[i] = (next >>> bits) | (c << -bits);
- c = next;
- }
- return c << -bits;
- }
-
- public static int shiftDownWord(int[] x, int xLen, int c)
- {
- int i = xLen;
- while (--i >= 0)
- {
- int next = x[i];
- x[i] = c;
- c = next;
- }
- return c;
- }
-
- public static int shiftUpBit(int[] x, int xLen, int c)
- {
- for (int i = 0; i < xLen; ++i)
- {
- int next = x[i];
- x[i] = (next << 1) | (c >>> 31);
- c = next;
- }
- return c >>> 31;
- }
-
- public static int shiftUpBit(int[] x, int xOff, int xLen, int c)
- {
- for (int i = 0; i < xLen; ++i)
- {
- int next = x[xOff + i];
- x[xOff + i] = (next << 1) | (c >>> 31);
- c = next;
- }
- return c >>> 31;
- }
-
- public static int shiftUpBit(int[] x, int c, int[] z)
- {
- for (int i = 0; i < 8; ++i)
- {
- int next = x[i];
- z[i] = (next << 1) | (c >>> 31);
- c = next;
- }
- return c >>> 31;
- }
-
public static void square(int[] x, int[] zz)
{
long x_0 = x[0] & M;
long zz_1;
+ int c = 0, w;
{
- int c = 0, i = 7, j = 16;
+ int i = 7, j = 16;
do
{
long xVal = (x[i--] & M);
@@ -922,7 +822,8 @@ public abstract class Nat256
{
long p = x_0 * x_0;
zz_1 = ((c << 31) & M) | (p >>> 33);
- zz[0] = (int)(p >>> 1);
+ zz[0] = (int)p;
+ c = (int)(p >>> 32) & 1;
}
}
@@ -931,7 +832,9 @@ public abstract class Nat256
{
zz_1 += x_1 * x_0;
- zz[1] = (int)zz_1;
+ w = (int)zz_1;
+ zz[1] = (w << 1) | c;
+ c = w >>> 31;
zz_2 += zz_1 >>> 32;
}
@@ -940,7 +843,9 @@ public abstract class Nat256
long zz_4 = zz[4] & M;
{
zz_2 += x_2 * x_0;
- zz[2] = (int)zz_2;
+ w = (int)zz_2;
+ zz[2] = (w << 1) | c;
+ c = w >>> 31;
zz_3 += (zz_2 >>> 32) + x_2 * x_1;
zz_4 += zz_3 >>> 32;
zz_3 &= M;
@@ -951,7 +856,9 @@ public abstract class Nat256
long zz_6 = zz[6] & M;
{
zz_3 += x_3 * x_0;
- zz[3] = (int)zz_3;
+ w = (int)zz_3;
+ zz[3] = (w << 1) | c;
+ c = w >>> 31;
zz_4 += (zz_3 >>> 32) + x_3 * x_1;
zz_5 += (zz_4 >>> 32) + x_3 * x_2;
zz_4 &= M;
@@ -964,7 +871,9 @@ public abstract class Nat256
long zz_8 = zz[8] & M;
{
zz_4 += x_4 * x_0;
- zz[4] = (int)zz_4;
+ w = (int)zz_4;
+ zz[4] = (w << 1) | c;
+ c = w >>> 31;
zz_5 += (zz_4 >>> 32) + x_4 * x_1;
zz_6 += (zz_5 >>> 32) + x_4 * x_2;
zz_5 &= M;
@@ -979,7 +888,9 @@ public abstract class Nat256
long zz_10 = zz[10] & M;
{
zz_5 += x_5 * x_0;
- zz[5] = (int)zz_5;
+ w = (int)zz_5;
+ zz[5] = (w << 1) | c;
+ c = w >>> 31;
zz_6 += (zz_5 >>> 32) + x_5 * x_1;
zz_7 += (zz_6 >>> 32) + x_5 * x_2;
zz_6 &= M;
@@ -996,7 +907,9 @@ public abstract class Nat256
long zz_12 = zz[12] & M;
{
zz_6 += x_6 * x_0;
- zz[6] = (int)zz_6;
+ w = (int)zz_6;
+ zz[6] = (w << 1) | c;
+ c = w >>> 31;
zz_7 += (zz_6 >>> 32) + x_6 * x_1;
zz_8 += (zz_7 >>> 32) + x_6 * x_2;
zz_7 &= M;
@@ -1015,7 +928,9 @@ public abstract class Nat256
long zz_14 = zz[14] & M;
{
zz_7 += x_7 * x_0;
- zz[7] = (int)zz_7;
+ w = (int)zz_7;
+ zz[7] = (w << 1) | c;
+ c = w >>> 31;
zz_8 += (zz_7 >>> 32) + x_7 * x_1;
zz_9 += (zz_8 >>> 32) + x_7 * x_2;
zz_10 += (zz_9 >>> 32) + x_7 * x_3;
@@ -1025,16 +940,29 @@ public abstract class Nat256
zz_14 += zz_13 >>> 32;
}
- zz[8] = (int)zz_8;
- zz[9] = (int)zz_9;
- zz[10] = (int)zz_10;
- zz[11] = (int)zz_11;
- zz[12] = (int)zz_12;
- zz[13] = (int)zz_13;
- zz[14] = (int)zz_14;
- zz[15] += (int)(zz_14 >>> 32);
-
- shiftUpBit(zz, 16, (int)x_0 << 31);
+ w = (int)zz_8;
+ zz[8] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_9;
+ zz[9] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_10;
+ zz[10] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_11;
+ zz[11] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_12;
+ zz[12] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_13;
+ zz[13] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_14;
+ zz[14] = (w << 1) | c;
+ c = w >>> 31;
+ w = zz[15] + (int)(zz_14 >> 32);
+ zz[15] = (w << 1) | c;
}
public static void square(int[] x, int xOff, int[] zz, int zzOff)
@@ -1042,8 +970,9 @@ public abstract class Nat256
long x_0 = x[xOff + 0] & M;
long zz_1;
+ int c = 0, w;
{
- int c = 0, i = 7, j = 16;
+ int i = 7, j = 16;
do
{
long xVal = (x[xOff + i--] & M);
@@ -1057,7 +986,8 @@ public abstract class Nat256
{
long p = x_0 * x_0;
zz_1 = ((c << 31) & M) | (p >>> 33);
- zz[zzOff + 0] = (int)(p >>> 1);
+ zz[zzOff + 0] = (int)p;
+ c = (int)(p >>> 32) & 1;
}
}
@@ -1066,7 +996,9 @@ public abstract class Nat256
{
zz_1 += x_1 * x_0;
- zz[zzOff + 1] = (int)zz_1;
+ w = (int)zz_1;
+ zz[zzOff + 1] = (w << 1) | c;
+ c = w >>> 31;
zz_2 += zz_1 >>> 32;
}
@@ -1075,7 +1007,9 @@ public abstract class Nat256
long zz_4 = zz[zzOff + 4] & M;
{
zz_2 += x_2 * x_0;
- zz[zzOff + 2] = (int)zz_2;
+ w = (int)zz_2;
+ zz[zzOff + 2] = (w << 1) | c;
+ c = w >>> 31;
zz_3 += (zz_2 >>> 32) + x_2 * x_1;
zz_4 += zz_3 >>> 32;
zz_3 &= M;
@@ -1086,7 +1020,9 @@ public abstract class Nat256
long zz_6 = zz[zzOff + 6] & M;
{
zz_3 += x_3 * x_0;
- zz[zzOff + 3] = (int)zz_3;
+ w = (int)zz_3;
+ zz[zzOff + 3] = (w << 1) | c;
+ c = w >>> 31;
zz_4 += (zz_3 >>> 32) + x_3 * x_1;
zz_5 += (zz_4 >>> 32) + x_3 * x_2;
zz_4 &= M;
@@ -1099,7 +1035,9 @@ public abstract class Nat256
long zz_8 = zz[zzOff + 8] & M;
{
zz_4 += x_4 * x_0;
- zz[zzOff + 4] = (int)zz_4;
+ w = (int)zz_4;
+ zz[zzOff + 4] = (w << 1) | c;
+ c = w >>> 31;
zz_5 += (zz_4 >>> 32) + x_4 * x_1;
zz_6 += (zz_5 >>> 32) + x_4 * x_2;
zz_5 &= M;
@@ -1114,7 +1052,9 @@ public abstract class Nat256
long zz_10 = zz[zzOff + 10] & M;
{
zz_5 += x_5 * x_0;
- zz[zzOff + 5] = (int)zz_5;
+ w = (int)zz_5;
+ zz[zzOff + 5] = (w << 1) | c;
+ c = w >>> 31;
zz_6 += (zz_5 >>> 32) + x_5 * x_1;
zz_7 += (zz_6 >>> 32) + x_5 * x_2;
zz_6 &= M;
@@ -1131,7 +1071,9 @@ public abstract class Nat256
long zz_12 = zz[zzOff + 12] & M;
{
zz_6 += x_6 * x_0;
- zz[zzOff + 6] = (int)zz_6;
+ w = (int)zz_6;
+ zz[zzOff + 6] = (w << 1) | c;
+ c = w >>> 31;
zz_7 += (zz_6 >>> 32) + x_6 * x_1;
zz_8 += (zz_7 >>> 32) + x_6 * x_2;
zz_7 &= M;
@@ -1150,7 +1092,9 @@ public abstract class Nat256
long zz_14 = zz[zzOff + 14] & M;
{
zz_7 += x_7 * x_0;
- zz[zzOff + 7] = (int)zz_7;
+ w = (int)zz_7;
+ zz[zzOff + 7] = (w << 1) | c;
+ c = w >>> 31;
zz_8 += (zz_7 >>> 32) + x_7 * x_1;
zz_9 += (zz_8 >>> 32) + x_7 * x_2;
zz_10 += (zz_9 >>> 32) + x_7 * x_3;
@@ -1160,31 +1104,29 @@ public abstract class Nat256
zz_14 += zz_13 >>> 32;
}
- zz[zzOff + 8] = (int)zz_8;
- zz[zzOff + 9] = (int)zz_9;
- zz[zzOff + 10] = (int)zz_10;
- zz[zzOff + 11] = (int)zz_11;
- zz[zzOff + 12] = (int)zz_12;
- zz[zzOff + 13] = (int)zz_13;
- zz[zzOff + 14] = (int)zz_14;
- zz[zzOff + 15] += (int)(zz_14 >>> 32);
-
- shiftUpBit(zz, zzOff, 16, (int)x_0 << 31);
- }
-
- public static int squareWordAddExt(int[] x, int xPos, int[] zz)
- {
- // assert xPos > 0 && xPos < 8;
- long c = 0, xVal = x[xPos] & M;
- int i = 0;
- do
- {
- c += xVal * (x[i] & M) + (zz[xPos + i] & M);
- zz[xPos + i] = (int)c;
- c >>>= 32;
- }
- while (++i < xPos);
- return (int)c;
+ w = (int)zz_8;
+ zz[zzOff + 8] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_9;
+ zz[zzOff + 9] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_10;
+ zz[zzOff + 10] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_11;
+ zz[zzOff + 11] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_12;
+ zz[zzOff + 12] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_13;
+ zz[zzOff + 13] = (w << 1) | c;
+ c = w >>> 31;
+ w = (int)zz_14;
+ zz[zzOff + 14] = (w << 1) | c;
+ c = w >>> 31;
+ w = zz[zzOff + 15] + (int)(zz_14 >> 32);
+ zz[zzOff + 15] = (w << 1) | c;
}
public static int sub(int[] x, int[] y, int[] z)
@@ -1277,80 +1219,66 @@ public abstract class Nat256
return (int)c;
}
- // TODO Re-write to allow full range for x?
- public static int subDWord(long x, int[] z)
+ public static int subFrom(int[] x, int[] z)
{
- long c = -x;
- c += (z[0] & M);
+ long c = 0;
+ c += (z[0] & M) - (x[0] & M);
z[0] = (int)c;
c >>= 32;
- c += (z[1] & M);
+ c += (z[1] & M) - (x[1] & M);
z[1] = (int)c;
c >>= 32;
- return c == 0 ? 0 : dec(z, 2);
- }
-
- public static int subExt(int[] xx, int[] yy, int[] zz)
- {
- long c = 0;
- for (int i = 0; i < 16; ++i)
- {
- c += (xx[i] & M) - (yy[i] & M);
- zz[i] = (int)c;
- c >>= 32;
- }
+ c += (z[2] & M) - (x[2] & M);
+ z[2] = (int)c;
+ c >>= 32;
+ c += (z[3] & M) - (x[3] & M);
+ z[3] = (int)c;
+ c >>= 32;
+ c += (z[4] & M) - (x[4] & M);
+ z[4] = (int)c;
+ c >>= 32;
+ c += (z[5] & M) - (x[5] & M);
+ z[5] = (int)c;
+ c >>= 32;
+ c += (z[6] & M) - (x[6] & M);
+ z[6] = (int)c;
+ c >>= 32;
+ c += (z[7] & M) - (x[7] & M);
+ z[7] = (int)c;
+ c >>= 32;
return (int)c;
}
- public static int subFromExt(int[] x, int xOff, int[] zz, int zzOff)
+ public static int subFrom(int[] x, int xOff, int[] z, int zOff)
{
- // assert zzOff <= 8;
long c = 0;
- c += (zz[zzOff + 0] & M) - (x[xOff + 0] & M);
- zz[zzOff + 0] = (int)c;
+ c += (z[zOff + 0] & M) - (x[xOff + 0] & M);
+ z[zOff + 0] = (int)c;
c >>= 32;
- c += (zz[zzOff + 1] & M) - (x[xOff + 1] & M);
- zz[zzOff + 1] = (int)c;
+ c += (z[zOff + 1] & M) - (x[xOff + 1] & M);
+ z[zOff + 1] = (int)c;
c >>= 32;
- c += (zz[zzOff + 2] & M) - (x[xOff + 2] & M);
- zz[zzOff + 2] = (int)c;
+ c += (z[zOff + 2] & M) - (x[xOff + 2] & M);
+ z[zOff + 2] = (int)c;
c >>= 32;
- c += (zz[zzOff + 3] & M) - (x[xOff + 3] & M);
- zz[zzOff + 3] = (int)c;
+ c += (z[zOff + 3] & M) - (x[xOff + 3] & M);
+ z[zOff + 3] = (int)c;
c >>= 32;
- c += (zz[zzOff + 4] & M) - (x[xOff + 4] & M);
- zz[zzOff + 4] = (int)c;
+ c += (z[zOff + 4] & M) - (x[xOff + 4] & M);
+ z[zOff + 4] = (int)c;
c >>= 32;
- c += (zz[zzOff + 5] & M) - (x[xOff + 5] & M);
- zz[zzOff + 5] = (int)c;
+ c += (z[zOff + 5] & M) - (x[xOff + 5] & M);
+ z[zOff + 5] = (int)c;
c >>= 32;
- c += (zz[zzOff + 6] & M) - (x[xOff + 6] & M);
- zz[zzOff + 6] = (int)c;
+ c += (z[zOff + 6] & M) - (x[xOff + 6] & M);
+ z[zOff + 6] = (int)c;
c >>= 32;
- c += (zz[zzOff + 7] & M) - (x[xOff + 7] & M);
- zz[zzOff + 7] = (int)c;
+ c += (z[zOff + 7] & M) - (x[xOff + 7] & M);
+ z[zOff + 7] = (int)c;
c >>= 32;
return (int)c;
}
- public static int subWord(int x, int[] z, int zOff)
- {
- // assert zOff <= 7;
- long c = (z[zOff + 0] & M) - (x & M);
- z[zOff + 0] = (int)c;
- c >>= 32;
- return c == 0 ? 0 : dec(z, zOff + 1);
- }
-
- public static int subWordExt(int x, int[] zz, int zzOff)
- {
- // assert zzOff <= 15;
- long c = (zz[zzOff + 0] & M) - (x & M);
- zz[zzOff + 0] = (int)c;
- c >>= 32;
- return c == 0 ? 0 : decExt(zz, zzOff + 1);
- }
-
public static BigInteger toBigInteger(int[] x)
{
byte[] bs = new byte[32];
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat384.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat384.java
new file mode 100644
index 00000000..1a55e12c
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat384.java
@@ -0,0 +1,44 @@
+package org.bouncycastle.math.ec.custom.sec;
+
+import org.bouncycastle.math.ec.Nat;
+
+public abstract class Nat384
+{
+ public static void mul(int[] x, int[] y, int[] zz)
+ {
+ Nat192.mul(x, y, zz);
+ Nat192.mul(x, 6, y, 6, zz, 12);
+
+ int c18 = Nat192.addToEachOther(zz, 6, zz, 12);
+ int c12 = c18 + Nat192.addTo(zz, 0, zz, 6, 0);
+ c18 += Nat192.addTo(zz, 18, zz, 12, c12);
+
+ int[] dx = Nat192.create(), dy = Nat192.create();
+ boolean neg = Nat192.diff(x, 6, x, 0, dx, 0) != Nat192.diff(y, 6, y, 0, dy, 0);
+
+ int[] tt = Nat192.createExt();
+ Nat192.mul(dx, dy, tt);
+
+ c18 += neg ? Nat.addTo(12, tt, 0, zz, 6) : Nat.subFrom(12, tt, 0, zz, 6);
+ Nat.addWordAt(24, c18, zz, 18);
+ }
+
+ public static void square(int[] x, int[] zz)
+ {
+ Nat192.square(x, zz);
+ Nat192.square(x, 6, zz, 12);
+
+ int c18 = Nat192.addToEachOther(zz, 6, zz, 12);
+ int c12 = c18 + Nat192.addTo(zz, 0, zz, 6, 0);
+ c18 += Nat192.addTo(zz, 18, zz, 12, c12);
+
+ int[] dx = Nat192.create();
+ Nat192.diff(x, 6, x, 0, dx, 0);
+
+ int[] tt = Nat192.createExt();
+ Nat192.square(dx, tt);
+
+ c18 += Nat.subFrom(12, tt, 0, zz, 6);
+ Nat.addWordAt(24, c18, zz, 18);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat512.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat512.java
index a43008f0..59399617 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat512.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat512.java
@@ -20,9 +20,9 @@ public abstract class Nat512
Nat256.mul(dx, dy, tt);
c24 += neg ? Nat.addTo(16, tt, 0, zz, 8) : Nat.subFrom(16, tt, 0, zz, 8);
- Nat.addWordExt(16, c24, zz, 24);
+ Nat.addWordAt(32, c24, zz, 24);
}
-
+
public static void square(int[] x, int[] zz)
{
Nat256.square(x, zz);
@@ -39,6 +39,6 @@ public abstract class Nat512
Nat256.square(dx, tt);
c24 += Nat.subFrom(16, tt, 0, zz, 8);
- Nat.addWordExt(16, c24, zz, 24);
+ Nat.addWordAt(32, c24, zz, 24);
}
}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Curve.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Curve.java
index b26348cd..87d9f10c 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Curve.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Curve.java
@@ -5,7 +5,11 @@ import java.math.BigInteger;
import org.bouncycastle.math.ec.ECConstants;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECFieldElement;
+import org.bouncycastle.math.ec.ECMultiplier;
import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.ec.GLVMultiplier;
+import org.bouncycastle.math.ec.endo.GLVTypeBEndomorphism;
+import org.bouncycastle.math.ec.endo.GLVTypeBParameters;
import org.bouncycastle.math.field.FiniteFields;
import org.bouncycastle.util.encoders.Hex;
@@ -68,6 +72,11 @@ public class SecP192K1Curve extends ECCurve
return new SecP192K1Point(this, x, y, withCompression);
}
+ protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+ {
+ return new SecP192K1Point(this, x, y, zs, withCompression);
+ }
+
protected ECPoint decompressPoint(int yTilde, BigInteger X1)
{
ECFieldElement x = fromBigInteger(X1);
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Field.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Field.java
index 39fcd3d9..20827e55 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Field.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Field.java
@@ -2,15 +2,18 @@ package org.bouncycastle.math.ec.custom.sec;
import java.math.BigInteger;
+import org.bouncycastle.math.ec.Nat;
+
public class SecP192K1Field
{
// 2^192 - 2^32 - 2^12 - 2^8 - 2^7 - 2^6 - 2^3 - 1
static final int[] P = new int[]{ 0xFFFFEE37, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
- private static final int P5 = 0xFFFFFFFF;
- private static final int[] PExt = new int[]{ 0x013C4FD1, 0x00002392, 0x00000001, 0x00000000, 0x00000000,
+ static final int[] PExt = new int[]{ 0x013C4FD1, 0x00002392, 0x00000001, 0x00000000, 0x00000000,
0x00000000, 0xFFFFDC6E, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ private static final int[] PExtInv = new int[]{ 0xFEC3B02F, 0xFFFFDC6D, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0x00002391, 0x00000002 };
+ private static final int P5 = 0xFFFFFFFF;
private static final int PExt11 = 0xFFFFFFFF;
- private static final long PInv = 0x00000001000011C9L;
private static final int PInv33 = 0x11C9;
public static void add(int[] x, int[] y, int[] z)
@@ -18,26 +21,28 @@ public class SecP192K1Field
int c = Nat192.add(x, y, z);
if (c != 0 || (z[5] == P5 && Nat192.gte(z, P)))
{
- Nat192.addDWord(PInv, z, 0);
+ Nat.add33To(6, PInv33, z);
}
}
public static void addExt(int[] xx, int[] yy, int[] zz)
{
- int c = Nat192.addExt(xx, yy, zz);
- if (c != 0 || (zz[11] == PExt11 && Nat192.gteExt(zz, PExt)))
+ int c = Nat.add(12, xx, yy, zz);
+ if (c != 0 || (zz[11] == PExt11 && Nat.gte(12, zz, PExt)))
{
- Nat192.subExt(zz, PExt, zz);
+ if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0)
+ {
+ Nat.incAt(12, zz, PExtInv.length);
+ }
}
}
public static void addOne(int[] x, int[] z)
{
- System.arraycopy(x, 0, z, 0, 6);
- int c = Nat192.inc(z, 0);
+ int c = Nat.inc(6, x, z);
if (c != 0 || (z[5] == P5 && Nat192.gte(z, P)))
{
- Nat192.addDWord(PInv, z, 0);
+ Nat.add33To(6, PInv33, z);
}
}
@@ -46,7 +51,7 @@ public class SecP192K1Field
int[] z = Nat192.fromBigInteger(x);
if (z[5] == P5 && Nat192.gte(z, P))
{
- Nat192.addDWord(PInv, z, 0);
+ Nat192.subFrom(P, z);
}
return z;
}
@@ -55,12 +60,12 @@ public class SecP192K1Field
{
if ((x[0] & 1) == 0)
{
- Nat192.shiftDownBit(x, 0, z);
+ Nat.shiftDownBit(6, x, 0, z);
}
else
{
int c = Nat192.add(x, P, z);
- Nat192.shiftDownBit(z, c, z);
+ Nat.shiftDownBit(6, z, c);
}
}
@@ -71,6 +76,18 @@ public class SecP192K1Field
reduce(tt, z);
}
+ public static void multiplyAddToExt(int[] x, int[] y, int[] zz)
+ {
+ int c = Nat192.mulAddTo(x, y, zz);
+ if (c != 0 || (zz[11] == PExt11 && Nat.gte(12, zz, PExt)))
+ {
+ if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0)
+ {
+ Nat.incAt(12, zz, PExtInv.length);
+ }
+ }
+ }
+
public static void negate(int[] x, int[] z)
{
if (Nat192.isZero(x))
@@ -85,14 +102,23 @@ public class SecP192K1Field
public static void reduce(int[] xx, int[] z)
{
- long c = Nat192.mul33AddExt(PInv33, xx, 6, xx, 0, z, 0);
- c = Nat192.mul33DWordAdd(PInv33, c, z, 0);
+ long cc = Nat192.mul33Add(PInv33, xx, 6, xx, 0, z, 0);
+ int c = Nat192.mul33DWordAdd(PInv33, cc, z, 0);
// assert c == 0L || c == 1L;
if (c != 0 || (z[5] == P5 && Nat192.gte(z, P)))
{
- Nat192.addDWord(PInv, z, 0);
+ Nat.add33To(6, PInv33, z);
+ }
+ }
+
+ public static void reduce32(int x, int[] z)
+ {
+ if ((x != 0 && Nat192.mul33WordAdd(PInv33, x, z, 0) != 0)
+ || (z[5] == P5 && Nat192.gte(z, P)))
+ {
+ Nat.add33To(6, PInv33, z);
}
}
@@ -123,25 +149,28 @@ public class SecP192K1Field
int c = Nat192.sub(x, y, z);
if (c != 0)
{
- Nat192.subDWord(PInv, z);
+ Nat.sub33From(6, PInv33, z);
}
}
public static void subtractExt(int[] xx, int[] yy, int[] zz)
{
- int c = Nat192.subExt(xx, yy, zz);
+ int c = Nat.sub(12, xx, yy, zz);
if (c != 0)
{
- Nat192.addExt(zz, PExt, zz);
+ if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0)
+ {
+ Nat.decAt(12, zz, PExtInv.length);
+ }
}
}
public static void twice(int[] x, int[] z)
{
- int c = Nat192.shiftUpBit(x, 0, z);
+ int c = Nat.shiftUpBit(6, x, 0, z);
if (c != 0 || (z[5] == P5 && Nat192.gte(z, P)))
{
- Nat192.addDWord(PInv, z, 0);
+ Nat.add33To(6, PInv33, z);
}
}
}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1FieldElement.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1FieldElement.java
index 91d576d1..3e70754b 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1FieldElement.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1FieldElement.java
@@ -186,7 +186,7 @@ public class SecP192K1FieldElement extends ECFieldElement
int[] t2 = x3;
SecP192K1Field.square(t1, t2);
- return Arrays.areEqual(x1, t2) ? new SecP192K1FieldElement(t1) : null;
+ return Nat192.eq(x1, t2) ? new SecP192K1FieldElement(t1) : null;
}
public boolean equals(Object other)
@@ -202,11 +202,11 @@ public class SecP192K1FieldElement extends ECFieldElement
}
SecP192K1FieldElement o = (SecP192K1FieldElement)other;
- return Arrays.areEqual(x, o.x);
+ return Nat192.eq(x, o.x);
}
public int hashCode()
{
- return Q.hashCode() ^ Arrays.hashCode(x);
+ return Q.hashCode() ^ Arrays.hashCode(x, 0, 6);
}
}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Point.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Point.java
index da9e5e24..d3802086 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Point.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Point.java
@@ -3,6 +3,7 @@ package org.bouncycastle.math.ec.custom.sec;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECFieldElement;
import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.ec.Nat;
public class SecP192K1Point extends ECPoint
{
@@ -92,8 +93,9 @@ public class SecP192K1Point extends ECPoint
SecP192K1FieldElement Z1 = (SecP192K1FieldElement)this.zs[0];
SecP192K1FieldElement Z2 = (SecP192K1FieldElement)b.getZCoord(0);
+ int c;
int[] tt1 = Nat192.createExt();
- int[] tt2 = Nat192.createExt();
+ int[] t2 = Nat192.create();
int[] t3 = Nat192.create();
int[] t4 = Nat192.create();
@@ -109,7 +111,7 @@ public class SecP192K1Point extends ECPoint
S2 = t3;
SecP192K1Field.square(Z1.x, S2);
- U2 = tt2;
+ U2 = t2;
SecP192K1Field.multiply(S2, X2.x, U2);
SecP192K1Field.multiply(S2, Z1.x, S2);
@@ -138,7 +140,7 @@ public class SecP192K1Point extends ECPoint
int[] H = Nat192.create();
SecP192K1Field.subtract(U1, U2, H);
- int[] R = tt2;
+ int[] R = t2;
SecP192K1Field.subtract(S1, S2, R);
// Check if b == this or b == -this
@@ -163,19 +165,20 @@ public class SecP192K1Point extends ECPoint
int[] V = t3;
SecP192K1Field.multiply(HSquared, U1, V);
+ SecP192K1Field.negate(G, G);
Nat192.mul(S1, G, tt1);
+ c = Nat192.addBothTo(V, V, G);
+ SecP192K1Field.reduce32(c, G);
+
SecP192K1FieldElement X3 = new SecP192K1FieldElement(t4);
SecP192K1Field.square(R, X3.x);
- SecP192K1Field.add(X3.x, G, X3.x);
- SecP192K1Field.subtract(X3.x, V, X3.x);
- SecP192K1Field.subtract(X3.x, V, X3.x);
+ SecP192K1Field.subtract(X3.x, G, X3.x);
SecP192K1FieldElement Y3 = new SecP192K1FieldElement(G);
SecP192K1Field.subtract(V, X3.x, Y3.x);
- Nat192.mul(Y3.x, R, tt2);
- SecP192K1Field.subtractExt(tt2, tt1, tt2);
- SecP192K1Field.reduce(tt2, Y3.x);
+ SecP192K1Field.multiplyAddToExt(Y3.x, R, tt1);
+ SecP192K1Field.reduce(tt1, Y3.x);
SecP192K1FieldElement Z3 = new SecP192K1FieldElement(H);
if (!Z1IsOne)
@@ -210,27 +213,27 @@ public class SecP192K1Point extends ECPoint
SecP192K1FieldElement X1 = (SecP192K1FieldElement)this.x, Z1 = (SecP192K1FieldElement)this.zs[0];
+ int c;
+
int[] Y1Squared = Nat192.create();
SecP192K1Field.square(Y1.x, Y1Squared);
int[] T = Nat192.create();
SecP192K1Field.square(Y1Squared, T);
- int[] t1 = Nat192.create();
- SecP192K1Field.square(X1.x, t1);
-
int[] M = Nat192.create();
- SecP192K1Field.twice(t1, M);
- SecP192K1Field.add(M, t1, M);
+ SecP192K1Field.square(X1.x, M);
+ c = Nat192.addBothTo(M, M, M);
+ SecP192K1Field.reduce32(c, M);
int[] S = Y1Squared;
SecP192K1Field.multiply(Y1Squared, X1.x, S);
- SecP192K1Field.twice(S, S);
- SecP192K1Field.twice(S, S);
+ c = Nat.shiftUpBits(6, S, 2, 0);
+ SecP192K1Field.reduce32(c, S);
- SecP192K1Field.twice(T, t1);
- SecP192K1Field.twice(t1, t1);
- SecP192K1Field.twice(t1, t1);
+ int[] t1 = Nat192.create();
+ c = Nat.shiftUpBits(6, T, 3, 0, t1);
+ SecP192K1Field.reduce32(c, t1);
SecP192K1FieldElement X3 = new SecP192K1FieldElement(T);
SecP192K1Field.square(M, X3.x);
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Curve.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Curve.java
index 8e00c5bc..5491609b 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Curve.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Curve.java
@@ -69,6 +69,11 @@ public class SecP192R1Curve extends ECCurve
return new SecP192R1Point(this, x, y, withCompression);
}
+ protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+ {
+ return new SecP192R1Point(this, x, y, zs, withCompression);
+ }
+
protected ECPoint decompressPoint(int yTilde, BigInteger X1)
{
ECFieldElement x = fromBigInteger(X1);
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Field.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Field.java
index 02d0b72e..2f77815b 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Field.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Field.java
@@ -2,15 +2,19 @@ package org.bouncycastle.math.ec.custom.sec;
import java.math.BigInteger;
+import org.bouncycastle.math.ec.Nat;
+
public class SecP192R1Field
{
private static final long M = 0xFFFFFFFFL;
// 2^192 - 2^64 - 1
static final int[] P = new int[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
- private static final int P5 = 0xFFFFFFFF;
- private static final int[] PExt = new int[]{ 0x00000001, 0x00000000, 0x00000002, 0x00000000, 0x00000001,
+ static final int[] PExt = new int[]{ 0x00000001, 0x00000000, 0x00000002, 0x00000000, 0x00000001,
0x00000000, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ private static final int[] PExtInv = new int[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFE,
+ 0xFFFFFFFF, 0x00000001, 0x00000000, 0x00000002 };
+ private static final int P5 = 0xFFFFFFFF;
private static final int PExt11 = 0xFFFFFFFF;
public static void add(int[] x, int[] y, int[] z)
@@ -18,26 +22,28 @@ public class SecP192R1Field
int c = Nat192.add(x, y, z);
if (c != 0 || (z[5] == P5 && Nat192.gte(z, P)))
{
- Nat192.sub(z, P, z);
+ addPInvTo(z);
}
}
public static void addExt(int[] xx, int[] yy, int[] zz)
{
- int c = Nat192.addExt(xx, yy, zz);
- if (c != 0 || (zz[11] == PExt11 && Nat192.gteExt(zz, PExt)))
+ int c = Nat.add(12, xx, yy, zz);
+ if (c != 0 || (zz[11] == PExt11 && Nat.gte(12, zz, PExt)))
{
- Nat192.subExt(zz, PExt, zz);
+ if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0)
+ {
+ Nat.incAt(12, zz, PExtInv.length);
+ }
}
}
public static void addOne(int[] x, int[] z)
{
- System.arraycopy(x, 0, z, 0, 6);
- int c = Nat192.inc(z, 0);
+ int c = Nat.inc(6, x, z);
if (c != 0 || (z[5] == P5 && Nat192.gte(z, P)))
{
- Nat192.sub(z, P, z);
+ addPInvTo(z);
}
}
@@ -46,7 +52,7 @@ public class SecP192R1Field
int[] z = Nat192.fromBigInteger(x);
if (z[5] == P5 && Nat192.gte(z, P))
{
- Nat192.sub(z, P, z);
+ Nat192.subFrom(P, z);
}
return z;
}
@@ -55,12 +61,12 @@ public class SecP192R1Field
{
if ((x[0] & 1) == 0)
{
- Nat192.shiftDownBit(x, 0, z);
+ Nat.shiftDownBit(6, x, 0, z);
}
else
{
int c = Nat192.add(x, P, z);
- Nat192.shiftDownBit(z, c, z);
+ Nat.shiftDownBit(6, z, c);
}
}
@@ -71,6 +77,18 @@ public class SecP192R1Field
reduce(tt, z);
}
+ public static void multiplyAddToExt(int[] x, int[] y, int[] zz)
+ {
+ int c = Nat192.mulAddTo(x, y, zz);
+ if (c != 0 || (zz[11] == PExt11 && Nat.gte(12, zz, PExt)))
+ {
+ if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0)
+ {
+ Nat.incAt(12, zz, PExtInv.length);
+ }
+ }
+ }
+
public static void negate(int[] x, int[] z)
{
if (Nat192.isZero(x))
@@ -93,7 +111,7 @@ public class SecP192R1Field
long cc = 0;
cc += (xx[0] & M) + t0;
- z[0] = (int)cc;
+ int z0 = (int)cc;
cc >>= 32;
cc += (xx[1] & M) + t1;
z[1] = (int)cc;
@@ -103,7 +121,7 @@ public class SecP192R1Field
t1 += xx09;
cc += (xx[2] & M) + t0;
- z[2] = (int)cc;
+ long z2 = cc & M;
cc >>= 32;
cc += (xx[3] & M) + t1;
z[3] = (int)cc;
@@ -119,15 +137,57 @@ public class SecP192R1Field
z[5] = (int)cc;
cc >>= 32;
- int c = (int)cc;
- while (c > 0)
+ z2 += cc;
+
+ cc += (z0 & M);
+ z[0] = (int)cc;
+ cc >>= 32;
+ if (cc != 0)
{
- c += Nat192.sub(z, P, z);
+ cc += (z[1] & M);
+ z[1] = (int)cc;
+ z2 += cc >> 32;
}
+ z[2] = (int)z2;
+ cc = z2 >> 32;
- if (z[5] == P5 && Nat192.gte(z, P))
+// assert cc == 0 || cc == 1;
+
+ if ((cc != 0 && Nat.incAt(6, z, 3) != 0)
+ || (z[5] == P5 && Nat192.gte(z, P)))
{
- Nat192.sub(z, P, z);
+ addPInvTo(z);
+ }
+ }
+
+ public static void reduce32(int x, int[] z)
+ {
+ long cc = 0;
+
+ if (x != 0)
+ {
+ long xx06 = x & M;
+
+ cc += (z[0] & M) + xx06;
+ z[0] = (int)cc;
+ cc >>= 32;
+ if (cc != 0)
+ {
+ cc += (z[1] & M);
+ z[1] = (int)cc;
+ cc >>= 32;
+ }
+ cc += (z[2] & M) + xx06;
+ z[2] = (int)cc;
+ cc >>= 32;
+
+// assert cc == 0 || cc == 1;
+ }
+
+ if ((cc != 0 && Nat.incAt(6, z, 3) != 0)
+ || (z[5] == P5 && Nat192.gte(z, P)))
+ {
+ addPInvTo(z);
}
}
@@ -158,25 +218,68 @@ public class SecP192R1Field
int c = Nat192.sub(x, y, z);
if (c != 0)
{
- Nat192.add(z, P, z);
+ subPInvFrom(z);
}
}
public static void subtractExt(int[] xx, int[] yy, int[] zz)
{
- int c = Nat192.subExt(xx, yy, zz);
+ int c = Nat.sub(12, xx, yy, zz);
if (c != 0)
{
- Nat192.addExt(zz, PExt, zz);
+ if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0)
+ {
+ Nat.decAt(12, zz, PExtInv.length);
+ }
}
}
public static void twice(int[] x, int[] z)
{
- int c = Nat192.shiftUpBit(x, 0, z);
+ int c = Nat.shiftUpBit(6, x, 0, z);
if (c != 0 || (z[5] == P5 && Nat192.gte(z, P)))
{
- Nat192.sub(z, P, z);
+ addPInvTo(z);
+ }
+ }
+
+ private static void addPInvTo(int[] z)
+ {
+ long c = (z[0] & M) + 1;
+ z[0] = (int)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c += (z[1] & M);
+ z[1] = (int)c;
+ c >>= 32;
+ }
+ c += (z[2] & M) + 1;
+ z[2] = (int)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ Nat.incAt(6, z, 3);
+ }
+ }
+
+ private static void subPInvFrom(int[] z)
+ {
+ long c = (z[0] & M) - 1;
+ z[0] = (int)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c += (z[1] & M);
+ z[1] = (int)c;
+ c >>= 32;
+ }
+ c += (z[2] & M) - 1;
+ z[2] = (int)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ Nat.decAt(6, z, 3);
}
}
}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1FieldElement.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1FieldElement.java
index cc1a231d..15d7de7d 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1FieldElement.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1FieldElement.java
@@ -163,7 +163,7 @@ public class SecP192R1FieldElement extends ECFieldElement
SecP192R1Field.squareN(t1, 62, t1);
SecP192R1Field.square(t1, t2);
- return Arrays.areEqual(x1, t2) ? new SecP192R1FieldElement(t1) : null;
+ return Nat192.eq(x1, t2) ? new SecP192R1FieldElement(t1) : null;
}
public boolean equals(Object other)
@@ -179,11 +179,11 @@ public class SecP192R1FieldElement extends ECFieldElement
}
SecP192R1FieldElement o = (SecP192R1FieldElement)other;
- return Arrays.areEqual(x, o.x);
+ return Nat192.eq(x, o.x);
}
public int hashCode()
{
- return Q.hashCode() ^ Arrays.hashCode(x);
+ return Q.hashCode() ^ Arrays.hashCode(x, 0, 6);
}
}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Point.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Point.java
index fb62217d..9a629ae4 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Point.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Point.java
@@ -3,6 +3,7 @@ package org.bouncycastle.math.ec.custom.sec;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECFieldElement;
import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.ec.Nat;
public class SecP192R1Point extends ECPoint
{
@@ -91,8 +92,9 @@ public class SecP192R1Point extends ECPoint
SecP192R1FieldElement Z1 = (SecP192R1FieldElement)this.zs[0];
SecP192R1FieldElement Z2 = (SecP192R1FieldElement)b.getZCoord(0);
+ int c;
int[] tt1 = Nat192.createExt();
- int[] tt2 = Nat192.createExt();
+ int[] t2 = Nat192.create();
int[] t3 = Nat192.create();
int[] t4 = Nat192.create();
@@ -108,7 +110,7 @@ public class SecP192R1Point extends ECPoint
S2 = t3;
SecP192R1Field.square(Z1.x, S2);
- U2 = tt2;
+ U2 = t2;
SecP192R1Field.multiply(S2, X2.x, U2);
SecP192R1Field.multiply(S2, Z1.x, S2);
@@ -137,7 +139,7 @@ public class SecP192R1Point extends ECPoint
int[] H = Nat192.create();
SecP192R1Field.subtract(U1, U2, H);
- int[] R = tt2;
+ int[] R = t2;
SecP192R1Field.subtract(S1, S2, R);
// Check if b == this or b == -this
@@ -162,19 +164,20 @@ public class SecP192R1Point extends ECPoint
int[] V = t3;
SecP192R1Field.multiply(HSquared, U1, V);
+ SecP192R1Field.negate(G, G);
Nat192.mul(S1, G, tt1);
+ c = Nat192.addBothTo(V, V, G);
+ SecP192R1Field.reduce32(c, G);
+
SecP192R1FieldElement X3 = new SecP192R1FieldElement(t4);
SecP192R1Field.square(R, X3.x);
- SecP192R1Field.add(X3.x, G, X3.x);
- SecP192R1Field.subtract(X3.x, V, X3.x);
- SecP192R1Field.subtract(X3.x, V, X3.x);
+ SecP192R1Field.subtract(X3.x, G, X3.x);
SecP192R1FieldElement Y3 = new SecP192R1FieldElement(G);
SecP192R1Field.subtract(V, X3.x, Y3.x);
- Nat192.mul(Y3.x, R, tt2);
- SecP192R1Field.subtractExt(tt2, tt1, tt2);
- SecP192R1Field.reduce(tt2, Y3.x);
+ SecP192R1Field.multiplyAddToExt(Y3.x, R, tt1);
+ SecP192R1Field.reduce(tt1, Y3.x);
SecP192R1FieldElement Z3 = new SecP192R1FieldElement(H);
if (!Z1IsOne)
@@ -209,6 +212,7 @@ public class SecP192R1Point extends ECPoint
SecP192R1FieldElement X1 = (SecP192R1FieldElement)this.x, Z1 = (SecP192R1FieldElement)this.zs[0];
+ int c;
int[] t1 = Nat192.create();
int[] t2 = Nat192.create();
@@ -232,17 +236,16 @@ public class SecP192R1Point extends ECPoint
int[] M = t2;
SecP192R1Field.add(X1.x, Z1Squared, M);
SecP192R1Field.multiply(M, t1, M);
- SecP192R1Field.twice(M, t1);
- SecP192R1Field.add(M, t1, M);
+ c = Nat192.addBothTo(M, M, M);
+ SecP192R1Field.reduce32(c, M);
int[] S = Y1Squared;
SecP192R1Field.multiply(Y1Squared, X1.x, S);
- SecP192R1Field.twice(S, S);
- SecP192R1Field.twice(S, S);
+ c = Nat.shiftUpBits(6, S, 2, 0);
+ SecP192R1Field.reduce32(c, S);
- SecP192R1Field.twice(T, t1);
- SecP192R1Field.twice(t1, t1);
- SecP192R1Field.twice(t1, t1);
+ c = Nat.shiftUpBits(6, T, 3, 0, t1);
+ SecP192R1Field.reduce32(c, t1);
SecP192R1FieldElement X3 = new SecP192R1FieldElement(T);
SecP192R1Field.square(M, X3.x);
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Curve.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Curve.java
new file mode 100644
index 00000000..8323de1d
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Curve.java
@@ -0,0 +1,107 @@
+package org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.math.ec.ECConstants;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECFieldElement;
+import org.bouncycastle.math.ec.ECMultiplier;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.ec.GLVMultiplier;
+import org.bouncycastle.math.ec.endo.GLVTypeBEndomorphism;
+import org.bouncycastle.math.ec.endo.GLVTypeBParameters;
+import org.bouncycastle.math.field.FiniteFields;
+import org.bouncycastle.util.encoders.Hex;
+
+public class SecP224K1Curve extends ECCurve
+{
+ public static final BigInteger q = new BigInteger(1,
+ Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D"));
+
+ private static final int SECP224K1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+ protected SecP224K1Point infinity;
+
+ public SecP224K1Curve()
+ {
+ super(FiniteFields.getPrimeField(q));
+
+ this.infinity = new SecP224K1Point(this, null, null);
+
+ this.a = fromBigInteger(ECConstants.ZERO);
+ this.b = fromBigInteger(BigInteger.valueOf(5));
+ this.order = new BigInteger(1, Hex.decode("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7"));
+ this.cofactor = BigInteger.valueOf(1);
+ this.coord = SECP224K1_DEFAULT_COORDS;
+ }
+
+ protected ECCurve cloneCurve()
+ {
+ return new SecP224K1Curve();
+ }
+
+ public boolean supportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_JACOBIAN:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public BigInteger getQ()
+ {
+ return q;
+ }
+
+ public int getFieldSize()
+ {
+ return q.bitLength();
+ }
+
+ public ECFieldElement fromBigInteger(BigInteger x)
+ {
+ return new SecP224K1FieldElement(x);
+ }
+
+ protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)
+ {
+ return new SecP224K1Point(this, x, y, withCompression);
+ }
+
+ protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+ {
+ return new SecP224K1Point(this, x, y, zs, withCompression);
+ }
+
+ protected ECPoint decompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement x = fromBigInteger(X1);
+ ECFieldElement alpha = x.square().multiply(x).add(getB());
+ 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");
+ }
+
+ if (beta.testBitZero() != (yTilde == 1))
+ {
+ // Use the other root
+ beta = beta.negate();
+ }
+
+ return new SecP224K1Point(this, x, beta, true);
+ }
+
+ public ECPoint getInfinity()
+ {
+ return infinity;
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Field.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Field.java
new file mode 100644
index 00000000..0a9eebc8
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Field.java
@@ -0,0 +1,177 @@
+package org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.math.ec.Nat;
+
+public class SecP224K1Field
+{
+ // 2^224 - 2^32 - 2^12 - 2^11 - 2^9 - 2^7 - 2^4 - 2 - 1
+ static final int[] P = new int[]{ 0xFFFFE56D, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF };
+ static final int[] PExt = new int[]{ 0x02C23069, 0x00003526, 0x00000001, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFCADA, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ private static final int[] PExtInv = new int[]{ 0xFD3DCF97, 0xFFFFCAD9, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00003525, 0x00000002 };
+ private static final int P6 = 0xFFFFFFFF;
+ private static final int PExt13 = 0xFFFFFFFF;
+ private static final int PInv33 = 0x1A93;
+
+ public static void add(int[] x, int[] y, int[] z)
+ {
+ int c = Nat224.add(x, y, z);
+ if (c != 0 || (z[6] == P6 && Nat224.gte(z, P)))
+ {
+ Nat.add33To(7, PInv33, z);
+ }
+ }
+
+ public static void addExt(int[] xx, int[] yy, int[] zz)
+ {
+ int c = Nat.add(14, xx, yy, zz);
+ if (c != 0 || (zz[13] == PExt13 && Nat.gte(14, zz, PExt)))
+ {
+ if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0)
+ {
+ Nat.incAt(14, zz, PExtInv.length);
+ }
+ }
+ }
+
+ public static void addOne(int[] x, int[] z)
+ {
+ int c = Nat.inc(7, x, z);
+ if (c != 0 || (z[6] == P6 && Nat224.gte(z, P)))
+ {
+ Nat.add33To(7, PInv33, z);
+ }
+ }
+
+ public static int[] fromBigInteger(BigInteger x)
+ {
+ int[] z = Nat224.fromBigInteger(x);
+ if (z[6] == P6 && Nat224.gte(z, P))
+ {
+ Nat.add33To(7, PInv33, z);
+ }
+ return z;
+ }
+
+ public static void half(int[] x, int[] z)
+ {
+ if ((x[0] & 1) == 0)
+ {
+ Nat.shiftDownBit(7, x, 0, z);
+ }
+ else
+ {
+ int c = Nat224.add(x, P, z);
+ Nat.shiftDownBit(7, z, c);
+ }
+ }
+
+ public static void multiply(int[] x, int[] y, int[] z)
+ {
+ int[] tt = Nat224.createExt();
+ Nat224.mul(x, y, tt);
+ reduce(tt, z);
+ }
+
+ public static void multiplyAddToExt(int[] x, int[] y, int[] zz)
+ {
+ int c = Nat224.mulAddTo(x, y, zz);
+ if (c != 0 || (zz[13] == PExt13 && Nat.gte(14, zz, PExt)))
+ {
+ if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0)
+ {
+ Nat.incAt(14, zz, PExtInv.length);
+ }
+ }
+ }
+
+ public static void negate(int[] x, int[] z)
+ {
+ if (Nat224.isZero(x))
+ {
+ Nat224.zero(z);
+ }
+ else
+ {
+ Nat224.sub(P, x, z);
+ }
+ }
+
+ public static void reduce(int[] xx, int[] z)
+ {
+ long cc = Nat224.mul33Add(PInv33, xx, 7, xx, 0, z, 0);
+ int c = Nat224.mul33DWordAdd(PInv33, cc, z, 0);
+
+ // assert c == 0L || c == 1L;
+
+ if (c != 0 || (z[6] == P6 && Nat224.gte(z, P)))
+ {
+ Nat.add33To(7, PInv33, z);
+ }
+ }
+
+ public static void reduce32(int x, int[] z)
+ {
+ if ((x != 0 && Nat224.mul33WordAdd(PInv33, x, z, 0) != 0)
+ || (z[6] == P6 && Nat224.gte(z, P)))
+ {
+ Nat.add33To(7, PInv33, z);
+ }
+ }
+
+ public static void square(int[] x, int[] z)
+ {
+ int[] tt = Nat224.createExt();
+ Nat224.square(x, tt);
+ reduce(tt, z);
+ }
+
+ public static void squareN(int[] x, int n, int[] z)
+ {
+// assert n > 0;
+
+ int[] tt = Nat224.createExt();
+ Nat224.square(x, tt);
+ reduce(tt, z);
+
+ while (--n > 0)
+ {
+ Nat224.square(z, tt);
+ reduce(tt, z);
+ }
+ }
+
+ public static void subtract(int[] x, int[] y, int[] z)
+ {
+ int c = Nat224.sub(x, y, z);
+ if (c != 0)
+ {
+ Nat.sub33From(7, PInv33, z);
+ }
+ }
+
+ public static void subtractExt(int[] xx, int[] yy, int[] zz)
+ {
+ int c = Nat.sub(14, xx, yy, zz);
+ if (c != 0)
+ {
+ if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0)
+ {
+ Nat.decAt(14, zz, PExtInv.length);
+ }
+ }
+ }
+
+ public static void twice(int[] x, int[] z)
+ {
+ int c = Nat.shiftUpBit(7, x, 0, z);
+ if (c != 0 || (z[6] == P6 && Nat224.gte(z, P)))
+ {
+ Nat.add33To(7, PInv33, z);
+ }
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1FieldElement.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1FieldElement.java
new file mode 100644
index 00000000..5496c30a
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1FieldElement.java
@@ -0,0 +1,242 @@
+package org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.math.ec.ECFieldElement;
+import org.bouncycastle.math.ec.Mod;
+import org.bouncycastle.util.Arrays;
+
+public class SecP224K1FieldElement extends ECFieldElement
+{
+ public static final BigInteger Q = SecP224K1Curve.q;
+
+ // Calculated as ECConstants.TWO.modPow(Q.shiftRight(2), Q)
+ private static final int[] PRECOMP_POW2 = new int[]{ 0x33bfd202, 0xdcfad133, 0x2287624a, 0xc3811ba8,
+ 0xa85558fc, 0x1eaef5d7, 0x8edf154c };
+
+ protected int[] x;
+
+ public SecP224K1FieldElement(BigInteger x)
+ {
+ if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0)
+ {
+ throw new IllegalArgumentException("x value invalid for SecP224K1FieldElement");
+ }
+
+ this.x = SecP224K1Field.fromBigInteger(x);
+ }
+
+ public SecP224K1FieldElement()
+ {
+ this.x = Nat224.create();
+ }
+
+ protected SecP224K1FieldElement(int[] x)
+ {
+ this.x = x;
+ }
+
+ public boolean isZero()
+ {
+ return Nat224.isZero(x);
+ }
+
+ public boolean isOne()
+ {
+ return Nat224.isOne(x);
+ }
+
+ public boolean testBitZero()
+ {
+ return Nat224.getBit(x, 0) == 1;
+ }
+
+ public BigInteger toBigInteger()
+ {
+ return Nat224.toBigInteger(x);
+ }
+
+ public String getFieldName()
+ {
+ return "SecP224K1Field";
+ }
+
+ public int getFieldSize()
+ {
+ return Q.bitLength();
+ }
+
+ public ECFieldElement add(ECFieldElement b)
+ {
+ int[] z = Nat224.create();
+ SecP224K1Field.add(x, ((SecP224K1FieldElement)b).x, z);
+ return new SecP224K1FieldElement(z);
+ }
+
+ public ECFieldElement addOne()
+ {
+ int[] z = Nat224.create();
+ SecP224K1Field.addOne(x, z);
+ return new SecP224K1FieldElement(z);
+ }
+
+ public ECFieldElement subtract(ECFieldElement b)
+ {
+ int[] z = Nat224.create();
+ SecP224K1Field.subtract(x, ((SecP224K1FieldElement)b).x, z);
+ return new SecP224K1FieldElement(z);
+ }
+
+ public ECFieldElement multiply(ECFieldElement b)
+ {
+ int[] z = Nat224.create();
+ SecP224K1Field.multiply(x, ((SecP224K1FieldElement)b).x, z);
+ return new SecP224K1FieldElement(z);
+ }
+
+ public ECFieldElement divide(ECFieldElement b)
+ {
+// return multiply(b.invert());
+ int[] z = Nat224.create();
+ Mod.invert(SecP224K1Field.P, ((SecP224K1FieldElement)b).x, z);
+ SecP224K1Field.multiply(z, x, z);
+ return new SecP224K1FieldElement(z);
+ }
+
+ public ECFieldElement negate()
+ {
+ int[] z = Nat224.create();
+ SecP224K1Field.negate(x, z);
+ return new SecP224K1FieldElement(z);
+ }
+
+ public ECFieldElement square()
+ {
+ int[] z = Nat224.create();
+ SecP224K1Field.square(x, z);
+ return new SecP224K1FieldElement(z);
+ }
+
+ public ECFieldElement invert()
+ {
+// return new SecP224K1FieldElement(toBigInteger().modInverse(Q));
+ int[] z = Nat224.create();
+ Mod.invert(SecP224K1Field.P, x, z);
+ return new SecP224K1FieldElement(z);
+ }
+
+ // 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()
+ {
+ /*
+ * Q == 8m + 5, so we use Pocklington's method for this case.
+ *
+ * First, raise this element to the exponent 2^221 - 2^29 - 2^9 - 2^8 - 2^6 - 2^4 - 2^1 (i.e. m + 1)
+ *
+ * Breaking up the exponent's binary representation into "repunits", we get:
+ * { 191 1s } { 1 0s } { 19 1s } { 2 0s } { 1 1s } { 1 0s} { 1 1s } { 1 0s} { 3 1s } { 1 0s}
+ *
+ * Therefore we need an addition chain containing 1, 3, 19, 191 (the lengths of the repunits)
+ * We use: [1], 2, [3], 4, 8, 11, [19], 23, 42, 84, 107, [191]
+ */
+
+ int[] x1 = this.x;
+ if (Nat224.isZero(x1) || Nat224.isOne(x1))
+ {
+ return this;
+ }
+
+ int[] x2 = Nat224.create();
+ SecP224K1Field.square(x1, x2);
+ SecP224K1Field.multiply(x2, x1, x2);
+ int[] x3 = x2;
+ SecP224K1Field.square(x2, x3);
+ SecP224K1Field.multiply(x3, x1, x3);
+ int[] x4 = Nat224.create();
+ SecP224K1Field.square(x3, x4);
+ SecP224K1Field.multiply(x4, x1, x4);
+ int[] x8 = Nat224.create();
+ SecP224K1Field.squareN(x4, 4, x8);
+ SecP224K1Field.multiply(x8, x4, x8);
+ int[] x11 = Nat224.create();
+ SecP224K1Field.squareN(x8, 3, x11);
+ SecP224K1Field.multiply(x11, x3, x11);
+ int[] x19 = x11;
+ SecP224K1Field.squareN(x11, 8, x19);
+ SecP224K1Field.multiply(x19, x8, x19);
+ int[] x23 = x8;
+ SecP224K1Field.squareN(x19, 4, x23);
+ SecP224K1Field.multiply(x23, x4, x23);
+ int[] x42 = x4;
+ SecP224K1Field.squareN(x23, 19, x42);
+ SecP224K1Field.multiply(x42, x19, x42);
+ int[] x84 = Nat224.create();
+ SecP224K1Field.squareN(x42, 42, x84);
+ SecP224K1Field.multiply(x84, x42, x84);
+ int[] x107 = x42;
+ SecP224K1Field.squareN(x84, 23, x107);
+ SecP224K1Field.multiply(x107, x23, x107);
+ int[] x191 = x23;
+ SecP224K1Field.squareN(x107, 84, x191);
+ SecP224K1Field.multiply(x191, x84, x191);
+
+ int[] t1 = x191;
+ SecP224K1Field.squareN(t1, 20, t1);
+ SecP224K1Field.multiply(t1, x19, t1);
+ SecP224K1Field.squareN(t1, 3, t1);
+ SecP224K1Field.multiply(t1, x1, t1);
+ SecP224K1Field.squareN(t1, 2, t1);
+ SecP224K1Field.multiply(t1, x1, t1);
+ SecP224K1Field.squareN(t1, 4, t1);
+ SecP224K1Field.multiply(t1, x3, t1);
+ SecP224K1Field.square(t1, t1);
+
+ int[] t2 = x84;
+ SecP224K1Field.square(t1, t2);
+
+ if (Nat224.eq(x1, t2))
+ {
+ return new SecP224K1FieldElement(t1);
+ }
+
+ /*
+ * If the first guess is incorrect, we multiply by a precomputed power of 2 to get the second guess,
+ * which is ((4x)^(m + 1))/2 mod Q
+ */
+ SecP224K1Field.multiply(t1, PRECOMP_POW2, t1);
+
+ SecP224K1Field.square(t1, t2);
+
+ if (Nat224.eq(x1, t2))
+ {
+ return new SecP224K1FieldElement(t1);
+ }
+
+ return null;
+ }
+
+ public boolean equals(Object other)
+ {
+ if (other == this)
+ {
+ return true;
+ }
+
+ if (!(other instanceof SecP224K1FieldElement))
+ {
+ return false;
+ }
+
+ SecP224K1FieldElement o = (SecP224K1FieldElement)other;
+ return Nat224.eq(x, o.x);
+ }
+
+ public int hashCode()
+ {
+ return Q.hashCode() ^ Arrays.hashCode(x, 0, 7);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Point.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Point.java
new file mode 100644
index 00000000..6b72dbe7
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Point.java
@@ -0,0 +1,314 @@
+package org.bouncycastle.math.ec.custom.sec;
+
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECFieldElement;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.ec.Nat;
+
+public class SecP224K1Point 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
+ *
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecP224K1Point(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
+ *
+ * @deprecated per-point compression property will be removed, refer
+ * {@link #getEncoded(boolean)}
+ */
+ public SecP224K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
+ {
+ super(curve, x, y);
+
+ if ((x == null) != (y == null))
+ {
+ throw new IllegalArgumentException("Exactly one of the field elements is null");
+ }
+
+ this.withCompression = withCompression;
+ }
+
+ SecP224K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs,
+ boolean withCompression)
+ {
+ super(curve, x, y, zs);
+
+ this.withCompression = withCompression;
+ }
+
+ protected ECPoint detach()
+ {
+ return new SecP224K1Point(null, getAffineXCoord(), getAffineYCoord());
+ }
+
+ protected boolean getCompressionYTilde()
+ {
+ return this.getAffineYCoord().testBitZero();
+ }
+
+ // B.3 pg 62
+ public ECPoint add(ECPoint b)
+ {
+ if (this.isInfinity())
+ {
+ return b;
+ }
+ if (b.isInfinity())
+ {
+ return this;
+ }
+ if (this == b)
+ {
+ return twice();
+ }
+
+ ECCurve curve = this.getCurve();
+
+ SecP224K1FieldElement X1 = (SecP224K1FieldElement)this.x, Y1 = (SecP224K1FieldElement)this.y;
+ SecP224K1FieldElement X2 = (SecP224K1FieldElement)b.getXCoord(), Y2 = (SecP224K1FieldElement)b.getYCoord();
+
+ SecP224K1FieldElement Z1 = (SecP224K1FieldElement)this.zs[0];
+ SecP224K1FieldElement Z2 = (SecP224K1FieldElement)b.getZCoord(0);
+
+ int c;
+ int[] tt1 = Nat224.createExt();
+ int[] t2 = Nat224.create();
+ int[] t3 = Nat224.create();
+ int[] t4 = Nat224.create();
+
+ boolean Z1IsOne = Z1.isOne();
+ int[] U2, S2;
+ if (Z1IsOne)
+ {
+ U2 = X2.x;
+ S2 = Y2.x;
+ }
+ else
+ {
+ S2 = t3;
+ SecP224K1Field.square(Z1.x, S2);
+
+ U2 = t2;
+ SecP224K1Field.multiply(S2, X2.x, U2);
+
+ SecP224K1Field.multiply(S2, Z1.x, S2);
+ SecP224K1Field.multiply(S2, Y2.x, S2);
+ }
+
+ boolean Z2IsOne = Z2.isOne();
+ int[] U1, S1;
+ if (Z2IsOne)
+ {
+ U1 = X1.x;
+ S1 = Y1.x;
+ }
+ else
+ {
+ S1 = t4;
+ SecP224K1Field.square(Z2.x, S1);
+
+ U1 = tt1;
+ SecP224K1Field.multiply(S1, X1.x, U1);
+
+ SecP224K1Field.multiply(S1, Z2.x, S1);
+ SecP224K1Field.multiply(S1, Y1.x, S1);
+ }
+
+ int[] H = Nat224.create();
+ SecP224K1Field.subtract(U1, U2, H);
+
+ int[] R = t2;
+ SecP224K1Field.subtract(S1, S2, R);
+
+ // Check if b == this or b == -this
+ if (Nat224.isZero(H))
+ {
+ if (Nat224.isZero(R))
+ {
+ // this == b, i.e. this must be doubled
+ return this.twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return curve.getInfinity();
+ }
+
+ int[] HSquared = t3;
+ SecP224K1Field.square(H, HSquared);
+
+ int[] G = Nat224.create();
+ SecP224K1Field.multiply(HSquared, H, G);
+
+ int[] V = t3;
+ SecP224K1Field.multiply(HSquared, U1, V);
+
+ SecP224K1Field.negate(G, G);
+ Nat224.mul(S1, G, tt1);
+
+ c = Nat224.addBothTo(V, V, G);
+ SecP224K1Field.reduce32(c, G);
+
+ SecP224K1FieldElement X3 = new SecP224K1FieldElement(t4);
+ SecP224K1Field.square(R, X3.x);
+ SecP224K1Field.subtract(X3.x, G, X3.x);
+
+ SecP224K1FieldElement Y3 = new SecP224K1FieldElement(G);
+ SecP224K1Field.subtract(V, X3.x, Y3.x);
+ SecP224K1Field.multiplyAddToExt(Y3.x, R, tt1);
+ SecP224K1Field.reduce(tt1, Y3.x);
+
+ SecP224K1FieldElement Z3 = new SecP224K1FieldElement(H);
+ if (!Z1IsOne)
+ {
+ SecP224K1Field.multiply(Z3.x, Z1.x, Z3.x);
+ }
+ if (!Z2IsOne)
+ {
+ SecP224K1Field.multiply(Z3.x, Z2.x, Z3.x);
+ }
+
+ ECFieldElement[] zs = new ECFieldElement[] { Z3 };
+
+ return new SecP224K1Point(curve, X3, Y3, zs, this.withCompression);
+ }
+
+ // B.3 pg 62
+ public ECPoint twice()
+ {
+ if (this.isInfinity())
+ {
+ return this;
+ }
+
+ ECCurve curve = this.getCurve();
+
+ SecP224K1FieldElement Y1 = (SecP224K1FieldElement)this.y;
+ if (Y1.isZero())
+ {
+ return curve.getInfinity();
+ }
+
+ SecP224K1FieldElement X1 = (SecP224K1FieldElement)this.x, Z1 = (SecP224K1FieldElement)this.zs[0];
+
+ int c;
+
+ int[] Y1Squared = Nat224.create();
+ SecP224K1Field.square(Y1.x, Y1Squared);
+
+ int[] T = Nat224.create();
+ SecP224K1Field.square(Y1Squared, T);
+
+ int[] M = Nat224.create();
+ SecP224K1Field.square(X1.x, M);
+ c = Nat224.addBothTo(M, M, M);
+ SecP224K1Field.reduce32(c, M);
+
+ int[] S = Y1Squared;
+ SecP224K1Field.multiply(Y1Squared, X1.x, S);
+ c = Nat.shiftUpBits(7, S, 2, 0);
+ SecP224K1Field.reduce32(c, S);
+
+ int[] t1 = Nat224.create();
+ c = Nat.shiftUpBits(7, T, 3, 0, t1);
+ SecP224K1Field.reduce32(c, t1);
+
+ SecP224K1FieldElement X3 = new SecP224K1FieldElement(T);
+ SecP224K1Field.square(M, X3.x);
+ SecP224K1Field.subtract(X3.x, S, X3.x);
+ SecP224K1Field.subtract(X3.x, S, X3.x);
+
+ SecP224K1FieldElement Y3 = new SecP224K1FieldElement(S);
+ SecP224K1Field.subtract(S, X3.x, Y3.x);
+ SecP224K1Field.multiply(Y3.x, M, Y3.x);
+ SecP224K1Field.subtract(Y3.x, t1, Y3.x);
+
+ SecP224K1FieldElement Z3 = new SecP224K1FieldElement(M);
+ SecP224K1Field.twice(Y1.x, Z3.x);
+ if (!Z1.isOne())
+ {
+ SecP224K1Field.multiply(Z3.x, Z1.x, Z3.x);
+ }
+
+ return new SecP224K1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, this.withCompression);
+ }
+
+ public ECPoint twicePlus(ECPoint b)
+ {
+ if (this == b)
+ {
+ return threeTimes();
+ }
+ if (this.isInfinity())
+ {
+ return b;
+ }
+ if (b.isInfinity())
+ {
+ return twice();
+ }
+
+ ECFieldElement Y1 = this.y;
+ if (Y1.isZero())
+ {
+ return b;
+ }
+
+ return twice().add(b);
+ }
+
+ public ECPoint threeTimes()
+ {
+ if (this.isInfinity() || this.y.isZero())
+ {
+ return this;
+ }
+
+ // NOTE: Be careful about recursions between twicePlus and threeTimes
+ return twice().add(this);
+ }
+
+ // 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()
+ {
+ if (this.isInfinity())
+ {
+ return this;
+ }
+
+ return new SecP224K1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Curve.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Curve.java
new file mode 100644
index 00000000..bbb02701
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Curve.java
@@ -0,0 +1,105 @@
+package org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECFieldElement;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.field.FiniteFields;
+import org.bouncycastle.util.encoders.Hex;
+
+public class SecP224R1Curve extends ECCurve
+{
+ public static final BigInteger q = new BigInteger(1,
+ Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001"));
+
+ private static final int SecP224R1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+ protected SecP224R1Point infinity;
+
+ public SecP224R1Curve()
+ {
+ super(FiniteFields.getPrimeField(q));
+
+ this.infinity = new SecP224R1Point(this, null, null);
+
+ this.a = fromBigInteger(new BigInteger(1,
+ Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE")));
+ this.b = fromBigInteger(new BigInteger(1,
+ Hex.decode("B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4")));
+ this.order = new BigInteger(1, Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D"));
+ this.cofactor = BigInteger.valueOf(1);
+
+ this.coord = SecP224R1_DEFAULT_COORDS;
+ }
+
+ protected ECCurve cloneCurve()
+ {
+ return new SecP224R1Curve();
+ }
+
+ public boolean supportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_JACOBIAN:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public BigInteger getQ()
+ {
+ return q;
+ }
+
+ public int getFieldSize()
+ {
+ return q.bitLength();
+ }
+
+ public ECFieldElement fromBigInteger(BigInteger x)
+ {
+ return new SecP224R1FieldElement(x);
+ }
+
+ protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)
+ {
+ return new SecP224R1Point(this, x, y, withCompression);
+ }
+
+ protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+ {
+ return new SecP224R1Point(this, x, y, zs, withCompression);
+ }
+
+ protected ECPoint decompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement x = fromBigInteger(X1);
+ ECFieldElement alpha = x.square().add(getA()).multiply(x).add(getB());
+ 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");
+ }
+
+ if (beta.testBitZero() != (yTilde == 1))
+ {
+ // Use the other root
+ beta = beta.negate();
+ }
+
+ return new SecP224R1Point(this, x, beta, true);
+ }
+
+ public ECPoint getInfinity()
+ {
+ return infinity;
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Field.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Field.java
new file mode 100644
index 00000000..d39fb4dd
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Field.java
@@ -0,0 +1,297 @@
+package org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.math.ec.Nat;
+
+public class SecP224R1Field
+{
+ private static final long M = 0xFFFFFFFFL;
+
+ // 2^224 - 2^96 + 1
+ static final int[] P = new int[]{ 0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ static final int[] PExt = new int[]{ 0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ private static final int[] PExtInv = new int[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001 };
+ private static final int P6 = 0xFFFFFFFF;
+ private static final int PExt13 = 0xFFFFFFFF;
+
+ public static void add(int[] x, int[] y, int[] z)
+ {
+ int c = Nat224.add(x, y, z);
+ if (c != 0 || (z[6] == P6 && Nat224.gte(z, P)))
+ {
+ addPInvTo(z);
+ }
+ }
+
+ public static void addExt(int[] xx, int[] yy, int[] zz)
+ {
+ int c = Nat.add(14, xx, yy, zz);
+ if (c != 0 || (zz[13] == PExt13 && Nat.gte(14, zz, PExt)))
+ {
+ if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0)
+ {
+ Nat.incAt(14, zz, PExtInv.length);
+ }
+ }
+ }
+
+ public static void addOne(int[] x, int[] z)
+ {
+ int c = Nat.inc(7, x, z);
+ if (c != 0 || (z[6] == P6 && Nat224.gte(z, P)))
+ {
+ addPInvTo(z);
+ }
+ }
+
+ public static int[] fromBigInteger(BigInteger x)
+ {
+ int[] z = Nat224.fromBigInteger(x);
+ if (z[6] == P6 && Nat224.gte(z, P))
+ {
+ Nat224.subFrom(P, z);
+ }
+ return z;
+ }
+
+ public static void half(int[] x, int[] z)
+ {
+ if ((x[0] & 1) == 0)
+ {
+ Nat.shiftDownBit(7, x, 0, z);
+ }
+ else
+ {
+ int c = Nat224.add(x, P, z);
+ Nat.shiftDownBit(7, z, c);
+ }
+ }
+
+ public static void multiply(int[] x, int[] y, int[] z)
+ {
+ int[] tt = Nat224.createExt();
+ Nat224.mul(x, y, tt);
+ reduce(tt, z);
+ }
+
+ public static void multiplyAddToExt(int[] x, int[] y, int[] zz)
+ {
+ int c = Nat224.mulAddTo(x, y, zz);
+ if (c != 0 || (zz[13] == PExt13 && Nat.gte(14, zz, PExt)))
+ {
+ if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0)
+ {
+ Nat.incAt(14, zz, PExtInv.length);
+ }
+ }
+ }
+
+ public static void negate(int[] x, int[] z)
+ {
+ if (Nat224.isZero(x))
+ {
+ Nat224.zero(z);
+ }
+ else
+ {
+ Nat224.sub(P, x, z);
+ }
+ }
+
+ public static void reduce(int[] xx, int[] z)
+ {
+ long xx10 = xx[10] & M, xx11 = xx[11] & M, xx12 = xx[12] & M, xx13 = xx[13] & M;
+
+ final long n = 1;
+
+ long t0 = (xx[7] & M) + xx11 - n;
+ long t1 = (xx[8] & M) + xx12;
+ long t2 = (xx[9] & M) + xx13;
+
+ long cc = 0;
+ cc += (xx[0] & M) - t0;
+ long z0 = cc & M;
+ cc >>= 32;
+ cc += (xx[1] & M) - t1;
+ z[1] = (int)cc;
+ cc >>= 32;
+ cc += (xx[2] & M) - t2;
+ z[2] = (int)cc;
+ cc >>= 32;
+ cc += (xx[3] & M) + t0 - xx10;
+ long z3 = cc & M;
+ cc >>= 32;
+ cc += (xx[4] & M) + t1 - xx11;
+ z[4] = (int)cc;
+ cc >>= 32;
+ cc += (xx[5] & M) + t2 - xx12;
+ z[5] = (int)cc;
+ cc >>= 32;
+ cc += (xx[6] & M) + xx10 - xx13;
+ z[6] = (int)cc;
+ cc >>= 32;
+ cc += n;
+
+// assert cc >= 0;
+
+ z3 += cc;
+
+ z0 -= cc;
+ z[0] = (int)z0;
+ cc = z0 >> 32;
+ if (cc != 0)
+ {
+ cc += (z[1] & M);
+ z[1] = (int)cc;
+ cc >>= 32;
+ cc += (z[2] & M);
+ z[2] = (int)cc;
+ z3 += cc >> 32;
+ }
+ z[3] = (int)z3;
+ cc = z3 >> 32;
+
+// assert cc == 0 || cc == 1;
+
+ if ((cc != 0 && Nat.incAt(7, z, 4) != 0)
+ || (z[6] == P6 && Nat224.gte(z, P)))
+ {
+ addPInvTo(z);
+ }
+ }
+
+ public static void reduce32(int x, int[] z)
+ {
+ long cc = 0;
+
+ if (x != 0)
+ {
+ long xx07 = x & M;
+
+ cc += (z[0] & M) - xx07;
+ z[0] = (int)cc;
+ cc >>= 32;
+ if (cc != 0)
+ {
+ cc += (z[1] & M);
+ z[1] = (int)cc;
+ cc >>= 32;
+ cc += (z[2] & M);
+ z[2] = (int)cc;
+ cc >>= 32;
+ }
+ cc += (z[3] & M) + xx07;
+ z[3] = (int)cc;
+ cc >>= 32;
+
+// assert cc == 0 || cc == 1;
+ }
+
+ if ((cc != 0 && Nat.incAt(7, z, 4) != 0)
+ || (z[6] == P6 && Nat224.gte(z, P)))
+ {
+ addPInvTo(z);
+ }
+ }
+
+ public static void square(int[] x, int[] z)
+ {
+ int[] tt = Nat224.createExt();
+ Nat224.square(x, tt);
+ reduce(tt, z);
+ }
+
+ public static void squareN(int[] x, int n, int[] z)
+ {
+// assert n > 0;
+
+ int[] tt = Nat224.createExt();
+ Nat224.square(x, tt);
+ reduce(tt, z);
+
+ while (--n > 0)
+ {
+ Nat224.square(z, tt);
+ reduce(tt, z);
+ }
+ }
+
+ public static void subtract(int[] x, int[] y, int[] z)
+ {
+ int c = Nat224.sub(x, y, z);
+ if (c != 0)
+ {
+ subPInvFrom(z);
+ }
+ }
+
+ public static void subtractExt(int[] xx, int[] yy, int[] zz)
+ {
+ int c = Nat.sub(14, xx, yy, zz);
+ if (c != 0)
+ {
+ if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0)
+ {
+ Nat.decAt(14, zz, PExtInv.length);
+ }
+ }
+ }
+
+ public static void twice(int[] x, int[] z)
+ {
+ int c = Nat.shiftUpBit(7, x, 0, z);
+ if (c != 0 || (z[6] == P6 && Nat224.gte(z, P)))
+ {
+ addPInvTo(z);
+ }
+ }
+
+ private static void addPInvTo(int[] z)
+ {
+ long c = (z[0] & M) - 1;
+ z[0] = (int)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c += (z[1] & M);
+ z[1] = (int)c;
+ c >>= 32;
+ c += (z[2] & M);
+ z[2] = (int)c;
+ c >>= 32;
+ }
+ c += (z[3] & M) + 1;
+ z[3] = (int)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ Nat.incAt(7, z, 4);
+ }
+ }
+
+ private static void subPInvFrom(int[] z)
+ {
+ long c = (z[0] & M) + 1;
+ z[0] = (int)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c += (z[1] & M);
+ z[1] = (int)c;
+ c >>= 32;
+ c += (z[2] & M);
+ z[2] = (int)c;
+ c >>= 32;
+ }
+ c += (z[3] & M) - 1;
+ z[3] = (int)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ Nat.decAt(7, z, 4);
+ }
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1FieldElement.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1FieldElement.java
new file mode 100644
index 00000000..90e03de3
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1FieldElement.java
@@ -0,0 +1,272 @@
+package org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.math.ec.ECFieldElement;
+import org.bouncycastle.math.ec.Mod;
+import org.bouncycastle.math.ec.Nat;
+import org.bouncycastle.util.Arrays;
+
+public class SecP224R1FieldElement extends ECFieldElement
+{
+ public static final BigInteger Q = SecP224R1Curve.q;
+
+ protected int[] x;
+
+ public SecP224R1FieldElement(BigInteger x)
+ {
+ if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0)
+ {
+ throw new IllegalArgumentException("x value invalid for SecP224R1FieldElement");
+ }
+
+ this.x = SecP224R1Field.fromBigInteger(x);
+ }
+
+ public SecP224R1FieldElement()
+ {
+ this.x = Nat224.create();
+ }
+
+ protected SecP224R1FieldElement(int[] x)
+ {
+ this.x = x;
+ }
+
+ public boolean isZero()
+ {
+ return Nat224.isZero(x);
+ }
+
+ public boolean isOne()
+ {
+ return Nat224.isOne(x);
+ }
+
+ public boolean testBitZero()
+ {
+ return Nat224.getBit(x, 0) == 1;
+ }
+
+ public BigInteger toBigInteger()
+ {
+ return Nat224.toBigInteger(x);
+ }
+
+ public String getFieldName()
+ {
+ return "SecP224R1Field";
+ }
+
+ public int getFieldSize()
+ {
+ return Q.bitLength();
+ }
+
+ public ECFieldElement add(ECFieldElement b)
+ {
+ int[] z = Nat224.create();
+ SecP224R1Field.add(x, ((SecP224R1FieldElement)b).x, z);
+ return new SecP224R1FieldElement(z);
+ }
+
+ public ECFieldElement addOne()
+ {
+ int[] z = Nat224.create();
+ SecP224R1Field.addOne(x, z);
+ return new SecP224R1FieldElement(z);
+ }
+
+ public ECFieldElement subtract(ECFieldElement b)
+ {
+ int[] z = Nat224.create();
+ SecP224R1Field.subtract(x, ((SecP224R1FieldElement)b).x, z);
+ return new SecP224R1FieldElement(z);
+ }
+
+ public ECFieldElement multiply(ECFieldElement b)
+ {
+ int[] z = Nat224.create();
+ SecP224R1Field.multiply(x, ((SecP224R1FieldElement)b).x, z);
+ return new SecP224R1FieldElement(z);
+ }
+
+ public ECFieldElement divide(ECFieldElement b)
+ {
+// return multiply(b.invert());
+ int[] z = Nat224.create();
+ Mod.invert(SecP224R1Field.P, ((SecP224R1FieldElement)b).x, z);
+ SecP224R1Field.multiply(z, x, z);
+ return new SecP224R1FieldElement(z);
+ }
+
+ public ECFieldElement negate()
+ {
+ int[] z = Nat224.create();
+ SecP224R1Field.negate(x, z);
+ return new SecP224R1FieldElement(z);
+ }
+
+ public ECFieldElement square()
+ {
+ int[] z = Nat224.create();
+ SecP224R1Field.square(x, z);
+ return new SecP224R1FieldElement(z);
+ }
+
+ public ECFieldElement invert()
+ {
+// return new SecP224R1FieldElement(toBigInteger().modInverse(Q));
+ int[] z = Nat224.create();
+ Mod.invert(SecP224R1Field.P, x, z);
+ return new SecP224R1FieldElement(z);
+ }
+
+ /**
+ * return a sqrt root - the routine verifies that the calculation returns the right value - if
+ * none exists it returns null.
+ */
+ public ECFieldElement sqrt()
+ {
+ int[] c = this.x;
+ if (Nat224.isZero(c) || Nat224.isOne(c))
+ {
+ return this;
+ }
+
+ int[] nc = Nat224.create();
+ SecP224R1Field.negate(c, nc);
+
+ int[] r = Mod.random(SecP224R1Field.P);
+ int[] t = Nat224.create();
+
+ if (!isSquare(c))
+ {
+ return null;
+ }
+
+ while (!trySqrt(nc, r, t))
+ {
+ SecP224R1Field.addOne(r, r);
+ }
+
+ SecP224R1Field.square(t, r);
+
+ return Nat224.eq(c, r) ? new SecP224R1FieldElement(t) : null;
+ }
+
+ public boolean equals(Object other)
+ {
+ if (other == this)
+ {
+ return true;
+ }
+
+ if (!(other instanceof SecP224R1FieldElement))
+ {
+ return false;
+ }
+
+ SecP224R1FieldElement o = (SecP224R1FieldElement)other;
+ return Nat224.eq(x, o.x);
+ }
+
+ public int hashCode()
+ {
+ return Q.hashCode() ^ Arrays.hashCode(x, 0, 7);
+ }
+
+ private static boolean isSquare(int[] x)
+ {
+ int[] t1 = Nat224.create();
+ int[] t2 = Nat224.create();
+ Nat224.copy(x, t1);
+
+ for (int i = 0; i < 7; ++i)
+ {
+ Nat224.copy(t1, t2);
+ SecP224R1Field.squareN(t1, 1 << i, t1);
+ SecP224R1Field.multiply(t1, t2, t1);
+ }
+
+ SecP224R1Field.squareN(t1, 95, t1);
+ return Nat224.isOne(t1);
+ }
+
+ private static void RM(int[] nc, int[] d0, int[] e0, int[] d1, int[] e1, int[] f1, int[] t)
+ {
+ SecP224R1Field.multiply(e1, e0, t);
+ SecP224R1Field.multiply(t, nc, t);
+ SecP224R1Field.multiply(d1, d0, f1);
+ SecP224R1Field.add(f1, t, f1);
+ SecP224R1Field.multiply(d1, e0, t);
+ Nat224.copy(f1, d1);
+ SecP224R1Field.multiply(e1, d0, e1);
+ SecP224R1Field.add(e1, t, e1);
+ SecP224R1Field.square(e1, f1);
+ SecP224R1Field.multiply(f1, nc, f1);
+ }
+
+ private static void RP(int[] nc, int[] d1, int[] e1, int[] f1, int[] t)
+ {
+ Nat224.copy(nc, f1);
+
+ int[] d0 = Nat224.create();
+ int[] e0 = Nat224.create();
+
+ for (int i = 0; i < 7; ++i)
+ {
+ Nat224.copy(d1, d0);
+ Nat224.copy(e1, e0);
+
+ int j = 1 << i;
+ while (--j >= 0)
+ {
+ RS(d1, e1, f1, t);
+ }
+
+ RM(nc, d0, e0, d1, e1, f1, t);
+ }
+ }
+
+ private static void RS(int[] d, int[] e, int[] f, int[] t)
+ {
+ SecP224R1Field.multiply(e, d, e);
+ SecP224R1Field.twice(e, e);
+ SecP224R1Field.square(d, t);
+ SecP224R1Field.add(f, t, d);
+ SecP224R1Field.multiply(f, t, f);
+ int c = Nat.shiftUpBits(7, f, 2, 0);
+ SecP224R1Field.reduce32(c, f);
+ }
+
+ private static boolean trySqrt(int[] nc, int[] r, int[] t)
+ {
+ int[] d1 = Nat224.create();
+ Nat224.copy(r, d1);
+ int[] e1 = Nat224.create();
+ e1[0] = 1;
+ int[] f1 = Nat224.create();
+ RP(nc, d1, e1, f1, t);
+
+ int[] d0 = Nat224.create();
+ int[] e0 = Nat224.create();
+
+ for (int k = 1; k < 96; ++k)
+ {
+ Nat224.copy(d1, d0);
+ Nat224.copy(e1, e0);
+
+ RS(d1, e1, f1, t);
+
+ if (Nat224.isZero(d1))
+ {
+ Mod.invert(SecP224R1Field.P, e0, t);
+ SecP224R1Field.multiply(t, d0, t);
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Point.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Point.java
new file mode 100644
index 00000000..8b4de02f
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Point.java
@@ -0,0 +1,323 @@
+package org.bouncycastle.math.ec.custom.sec;
+
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECFieldElement;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.ec.Nat;
+
+public class SecP224R1Point 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
+ *
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecP224R1Point(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
+ *
+ * @deprecated per-point compression property will be removed, refer
+ * {@link #getEncoded(boolean)}
+ */
+ public SecP224R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
+ {
+ super(curve, x, y);
+
+ if ((x == null) != (y == null))
+ {
+ throw new IllegalArgumentException("Exactly one of the field elements is null");
+ }
+
+ this.withCompression = withCompression;
+ }
+
+ SecP224R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+ {
+ super(curve, x, y, zs);
+
+ this.withCompression = withCompression;
+ }
+
+ protected ECPoint detach()
+ {
+ return new SecP224R1Point(null, getAffineXCoord(), getAffineYCoord());
+ }
+
+ protected boolean getCompressionYTilde()
+ {
+ return this.getAffineYCoord().testBitZero();
+ }
+
+ public ECPoint add(ECPoint b)
+ {
+ if (this.isInfinity())
+ {
+ return b;
+ }
+ if (b.isInfinity())
+ {
+ return this;
+ }
+ if (this == b)
+ {
+ return twice();
+ }
+
+ ECCurve curve = this.getCurve();
+
+ SecP224R1FieldElement X1 = (SecP224R1FieldElement)this.x, Y1 = (SecP224R1FieldElement)this.y;
+ SecP224R1FieldElement X2 = (SecP224R1FieldElement)b.getXCoord(), Y2 = (SecP224R1FieldElement)b.getYCoord();
+
+ SecP224R1FieldElement Z1 = (SecP224R1FieldElement)this.zs[0];
+ SecP224R1FieldElement Z2 = (SecP224R1FieldElement)b.getZCoord(0);
+
+ int c;
+ int[] tt1 = Nat224.createExt();
+ int[] t2 = Nat224.create();
+ int[] t3 = Nat224.create();
+ int[] t4 = Nat224.create();
+
+ boolean Z1IsOne = Z1.isOne();
+ int[] U2, S2;
+ if (Z1IsOne)
+ {
+ U2 = X2.x;
+ S2 = Y2.x;
+ }
+ else
+ {
+ S2 = t3;
+ SecP224R1Field.square(Z1.x, S2);
+
+ U2 = t2;
+ SecP224R1Field.multiply(S2, X2.x, U2);
+
+ SecP224R1Field.multiply(S2, Z1.x, S2);
+ SecP224R1Field.multiply(S2, Y2.x, S2);
+ }
+
+ boolean Z2IsOne = Z2.isOne();
+ int[] U1, S1;
+ if (Z2IsOne)
+ {
+ U1 = X1.x;
+ S1 = Y1.x;
+ }
+ else
+ {
+ S1 = t4;
+ SecP224R1Field.square(Z2.x, S1);
+
+ U1 = tt1;
+ SecP224R1Field.multiply(S1, X1.x, U1);
+
+ SecP224R1Field.multiply(S1, Z2.x, S1);
+ SecP224R1Field.multiply(S1, Y1.x, S1);
+ }
+
+ int[] H = Nat224.create();
+ SecP224R1Field.subtract(U1, U2, H);
+
+ int[] R = t2;
+ SecP224R1Field.subtract(S1, S2, R);
+
+ // Check if b == this or b == -this
+ if (Nat224.isZero(H))
+ {
+ if (Nat224.isZero(R))
+ {
+ // this == b, i.e. this must be doubled
+ return this.twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return curve.getInfinity();
+ }
+
+ int[] HSquared = t3;
+ SecP224R1Field.square(H, HSquared);
+
+ int[] G = Nat224.create();
+ SecP224R1Field.multiply(HSquared, H, G);
+
+ int[] V = t3;
+ SecP224R1Field.multiply(HSquared, U1, V);
+
+ SecP224R1Field.negate(G, G);
+ Nat224.mul(S1, G, tt1);
+
+ c = Nat224.addBothTo(V, V, G);
+ SecP224R1Field.reduce32(c, G);
+
+ SecP224R1FieldElement X3 = new SecP224R1FieldElement(t4);
+ SecP224R1Field.square(R, X3.x);
+ SecP224R1Field.subtract(X3.x, G, X3.x);
+
+ SecP224R1FieldElement Y3 = new SecP224R1FieldElement(G);
+ SecP224R1Field.subtract(V, X3.x, Y3.x);
+ SecP224R1Field.multiplyAddToExt(Y3.x, R, tt1);
+ SecP224R1Field.reduce(tt1, Y3.x);
+
+ SecP224R1FieldElement Z3 = new SecP224R1FieldElement(H);
+ if (!Z1IsOne)
+ {
+ SecP224R1Field.multiply(Z3.x, Z1.x, Z3.x);
+ }
+ if (!Z2IsOne)
+ {
+ SecP224R1Field.multiply(Z3.x, Z2.x, Z3.x);
+ }
+
+ ECFieldElement[] zs = new ECFieldElement[]{ Z3 };
+
+ return new SecP224R1Point(curve, X3, Y3, zs, this.withCompression);
+ }
+
+ public ECPoint twice()
+ {
+ if (this.isInfinity())
+ {
+ return this;
+ }
+
+ ECCurve curve = this.getCurve();
+
+ SecP224R1FieldElement Y1 = (SecP224R1FieldElement)this.y;
+ if (Y1.isZero())
+ {
+ return curve.getInfinity();
+ }
+
+ SecP224R1FieldElement X1 = (SecP224R1FieldElement)this.x, Z1 = (SecP224R1FieldElement)this.zs[0];
+
+ int c;
+ int[] t1 = Nat224.create();
+ int[] t2 = Nat224.create();
+
+ int[] Y1Squared = Nat224.create();
+ SecP224R1Field.square(Y1.x, Y1Squared);
+
+ int[] T = Nat224.create();
+ SecP224R1Field.square(Y1Squared, T);
+
+ boolean Z1IsOne = Z1.isOne();
+
+ int[] Z1Squared = Z1.x;
+ if (!Z1IsOne)
+ {
+ Z1Squared = t2;
+ SecP224R1Field.square(Z1.x, Z1Squared);
+ }
+
+ SecP224R1Field.subtract(X1.x, Z1Squared, t1);
+
+ int[] M = t2;
+ SecP224R1Field.add(X1.x, Z1Squared, M);
+ SecP224R1Field.multiply(M, t1, M);
+ c = Nat224.addBothTo(M, M, M);
+ SecP224R1Field.reduce32(c, M);
+
+ int[] S = Y1Squared;
+ SecP224R1Field.multiply(Y1Squared, X1.x, S);
+ c = Nat.shiftUpBits(7, S, 2, 0);
+ SecP224R1Field.reduce32(c, S);
+
+ c = Nat.shiftUpBits(7, T, 3, 0, t1);
+ SecP224R1Field.reduce32(c, t1);
+
+ SecP224R1FieldElement X3 = new SecP224R1FieldElement(T);
+ SecP224R1Field.square(M, X3.x);
+ SecP224R1Field.subtract(X3.x, S, X3.x);
+ SecP224R1Field.subtract(X3.x, S, X3.x);
+
+ SecP224R1FieldElement Y3 = new SecP224R1FieldElement(S);
+ SecP224R1Field.subtract(S, X3.x, Y3.x);
+ SecP224R1Field.multiply(Y3.x, M, Y3.x);
+ SecP224R1Field.subtract(Y3.x, t1, Y3.x);
+
+ SecP224R1FieldElement Z3 = new SecP224R1FieldElement(M);
+ SecP224R1Field.twice(Y1.x, Z3.x);
+ if (!Z1IsOne)
+ {
+ SecP224R1Field.multiply(Z3.x, Z1.x, Z3.x);
+ }
+
+ return new SecP224R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression);
+ }
+
+ public ECPoint twicePlus(ECPoint b)
+ {
+ if (this == b)
+ {
+ return threeTimes();
+ }
+ if (this.isInfinity())
+ {
+ return b;
+ }
+ if (b.isInfinity())
+ {
+ return twice();
+ }
+
+ ECFieldElement Y1 = this.y;
+ if (Y1.isZero())
+ {
+ return b;
+ }
+
+ return twice().add(b);
+ }
+
+ public ECPoint threeTimes()
+ {
+ if (this.isInfinity() || this.y.isZero())
+ {
+ return this;
+ }
+
+ // NOTE: Be careful about recursions between twicePlus and threeTimes
+ return twice().add(this);
+ }
+
+ public ECPoint subtract(ECPoint b)
+ {
+ if (b.isInfinity())
+ {
+ return this;
+ }
+
+ // Add -b
+ return add(b.negate());
+ }
+
+ public ECPoint negate()
+ {
+ if (this.isInfinity())
+ {
+ return this;
+ }
+
+ return new SecP224R1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Curve.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Curve.java
index 39c730d1..7977d9df 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Curve.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Curve.java
@@ -5,7 +5,11 @@ import java.math.BigInteger;
import org.bouncycastle.math.ec.ECConstants;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECFieldElement;
+import org.bouncycastle.math.ec.ECMultiplier;
import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.ec.GLVMultiplier;
+import org.bouncycastle.math.ec.endo.GLVTypeBEndomorphism;
+import org.bouncycastle.math.ec.endo.GLVTypeBParameters;
import org.bouncycastle.math.field.FiniteFields;
import org.bouncycastle.util.encoders.Hex;
@@ -67,6 +71,11 @@ public class SecP256K1Curve extends ECCurve
return new SecP256K1Point(this, x, y, withCompression);
}
+ protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+ {
+ return new SecP256K1Point(this, x, y, zs, withCompression);
+ }
+
protected ECPoint decompressPoint(int yTilde, BigInteger X1)
{
ECFieldElement x = fromBigInteger(X1);
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Field.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Field.java
index 74313386..221f505c 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Field.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Field.java
@@ -2,17 +2,20 @@ package org.bouncycastle.math.ec.custom.sec;
import java.math.BigInteger;
+import org.bouncycastle.math.ec.Nat;
+
public class SecP256K1Field
{
// 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
static final int[] P = new int[]{ 0xFFFFFC2F, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF };
- private static final int P7 = 0xFFFFFFFF;
- private static final int[] PExt = new int[]{ 0x000E90A1, 0x000007A2, 0x00000001, 0x00000000, 0x00000000,
+ static final int[] PExt = new int[]{ 0x000E90A1, 0x000007A2, 0x00000001, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0xFFFFF85E, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF };
+ private static final int[] PExtInv = new int[]{ 0xFFF16F5F, 0xFFFFF85D, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x000007A1, 0x00000002 };
+ private static final int P7 = 0xFFFFFFFF;
private static final int PExt15 = 0xFFFFFFFF;
- private static final long PInv = 0x00000001000003D1L;
private static final int PInv33 = 0x3D1;
public static void add(int[] x, int[] y, int[] z)
@@ -20,26 +23,28 @@ public class SecP256K1Field
int c = Nat256.add(x, y, z);
if (c != 0 || (z[7] == P7 && Nat256.gte(z, P)))
{
- Nat256.addDWord(PInv, z, 0);
+ Nat.add33To(8, PInv33, z);
}
}
public static void addExt(int[] xx, int[] yy, int[] zz)
{
- int c = Nat256.addExt(xx, yy, zz);
- if (c != 0 || (zz[15] == PExt15 && Nat256.gteExt(zz, PExt)))
+ int c = Nat.add(16, xx, yy, zz);
+ if (c != 0 || (zz[15] == PExt15 && Nat.gte(16, zz, PExt)))
{
- Nat256.subExt(zz, PExt, zz);
+ if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0)
+ {
+ Nat.incAt(16, zz, PExtInv.length);
+ }
}
}
public static void addOne(int[] x, int[] z)
{
- System.arraycopy(x, 0, z, 0, 8);
- int c = Nat256.inc(z, 0);
+ int c = Nat.inc(8, x, z);
if (c != 0 || (z[7] == P7 && Nat256.gte(z, P)))
{
- Nat256.addDWord(PInv, z, 0);
+ Nat.add33To(8, PInv33, z);
}
}
@@ -48,7 +53,7 @@ public class SecP256K1Field
int[] z = Nat256.fromBigInteger(x);
if (z[7] == P7 && Nat256.gte(z, P))
{
- Nat256.addDWord(PInv, z, 0);
+ Nat256.subFrom(P, z);
}
return z;
}
@@ -57,12 +62,12 @@ public class SecP256K1Field
{
if ((x[0] & 1) == 0)
{
- Nat256.shiftDownBit(x, 0, z);
+ Nat.shiftDownBit(8, x, 0, z);
}
else
{
int c = Nat256.add(x, P, z);
- Nat256.shiftDownBit(z, c, z);
+ Nat.shiftDownBit(8, z, c);
}
}
@@ -73,6 +78,18 @@ public class SecP256K1Field
reduce(tt, z);
}
+ public static void multiplyAddToExt(int[] x, int[] y, int[] zz)
+ {
+ int c = Nat256.mulAddTo(x, y, zz);
+ if (c != 0 || (zz[15] == PExt15 && Nat.gte(16, zz, PExt)))
+ {
+ if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0)
+ {
+ Nat.incAt(16, zz, PExtInv.length);
+ }
+ }
+ }
+
public static void negate(int[] x, int[] z)
{
if (Nat256.isZero(x))
@@ -87,14 +104,23 @@ public class SecP256K1Field
public static void reduce(int[] xx, int[] z)
{
- long c = Nat256.mul33AddExt(PInv33, xx, 8, xx, 0, z, 0);
- c = Nat256.mul33DWordAdd(PInv33, c, z, 0);
+ long cc = Nat256.mul33Add(PInv33, xx, 8, xx, 0, z, 0);
+ int c = Nat256.mul33DWordAdd(PInv33, cc, z, 0);
// assert c == 0L || c == 1L;
if (c != 0 || (z[7] == P7 && Nat256.gte(z, P)))
{
- Nat256.addDWord(PInv, z, 0);
+ Nat.add33To(8, PInv33, z);
+ }
+ }
+
+ public static void reduce32(int x, int[] z)
+ {
+ if ((x != 0 && Nat256.mul33WordAdd(PInv33, x, z, 0) != 0)
+ || (z[7] == P7 && Nat256.gte(z, P)))
+ {
+ Nat.add33To(8, PInv33, z);
}
}
@@ -125,25 +151,28 @@ public class SecP256K1Field
int c = Nat256.sub(x, y, z);
if (c != 0)
{
- Nat256.subDWord(PInv, z);
+ Nat.sub33From(8, PInv33, z);
}
}
public static void subtractExt(int[] xx, int[] yy, int[] zz)
{
- int c = Nat256.subExt(xx, yy, zz);
+ int c = Nat.sub(16, xx, yy, zz);
if (c != 0)
{
- Nat256.addExt(zz, PExt, zz);
+ if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0)
+ {
+ Nat.decAt(16, zz, PExtInv.length);
+ }
}
}
public static void twice(int[] x, int[] z)
{
- int c = Nat256.shiftUpBit(x, 0, z);
+ int c = Nat.shiftUpBit(8, x, 0, z);
if (c != 0 || (z[7] == P7 && Nat256.gte(z, P)))
{
- Nat256.addDWord(PInv, z, 0);
+ Nat.add33To(8, PInv33, z);
}
}
}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1FieldElement.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1FieldElement.java
index 0a874767..4454ef70 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1FieldElement.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1FieldElement.java
@@ -188,7 +188,7 @@ public class SecP256K1FieldElement extends ECFieldElement
int[] t2 = x2;
SecP256K1Field.square(t1, t2);
- return Arrays.areEqual(x1, t2) ? new SecP256K1FieldElement(t1) : null;
+ return Nat256.eq(x1, t2) ? new SecP256K1FieldElement(t1) : null;
}
public boolean equals(Object other)
@@ -204,11 +204,11 @@ public class SecP256K1FieldElement extends ECFieldElement
}
SecP256K1FieldElement o = (SecP256K1FieldElement)other;
- return Arrays.areEqual(x, o.x);
+ return Nat256.eq(x, o.x);
}
public int hashCode()
{
- return Q.hashCode() ^ Arrays.hashCode(x);
+ return Q.hashCode() ^ Arrays.hashCode(x, 0, 8);
}
}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Point.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Point.java
index f1d07cad..9557cb26 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Point.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Point.java
@@ -3,6 +3,7 @@ package org.bouncycastle.math.ec.custom.sec;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECFieldElement;
import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.ec.Nat;
public class SecP256K1Point extends ECPoint
{
@@ -92,8 +93,9 @@ public class SecP256K1Point extends ECPoint
SecP256K1FieldElement Z1 = (SecP256K1FieldElement)this.zs[0];
SecP256K1FieldElement Z2 = (SecP256K1FieldElement)b.getZCoord(0);
+ int c;
int[] tt1 = Nat256.createExt();
- int[] tt2 = Nat256.createExt();
+ int[] t2 = Nat256.create();
int[] t3 = Nat256.create();
int[] t4 = Nat256.create();
@@ -109,7 +111,7 @@ public class SecP256K1Point extends ECPoint
S2 = t3;
SecP256K1Field.square(Z1.x, S2);
- U2 = tt2;
+ U2 = t2;
SecP256K1Field.multiply(S2, X2.x, U2);
SecP256K1Field.multiply(S2, Z1.x, S2);
@@ -138,7 +140,7 @@ public class SecP256K1Point extends ECPoint
int[] H = Nat256.create();
SecP256K1Field.subtract(U1, U2, H);
- int[] R = tt2;
+ int[] R = t2;
SecP256K1Field.subtract(S1, S2, R);
// Check if b == this or b == -this
@@ -163,19 +165,20 @@ public class SecP256K1Point extends ECPoint
int[] V = t3;
SecP256K1Field.multiply(HSquared, U1, V);
+ SecP256K1Field.negate(G, G);
Nat256.mul(S1, G, tt1);
+ c = Nat256.addBothTo(V, V, G);
+ SecP256K1Field.reduce32(c, G);
+
SecP256K1FieldElement X3 = new SecP256K1FieldElement(t4);
SecP256K1Field.square(R, X3.x);
- SecP256K1Field.add(X3.x, G, X3.x);
- SecP256K1Field.subtract(X3.x, V, X3.x);
- SecP256K1Field.subtract(X3.x, V, X3.x);
+ SecP256K1Field.subtract(X3.x, G, X3.x);
SecP256K1FieldElement Y3 = new SecP256K1FieldElement(G);
SecP256K1Field.subtract(V, X3.x, Y3.x);
- Nat256.mul(Y3.x, R, tt2);
- SecP256K1Field.subtractExt(tt2, tt1, tt2);
- SecP256K1Field.reduce(tt2, Y3.x);
+ SecP256K1Field.multiplyAddToExt(Y3.x, R, tt1);
+ SecP256K1Field.reduce(tt1, Y3.x);
SecP256K1FieldElement Z3 = new SecP256K1FieldElement(H);
if (!Z1IsOne)
@@ -210,27 +213,27 @@ public class SecP256K1Point extends ECPoint
SecP256K1FieldElement X1 = (SecP256K1FieldElement)this.x, Z1 = (SecP256K1FieldElement)this.zs[0];
+ int c;
+
int[] Y1Squared = Nat256.create();
SecP256K1Field.square(Y1.x, Y1Squared);
int[] T = Nat256.create();
SecP256K1Field.square(Y1Squared, T);
- int[] t1 = Nat256.create();
- SecP256K1Field.square(X1.x, t1);
-
int[] M = Nat256.create();
- SecP256K1Field.twice(t1, M);
- SecP256K1Field.add(M, t1, M);
+ SecP256K1Field.square(X1.x, M);
+ c = Nat256.addBothTo(M, M, M);
+ SecP256K1Field.reduce32(c, M);
int[] S = Y1Squared;
SecP256K1Field.multiply(Y1Squared, X1.x, S);
- SecP256K1Field.twice(S, S);
- SecP256K1Field.twice(S, S);
+ c = Nat.shiftUpBits(8, S, 2, 0);
+ SecP256K1Field.reduce32(c, S);
- SecP256K1Field.twice(T, t1);
- SecP256K1Field.twice(t1, t1);
- SecP256K1Field.twice(t1, t1);
+ int[] t1 = Nat256.create();
+ c = Nat.shiftUpBits(8, T, 3, 0, t1);
+ SecP256K1Field.reduce32(c, t1);
SecP256K1FieldElement X3 = new SecP256K1FieldElement(T);
SecP256K1Field.square(M, X3.x);
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Curve.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Curve.java
index f27ac876..ae3bfacb 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Curve.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Curve.java
@@ -69,6 +69,11 @@ public class SecP256R1Curve extends ECCurve
return new SecP256R1Point(this, x, y, withCompression);
}
+ protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+ {
+ return new SecP256R1Point(this, x, y, zs, withCompression);
+ }
+
protected ECPoint decompressPoint(int yTilde, BigInteger X1)
{
ECFieldElement x = fromBigInteger(X1);
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java
index 21ecc226..479f62e7 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java
@@ -2,6 +2,8 @@ package org.bouncycastle.math.ec.custom.sec;
import java.math.BigInteger;
+import org.bouncycastle.math.ec.Nat;
+
public class SecP256R1Field
{
private static final long M = 0xFFFFFFFFL;
@@ -9,36 +11,36 @@ public class SecP256R1Field
// 2^256 - 2^224 + 2^192 + 2^96 - 1
static final int[] P = new int[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000,
0x00000001, 0xFFFFFFFF };
- private static final int P7 = 0xFFFFFFFF;
- private static final int[] PExt = new int[]{ 0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF,
+ static final int[] PExt = new int[]{ 0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFE, 0x00000001, 0xFFFFFFFE, 0x00000001, 0xFFFFFFFE, 0x00000001, 0x00000001, 0xFFFFFFFE,
0x00000002, 0xFFFFFFFE };
+ private static final int P7 = 0xFFFFFFFF;
+ private static final int PExt15 = 0xFFFFFFFF;
public static void add(int[] x, int[] y, int[] z)
{
int c = Nat256.add(x, y, z);
if (c != 0 || (z[7] == P7 && Nat256.gte(z, P)))
{
- Nat256.sub(z, P, z);
+ addPInvTo(z);
}
}
public static void addExt(int[] xx, int[] yy, int[] zz)
{
- int c = Nat256.addExt(xx, yy, zz);
- if (c != 0 || Nat256.gteExt(zz, PExt))
+ int c = Nat.add(16, xx, yy, zz);
+ if (c != 0 || ((zz[15] & PExt15) == PExt15 && Nat.gte(16, zz, PExt)))
{
- Nat256.subExt(zz, PExt, zz);
+ Nat.subFrom(16, PExt, zz);
}
}
public static void addOne(int[] x, int[] z)
{
- System.arraycopy(x, 0, z, 0, 8);
- int c = Nat256.inc(z, 0);
+ int c = Nat.inc(8, x, z);
if (c != 0 || (z[7] == P7 && Nat256.gte(z, P)))
{
- Nat256.sub(z, P, z);
+ addPInvTo(z);
}
}
@@ -47,7 +49,7 @@ public class SecP256R1Field
int[] z = Nat256.fromBigInteger(x);
if (z[7] == P7 && Nat256.gte(z, P))
{
- Nat256.sub(z, P, z);
+ Nat256.subFrom(P, z);
}
return z;
}
@@ -56,12 +58,12 @@ public class SecP256R1Field
{
if ((x[0] & 1) == 0)
{
- Nat256.shiftDownBit(x, 0, z);
+ Nat.shiftDownBit(8, x, 0, z);
}
else
{
int c = Nat256.add(x, P, z);
- Nat256.shiftDownBit(z, c, z);
+ Nat.shiftDownBit(8, z, c);
}
}
@@ -72,6 +74,15 @@ public class SecP256R1Field
reduce(tt, z);
}
+ public static void multiplyAddToExt(int[] x, int[] y, int[] zz)
+ {
+ int c = Nat256.mulAddTo(x, y, zz);
+ if (c != 0 || ((zz[15] & PExt15) == PExt15 && Nat.gte(16, zz, PExt)))
+ {
+ Nat.subFrom(16, PExt, zz);
+ }
+ }
+
public static void negate(int[] x, int[] z)
{
if (Nat256.isZero(x))
@@ -89,9 +100,13 @@ public class SecP256R1Field
long xx08 = xx[8] & M, xx09 = xx[9] & M, xx10 = xx[10] & M, xx11 = xx[11] & M;
long xx12 = xx[12] & M, xx13 = xx[13] & M, xx14 = xx[14] & M, xx15 = xx[15] & M;
+ final long n = 6;
+
+ xx08 -= n;
+
long t0 = xx08 + xx09;
long t1 = xx09 + xx10;
- long t2 = xx10 + xx11;
+ long t2 = xx10 + xx11 - xx15;
long t3 = xx11 + xx12;
long t4 = xx12 + xx13;
long t5 = xx13 + xx14;
@@ -104,7 +119,7 @@ public class SecP256R1Field
cc += (xx[1] & M) + t1 - t4 - t6;
z[1] = (int)cc;
cc >>= 32;
- cc += (xx[2] & M) + t2 - t5 - xx15;
+ cc += (xx[2] & M) + t2 - t5;
z[2] = (int)cc;
cc >>= 32;
cc += (xx[3] & M) + (t3 << 1) + xx13 - xx15 - t0;
@@ -113,36 +128,67 @@ public class SecP256R1Field
cc += (xx[4] & M) + (t4 << 1) + xx14 - t1;
z[4] = (int)cc;
cc >>= 32;
- cc += (xx[5] & M) + (t5 << 1) + xx15 - t2;
+ cc += (xx[5] & M) + (t5 << 1) - t2;
z[5] = (int)cc;
cc >>= 32;
cc += (xx[6] & M) + (t6 << 1) + t5 - t0;
z[6] = (int)cc;
cc >>= 32;
- cc += (xx[7] & M) + (xx15 << 1) + xx15 + xx08 - t2 - t4;
+ cc += (xx[7] & M) + (xx15 << 1) + xx08 - t2 - t4;
z[7] = (int)cc;
cc >>= 32;
+ cc += n;
+
+// assert cc >= 0;
- int c = (int)cc;
- if (c < 0)
+ reduce32((int)cc, z);
+ }
+
+ public static void reduce32(int x, int[] z)
+ {
+ long cc = 0;
+
+ if (x != 0)
{
- do
+ long xx08 = x & M;
+
+ cc += (z[0] & M) + xx08;
+ z[0] = (int)cc;
+ cc >>= 32;
+ if (cc != 0)
{
- c += Nat256.add(z, P, z);
+ cc += (z[1] & M);
+ z[1] = (int)cc;
+ cc >>= 32;
+ cc += (z[2] & M);
+ z[2] = (int)cc;
+ cc >>= 32;
}
- while (c < 0);
- }
- else
- {
- while (c > 0)
+ cc += (z[3] & M) - xx08;
+ z[3] = (int)cc;
+ cc >>= 32;
+ if (cc != 0)
{
- c += Nat256.sub(z, P, z);
+ cc += (z[4] & M);
+ z[4] = (int)cc;
+ cc >>= 32;
+ cc += (z[5] & M);
+ z[5] = (int)cc;
+ cc >>= 32;
}
+ cc += (z[6] & M) - xx08;
+ z[6] = (int)cc;
+ cc >>= 32;
+ cc += (z[7] & M) + xx08;
+ z[7] = (int)cc;
+ cc >>= 32;
- if (z[7] == P7 && Nat256.gte(z, P))
- {
- Nat256.sub(z, P, z);
- }
+// assert cc == 0 || cc == 1;
+ }
+
+ if (cc != 0 || (z[7] == P7 && Nat256.gte(z, P)))
+ {
+ addPInvTo(z);
}
}
@@ -173,25 +219,93 @@ public class SecP256R1Field
int c = Nat256.sub(x, y, z);
if (c != 0)
{
- Nat256.add(z, P, z);
+ subPInvFrom(z);
}
}
public static void subtractExt(int[] xx, int[] yy, int[] zz)
{
- int c = Nat256.subExt(xx, yy, zz);
+ int c = Nat.sub(16, xx, yy, zz);
if (c != 0)
{
- Nat256.addExt(zz, PExt, zz);
+ Nat.addTo(16, PExt, zz);
}
}
public static void twice(int[] x, int[] z)
{
- int c = Nat256.shiftUpBit(x, 0, z);
+ int c = Nat.shiftUpBit(8, x, 0, z);
if (c != 0 || (z[7] == P7 && Nat256.gte(z, P)))
{
- Nat256.sub(z, P, z);
+ addPInvTo(z);
+ }
+ }
+
+ private static void addPInvTo(int[] z)
+ {
+ long c = (z[0] & M) + 1;
+ z[0] = (int)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c += (z[1] & M);
+ z[1] = (int)c;
+ c >>= 32;
+ c += (z[2] & M);
+ z[2] = (int)c;
+ c >>= 32;
+ }
+ c += (z[3] & M) - 1;
+ z[3] = (int)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c += (z[4] & M);
+ z[4] = (int)c;
+ c >>= 32;
+ c += (z[5] & M);
+ z[5] = (int)c;
+ c >>= 32;
+ }
+ c += (z[6] & M) - 1;
+ z[6] = (int)c;
+ c >>= 32;
+ c += (z[7] & M) + 1;
+ z[7] = (int)c;
+// c >>= 32;
+ }
+
+ private static void subPInvFrom(int[] z)
+ {
+ long c = (z[0] & M) - 1;
+ z[0] = (int)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c += (z[1] & M);
+ z[1] = (int)c;
+ c >>= 32;
+ c += (z[2] & M);
+ z[2] = (int)c;
+ c >>= 32;
+ }
+ c += (z[3] & M) + 1;
+ z[3] = (int)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c += (z[4] & M);
+ z[4] = (int)c;
+ c >>= 32;
+ c += (z[5] & M);
+ z[5] = (int)c;
+ c >>= 32;
}
+ c += (z[6] & M) + 1;
+ z[6] = (int)c;
+ c >>= 32;
+ c += (z[7] & M) - 1;
+ z[7] = (int)c;
+// c >>= 32;
}
}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1FieldElement.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1FieldElement.java
index b01a20d6..084c21d4 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1FieldElement.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1FieldElement.java
@@ -162,7 +162,7 @@ public class SecP256R1FieldElement extends ECFieldElement
SecP256R1Field.squareN(t1, 94, t1);
SecP256R1Field.square(t1, t2);
- return Arrays.areEqual(x1, t2) ? new SecP256R1FieldElement(t1) : null;
+ return Nat256.eq(x1, t2) ? new SecP256R1FieldElement(t1) : null;
}
public boolean equals(Object other)
@@ -178,11 +178,11 @@ public class SecP256R1FieldElement extends ECFieldElement
}
SecP256R1FieldElement o = (SecP256R1FieldElement)other;
- return Arrays.areEqual(x, o.x);
+ return Nat256.eq(x, o.x);
}
public int hashCode()
{
- return Q.hashCode() ^ Arrays.hashCode(x);
+ return Q.hashCode() ^ Arrays.hashCode(x, 0, 8);
}
}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Point.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Point.java
index fe971c27..46683151 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Point.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Point.java
@@ -3,6 +3,7 @@ package org.bouncycastle.math.ec.custom.sec;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECFieldElement;
import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.ec.Nat;
public class SecP256R1Point extends ECPoint
{
@@ -90,8 +91,9 @@ public class SecP256R1Point extends ECPoint
SecP256R1FieldElement Z1 = (SecP256R1FieldElement)this.zs[0];
SecP256R1FieldElement Z2 = (SecP256R1FieldElement)b.getZCoord(0);
+ int c;
int[] tt1 = Nat256.createExt();
- int[] tt2 = Nat256.createExt();
+ int[] t2 = Nat256.create();
int[] t3 = Nat256.create();
int[] t4 = Nat256.create();
@@ -107,7 +109,7 @@ public class SecP256R1Point extends ECPoint
S2 = t3;
SecP256R1Field.square(Z1.x, S2);
- U2 = tt2;
+ U2 = t2;
SecP256R1Field.multiply(S2, X2.x, U2);
SecP256R1Field.multiply(S2, Z1.x, S2);
@@ -136,7 +138,7 @@ public class SecP256R1Point extends ECPoint
int[] H = Nat256.create();
SecP256R1Field.subtract(U1, U2, H);
- int[] R = tt2;
+ int[] R = t2;
SecP256R1Field.subtract(S1, S2, R);
// Check if b == this or b == -this
@@ -161,19 +163,20 @@ public class SecP256R1Point extends ECPoint
int[] V = t3;
SecP256R1Field.multiply(HSquared, U1, V);
+ SecP256R1Field.negate(G, G);
Nat256.mul(S1, G, tt1);
+ c = Nat256.addBothTo(V, V, G);
+ SecP256R1Field.reduce32(c, G);
+
SecP256R1FieldElement X3 = new SecP256R1FieldElement(t4);
SecP256R1Field.square(R, X3.x);
- SecP256R1Field.add(X3.x, G, X3.x);
- SecP256R1Field.subtract(X3.x, V, X3.x);
- SecP256R1Field.subtract(X3.x, V, X3.x);
+ SecP256R1Field.subtract(X3.x, G, X3.x);
SecP256R1FieldElement Y3 = new SecP256R1FieldElement(G);
SecP256R1Field.subtract(V, X3.x, Y3.x);
- Nat256.mul(Y3.x, R, tt2);
- SecP256R1Field.subtractExt(tt2, tt1, tt2);
- SecP256R1Field.reduce(tt2, Y3.x);
+ SecP256R1Field.multiplyAddToExt(Y3.x, R, tt1);
+ SecP256R1Field.reduce(tt1, Y3.x);
SecP256R1FieldElement Z3 = new SecP256R1FieldElement(H);
if (!Z1IsOne)
@@ -207,6 +210,7 @@ public class SecP256R1Point extends ECPoint
SecP256R1FieldElement X1 = (SecP256R1FieldElement)this.x, Z1 = (SecP256R1FieldElement)this.zs[0];
+ int c;
int[] t1 = Nat256.create();
int[] t2 = Nat256.create();
@@ -230,17 +234,16 @@ public class SecP256R1Point extends ECPoint
int[] M = t2;
SecP256R1Field.add(X1.x, Z1Squared, M);
SecP256R1Field.multiply(M, t1, M);
- SecP256R1Field.twice(M, t1);
- SecP256R1Field.add(M, t1, M);
+ c = Nat256.addBothTo(M, M, M);
+ SecP256R1Field.reduce32(c, M);
int[] S = Y1Squared;
SecP256R1Field.multiply(Y1Squared, X1.x, S);
- SecP256R1Field.twice(S, S);
- SecP256R1Field.twice(S, S);
+ c = Nat.shiftUpBits(8, S, 2, 0);
+ SecP256R1Field.reduce32(c, S);
- SecP256R1Field.twice(T, t1);
- SecP256R1Field.twice(t1, t1);
- SecP256R1Field.twice(t1, t1);
+ c = Nat.shiftUpBits(8, T, 3, 0, t1);
+ SecP256R1Field.reduce32(c, t1);
SecP256R1FieldElement X3 = new SecP256R1FieldElement(T);
SecP256R1Field.square(M, X3.x);
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Curve.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Curve.java
new file mode 100644
index 00000000..ad37b0cd
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Curve.java
@@ -0,0 +1,105 @@
+package org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECFieldElement;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.field.FiniteFields;
+import org.bouncycastle.util.encoders.Hex;
+
+public class SecP384R1Curve extends ECCurve
+{
+ public static final BigInteger q = new BigInteger(1,
+ Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF"));
+
+ private static final int SecP384R1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+ protected SecP384R1Point infinity;
+
+ public SecP384R1Curve()
+ {
+ super(FiniteFields.getPrimeField(q));
+
+ this.infinity = new SecP384R1Point(this, null, null);
+
+ this.a = fromBigInteger(new BigInteger(1,
+ Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC")));
+ this.b = fromBigInteger(new BigInteger(1,
+ Hex.decode("B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF")));
+ this.order = new BigInteger(1, Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973"));
+ this.cofactor = BigInteger.valueOf(1);
+
+ this.coord = SecP384R1_DEFAULT_COORDS;
+ }
+
+ protected ECCurve cloneCurve()
+ {
+ return new SecP384R1Curve();
+ }
+
+ public boolean supportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_JACOBIAN:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public BigInteger getQ()
+ {
+ return q;
+ }
+
+ public int getFieldSize()
+ {
+ return q.bitLength();
+ }
+
+ public ECFieldElement fromBigInteger(BigInteger x)
+ {
+ return new SecP384R1FieldElement(x);
+ }
+
+ protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)
+ {
+ return new SecP384R1Point(this, x, y, withCompression);
+ }
+
+ protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+ {
+ return new SecP384R1Point(this, x, y, zs, withCompression);
+ }
+
+ protected ECPoint decompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement x = fromBigInteger(X1);
+ ECFieldElement alpha = x.square().add(getA()).multiply(x).add(getB());
+ 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");
+ }
+
+ if (beta.testBitZero() != (yTilde == 1))
+ {
+ // Use the other root
+ beta = beta.negate();
+ }
+
+ return new SecP384R1Point(this, x, beta, true);
+ }
+
+ public ECPoint getInfinity()
+ {
+ return infinity;
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Field.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Field.java
new file mode 100644
index 00000000..82c9aa0a
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Field.java
@@ -0,0 +1,294 @@
+package org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.math.ec.Nat;
+
+public class SecP384R1Field
+{
+ private static final long M = 0xFFFFFFFFL;
+
+ // 2^384 - 2^128 - 2^96 + 2^32 - 1
+ static final int[] P = new int[]{ 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ static final int[] PExt = new int[]{ 0x00000001, 0xFFFFFFFE, 0x00000000, 0x00000002, 0x00000000, 0xFFFFFFFE,
+ 0x00000000, 0x00000002, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFE, 0x00000001, 0x00000000,
+ 0xFFFFFFFE, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ private static final int[] PExtInv = new int[]{ 0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0x00000001,
+ 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001, 0xFFFFFFFE, 0xFFFFFFFF,
+ 0x00000001, 0x00000002 };
+ private static final int P11 = 0xFFFFFFFF;
+ private static final int PExt23 = 0xFFFFFFFF;
+
+ public static void add(int[] x, int[] y, int[] z)
+ {
+ int c = Nat.add(12, x, y, z);
+ if (c != 0 || (z[11] == P11 && Nat.gte(12, z, P)))
+ {
+ addPInvTo(z);
+ }
+ }
+
+ public static void addExt(int[] xx, int[] yy, int[] zz)
+ {
+ int c = Nat.add(24, xx, yy, zz);
+ if (c != 0 || (zz[23] == PExt23 && Nat.gte(24, zz, PExt)))
+ {
+ if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0)
+ {
+ Nat.incAt(24, zz, PExtInv.length);
+ }
+ }
+ }
+
+ public static void addOne(int[] x, int[] z)
+ {
+ int c = Nat.inc(12, x, z);
+ if (c != 0 || (z[11] == P11 && Nat.gte(12, z, P)))
+ {
+ addPInvTo(z);
+ }
+ }
+
+ public static int[] fromBigInteger(BigInteger x)
+ {
+ int[] z = Nat.fromBigInteger(384, x);
+ if (z[11] == P11 && Nat.gte(12, z, P))
+ {
+ Nat.subFrom(12, P, z);
+ }
+ return z;
+ }
+
+ public static void half(int[] x, int[] z)
+ {
+ if ((x[0] & 1) == 0)
+ {
+ Nat.shiftDownBit(12, x, 0, z);
+ }
+ else
+ {
+ int c = Nat.add(12, x, P, z);
+ Nat.shiftDownBit(12, z, c);
+ }
+ }
+
+ public static void multiply(int[] x, int[] y, int[] z)
+ {
+ int[] tt = Nat.create(24);
+ Nat384.mul(x, y, tt);
+ reduce(tt, z);
+ }
+
+ public static void negate(int[] x, int[] z)
+ {
+ if (Nat.isZero(12, x))
+ {
+ Nat.zero(12, z);
+ }
+ else
+ {
+ Nat.sub(12, P, x, z);
+ }
+ }
+
+ public static void reduce(int[] xx, int[] z)
+ {
+ long xx16 = xx[16] & M, xx17 = xx[17] & M, xx18 = xx[18] & M, xx19 = xx[19] & M;
+ long xx20 = xx[20] & M, xx21 = xx[21] & M, xx22 = xx[22] & M, xx23 = xx[23] & M;
+
+ final long n = 1;
+
+ long t0 = (xx[12] & M) + xx20 - n;
+ long t1 = (xx[13] & M) + xx22;
+ long t2 = (xx[14] & M) + xx22 + xx23;
+ long t3 = (xx[15] & M) + xx23;
+ long t4 = xx17 + xx21;
+ long t5 = xx21 - xx23;
+ long t6 = xx22 - xx23;
+
+ long cc = 0;
+ cc += (xx[0] & M) + t0 + t5;
+ z[0] = (int)cc;
+ cc >>= 32;
+ cc += (xx[1] & M) + xx23 - t0 + t1;
+ z[1] = (int)cc;
+ cc >>= 32;
+ cc += (xx[2] & M) - xx21 - t1 + t2;
+ z[2] = (int)cc;
+ cc >>= 32;
+ cc += (xx[3] & M) + t0 - t2 + t3 + t5;
+ z[3] = (int)cc;
+ cc >>= 32;
+ cc += (xx[4] & M) + xx16 + xx21 + t0 + t1 - t3 + t5;
+ z[4] = (int)cc;
+ cc >>= 32;
+ cc += (xx[5] & M) - xx16 + t1 + t2 + t4;
+ z[5] = (int)cc;
+ cc >>= 32;
+ cc += (xx[6] & M) + xx18 - xx17 + t2 + t3;
+ z[6] = (int)cc;
+ cc >>= 32;
+ cc += (xx[7] & M) + xx16 + xx19 - xx18 + t3;
+ z[7] = (int)cc;
+ cc >>= 32;
+ cc += (xx[8] & M) + xx16 + xx17 + xx20 - xx19;
+ z[8] = (int)cc;
+ cc >>= 32;
+ cc += (xx[9] & M) + xx18 - xx20 + t4;
+ z[9] = (int)cc;
+ cc >>= 32;
+ cc += (xx[10] & M) + xx18 + xx19 - t5 + t6;
+ z[10] = (int)cc;
+ cc >>= 32;
+ cc += (xx[11] & M) + xx19 + xx20 - t6;
+ z[11] = (int)cc;
+ cc >>= 32;
+ cc += n;
+
+// assert cc >= 0;
+
+ reduce32((int)cc, z);
+ }
+
+ public static void reduce32(int x, int[] z)
+ {
+ long cc = 0;
+
+ if (x != 0)
+ {
+ long xx12 = x & M;
+
+ cc += (z[0] & M) + xx12;
+ z[0] = (int)cc;
+ cc >>= 32;
+ cc += (z[1] & M) - xx12;
+ z[1] = (int)cc;
+ cc >>= 32;
+ if (cc != 0)
+ {
+ cc += (z[2] & M);
+ z[2] = (int)cc;
+ cc >>= 32;
+ }
+ cc += (z[3] & M) + xx12;
+ z[3] = (int)cc;
+ cc >>= 32;
+ cc += (z[4] & M) + xx12;
+ z[4] = (int)cc;
+ cc >>= 32;
+
+// assert cc == 0 || cc == 1;
+ }
+
+ if ((cc != 0 && Nat.incAt(12, z, 5) != 0)
+ || (z[11] == P11 && Nat.gte(12, z, P)))
+ {
+ addPInvTo(z);
+ }
+ }
+
+ public static void square(int[] x, int[] z)
+ {
+ int[] tt = Nat.create(24);
+ Nat384.square(x, tt);
+ reduce(tt, z);
+ }
+
+ public static void squareN(int[] x, int n, int[] z)
+ {
+// assert n > 0;
+
+ int[] tt = Nat.create(24);
+ Nat384.square(x, tt);
+ reduce(tt, z);
+
+ while (--n > 0)
+ {
+ Nat384.square(z, tt);
+ reduce(tt, z);
+ }
+ }
+
+ public static void subtract(int[] x, int[] y, int[] z)
+ {
+ int c = Nat.sub(12, x, y, z);
+ if (c != 0)
+ {
+ subPInvFrom(z);
+ }
+ }
+
+ public static void subtractExt(int[] xx, int[] yy, int[] zz)
+ {
+ int c = Nat.sub(24, xx, yy, zz);
+ if (c != 0)
+ {
+ if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0)
+ {
+ Nat.decAt(24, zz, PExtInv.length);
+ }
+ }
+ }
+
+ public static void twice(int[] x, int[] z)
+ {
+ int c = Nat.shiftUpBit(12, x, 0, z);
+ if (c != 0 || (z[11] == P11 && Nat.gte(12, z, P)))
+ {
+ addPInvTo(z);
+ }
+ }
+
+ private static void addPInvTo(int[] z)
+ {
+ long c = (z[0] & M) + 1;
+ z[0] = (int)c;
+ c >>= 32;
+ c += (z[1] & M) - 1;
+ z[1] = (int)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c += (z[2] & M);
+ z[2] = (int)c;
+ c >>= 32;
+ }
+ c += (z[3] & M) + 1;
+ z[3] = (int)c;
+ c >>= 32;
+ c += (z[4] & M) + 1;
+ z[4] = (int)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ Nat.incAt(12, z, 5);
+ }
+ }
+
+ private static void subPInvFrom(int[] z)
+ {
+ long c = (z[0] & M) - 1;
+ z[0] = (int)c;
+ c >>= 32;
+ c += (z[1] & M) + 1;
+ z[1] = (int)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c += (z[2] & M);
+ z[2] = (int)c;
+ c >>= 32;
+ }
+ c += (z[3] & M) - 1;
+ z[3] = (int)c;
+ c >>= 32;
+ c += (z[4] & M) - 1;
+ z[4] = (int)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ Nat.decAt(12, z, 5);
+ }
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1FieldElement.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1FieldElement.java
new file mode 100644
index 00000000..b1023190
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1FieldElement.java
@@ -0,0 +1,211 @@
+package org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.math.ec.ECFieldElement;
+import org.bouncycastle.math.ec.Mod;
+import org.bouncycastle.math.ec.Nat;
+import org.bouncycastle.util.Arrays;
+
+public class SecP384R1FieldElement extends ECFieldElement
+{
+ public static final BigInteger Q = SecP384R1Curve.q;
+
+ protected int[] x;
+
+ public SecP384R1FieldElement(BigInteger x)
+ {
+ if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0)
+ {
+ throw new IllegalArgumentException("x value invalid for SecP384R1FieldElement");
+ }
+
+ this.x = SecP384R1Field.fromBigInteger(x);
+ }
+
+ public SecP384R1FieldElement()
+ {
+ this.x = Nat.create(12);
+ }
+
+ protected SecP384R1FieldElement(int[] x)
+ {
+ this.x = x;
+ }
+
+ public boolean isZero()
+ {
+ return Nat.isZero(12, x);
+ }
+
+ public boolean isOne()
+ {
+ return Nat.isOne(12, x);
+ }
+
+ public boolean testBitZero()
+ {
+ return Nat.getBit(x, 0) == 1;
+ }
+
+ public BigInteger toBigInteger()
+ {
+ return Nat.toBigInteger(12, x);
+ }
+
+ public String getFieldName()
+ {
+ return "SecP384R1Field";
+ }
+
+ public int getFieldSize()
+ {
+ return Q.bitLength();
+ }
+
+ public ECFieldElement add(ECFieldElement b)
+ {
+ int[] z = Nat.create(12);
+ SecP384R1Field.add(x, ((SecP384R1FieldElement)b).x, z);
+ return new SecP384R1FieldElement(z);
+ }
+
+ public ECFieldElement addOne()
+ {
+ int[] z = Nat.create(12);
+ SecP384R1Field.addOne(x, z);
+ return new SecP384R1FieldElement(z);
+ }
+
+ public ECFieldElement subtract(ECFieldElement b)
+ {
+ int[] z = Nat.create(12);
+ SecP384R1Field.subtract(x, ((SecP384R1FieldElement)b).x, z);
+ return new SecP384R1FieldElement(z);
+ }
+
+ public ECFieldElement multiply(ECFieldElement b)
+ {
+ int[] z = Nat.create(12);
+ SecP384R1Field.multiply(x, ((SecP384R1FieldElement)b).x, z);
+ return new SecP384R1FieldElement(z);
+ }
+
+ public ECFieldElement divide(ECFieldElement b)
+ {
+// return multiply(b.invert());
+ int[] z = Nat.create(12);
+ Mod.invert(SecP384R1Field.P, ((SecP384R1FieldElement)b).x, z);
+ SecP384R1Field.multiply(z, x, z);
+ return new SecP384R1FieldElement(z);
+ }
+
+ public ECFieldElement negate()
+ {
+ int[] z = Nat.create(12);
+ SecP384R1Field.negate(x, z);
+ return new SecP384R1FieldElement(z);
+ }
+
+ public ECFieldElement square()
+ {
+ int[] z = Nat.create(12);
+ SecP384R1Field.square(x, z);
+ return new SecP384R1FieldElement(z);
+ }
+
+ public ECFieldElement invert()
+ {
+// return new SecP384R1FieldElement(toBigInteger().modInverse(Q));
+ int[] z = Nat.create(12);
+ Mod.invert(SecP384R1Field.P, x, z);
+ return new SecP384R1FieldElement(z);
+ }
+
+ /**
+ * return a sqrt root - the routine verifies that the calculation returns the right value - if
+ * none exists it returns null.
+ */
+ public ECFieldElement sqrt()
+ {
+ // Raise this element to the exponent 2^382 - 2^126 - 2^94 + 2^30
+
+ int[] x1 = this.x;
+ if (Nat.isZero(12, x1) || Nat.isOne(12, x1))
+ {
+ return this;
+ }
+
+ int[] t1 = Nat.create(12);
+ int[] t2 = Nat.create(12);
+ int[] t3 = Nat.create(12);
+ int[] t4 = Nat.create(12);
+
+ SecP384R1Field.square(x1, t1);
+ SecP384R1Field.multiply(t1, x1, t1);
+
+ SecP384R1Field.squareN(t1, 2, t2);
+ SecP384R1Field.multiply(t2, t1, t2);
+
+ SecP384R1Field.square(t2, t2);
+ SecP384R1Field.multiply(t2, x1, t2);
+
+ SecP384R1Field.squareN(t2, 5, t3);
+ SecP384R1Field.multiply(t3, t2, t3);
+
+ SecP384R1Field.squareN(t3, 5, t4);
+ SecP384R1Field.multiply(t4, t2, t4);
+
+ SecP384R1Field.squareN(t4, 15, t2);
+ SecP384R1Field.multiply(t2, t4, t2);
+
+ SecP384R1Field.squareN(t2, 2, t3);
+ SecP384R1Field.multiply(t1, t3, t1);
+
+ SecP384R1Field.squareN(t3, 28, t3);
+ SecP384R1Field.multiply(t2, t3, t2);
+
+ SecP384R1Field.squareN(t2, 60, t3);
+ SecP384R1Field.multiply(t3, t2, t3);
+
+ int[] r = t2;
+
+ SecP384R1Field.squareN(t3, 120, r);
+ SecP384R1Field.multiply(r, t3, r);
+
+ SecP384R1Field.squareN(r, 15, r);
+ SecP384R1Field.multiply(r, t4, r);
+
+ SecP384R1Field.squareN(r, 33, r);
+ SecP384R1Field.multiply(r, t1, r);
+
+ SecP384R1Field.squareN(r, 64, r);
+ SecP384R1Field.multiply(r, x1, r);
+
+ SecP384R1Field.squareN(r, 30, t1);
+ SecP384R1Field.square(t1, t2);
+
+ return Nat.eq(12, x1, t2) ? new SecP384R1FieldElement(t1) : null;
+ }
+
+ public boolean equals(Object other)
+ {
+ if (other == this)
+ {
+ return true;
+ }
+
+ if (!(other instanceof SecP384R1FieldElement))
+ {
+ return false;
+ }
+
+ SecP384R1FieldElement o = (SecP384R1FieldElement)other;
+ return Nat.eq(12, x, o.x);
+ }
+
+ public int hashCode()
+ {
+ return Q.hashCode() ^ Arrays.hashCode(x, 0, 12);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Point.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Point.java
new file mode 100644
index 00000000..f1d79303
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Point.java
@@ -0,0 +1,324 @@
+package org.bouncycastle.math.ec.custom.sec;
+
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECFieldElement;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.ec.Nat;
+
+public class SecP384R1Point 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
+ *
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecP384R1Point(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
+ *
+ * @deprecated per-point compression property will be removed, refer
+ * {@link #getEncoded(boolean)}
+ */
+ public SecP384R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
+ {
+ super(curve, x, y);
+
+ if ((x == null) != (y == null))
+ {
+ throw new IllegalArgumentException("Exactly one of the field elements is null");
+ }
+
+ this.withCompression = withCompression;
+ }
+
+ SecP384R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+ {
+ super(curve, x, y, zs);
+
+ this.withCompression = withCompression;
+ }
+
+ protected ECPoint detach()
+ {
+ return new SecP384R1Point(null, getAffineXCoord(), getAffineYCoord());
+ }
+
+ protected boolean getCompressionYTilde()
+ {
+ return this.getAffineYCoord().testBitZero();
+ }
+
+ public ECPoint add(ECPoint b)
+ {
+ if (this.isInfinity())
+ {
+ return b;
+ }
+ if (b.isInfinity())
+ {
+ return this;
+ }
+ if (this == b)
+ {
+ return twice();
+ }
+
+ ECCurve curve = this.getCurve();
+
+ SecP384R1FieldElement X1 = (SecP384R1FieldElement)this.x, Y1 = (SecP384R1FieldElement)this.y;
+ SecP384R1FieldElement X2 = (SecP384R1FieldElement)b.getXCoord(), Y2 = (SecP384R1FieldElement)b.getYCoord();
+
+ SecP384R1FieldElement Z1 = (SecP384R1FieldElement)this.zs[0];
+ SecP384R1FieldElement Z2 = (SecP384R1FieldElement)b.getZCoord(0);
+
+ int c;
+ int[] tt1 = Nat.create(24);
+ int[] tt2 = Nat.create(24);
+ int[] t3 = Nat.create(12);
+ int[] t4 = Nat.create(12);
+
+ boolean Z1IsOne = Z1.isOne();
+ int[] U2, S2;
+ if (Z1IsOne)
+ {
+ U2 = X2.x;
+ S2 = Y2.x;
+ }
+ else
+ {
+ S2 = t3;
+ SecP384R1Field.square(Z1.x, S2);
+
+ U2 = tt2;
+ SecP384R1Field.multiply(S2, X2.x, U2);
+
+ SecP384R1Field.multiply(S2, Z1.x, S2);
+ SecP384R1Field.multiply(S2, Y2.x, S2);
+ }
+
+ boolean Z2IsOne = Z2.isOne();
+ int[] U1, S1;
+ if (Z2IsOne)
+ {
+ U1 = X1.x;
+ S1 = Y1.x;
+ }
+ else
+ {
+ S1 = t4;
+ SecP384R1Field.square(Z2.x, S1);
+
+ U1 = tt1;
+ SecP384R1Field.multiply(S1, X1.x, U1);
+
+ SecP384R1Field.multiply(S1, Z2.x, S1);
+ SecP384R1Field.multiply(S1, Y1.x, S1);
+ }
+
+ int[] H = Nat.create(12);
+ SecP384R1Field.subtract(U1, U2, H);
+
+ int[] R = Nat.create(12);
+ SecP384R1Field.subtract(S1, S2, R);
+
+ // Check if b == this or b == -this
+ if (Nat.isZero(12, H))
+ {
+ if (Nat.isZero(12, R))
+ {
+ // this == b, i.e. this must be doubled
+ return this.twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return curve.getInfinity();
+ }
+
+ int[] HSquared = t3;
+ SecP384R1Field.square(H, HSquared);
+
+ int[] G = Nat.create(12);
+ SecP384R1Field.multiply(HSquared, H, G);
+
+ int[] V = t3;
+ SecP384R1Field.multiply(HSquared, U1, V);
+
+ SecP384R1Field.negate(G, G);
+ Nat384.mul(S1, G, tt1);
+
+ c = Nat.addBothTo(12, V, V, G);
+ SecP384R1Field.reduce32(c, G);
+
+ SecP384R1FieldElement X3 = new SecP384R1FieldElement(t4);
+ SecP384R1Field.square(R, X3.x);
+ SecP384R1Field.subtract(X3.x, G, X3.x);
+
+ SecP384R1FieldElement Y3 = new SecP384R1FieldElement(G);
+ SecP384R1Field.subtract(V, X3.x, Y3.x);
+ Nat384.mul(Y3.x, R, tt2);
+ SecP384R1Field.addExt(tt1, tt2, tt1);
+ SecP384R1Field.reduce(tt1, Y3.x);
+
+ SecP384R1FieldElement Z3 = new SecP384R1FieldElement(H);
+ if (!Z1IsOne)
+ {
+ SecP384R1Field.multiply(Z3.x, Z1.x, Z3.x);
+ }
+ if (!Z2IsOne)
+ {
+ SecP384R1Field.multiply(Z3.x, Z2.x, Z3.x);
+ }
+
+ ECFieldElement[] zs = new ECFieldElement[]{ Z3 };
+
+ return new SecP384R1Point(curve, X3, Y3, zs, this.withCompression);
+ }
+
+ public ECPoint twice()
+ {
+ if (this.isInfinity())
+ {
+ return this;
+ }
+
+ ECCurve curve = this.getCurve();
+
+ SecP384R1FieldElement Y1 = (SecP384R1FieldElement)this.y;
+ if (Y1.isZero())
+ {
+ return curve.getInfinity();
+ }
+
+ SecP384R1FieldElement X1 = (SecP384R1FieldElement)this.x, Z1 = (SecP384R1FieldElement)this.zs[0];
+
+ int c;
+ int[] t1 = Nat.create(12);
+ int[] t2 = Nat.create(12);
+
+ int[] Y1Squared = Nat.create(12);
+ SecP384R1Field.square(Y1.x, Y1Squared);
+
+ int[] T = Nat.create(12);
+ SecP384R1Field.square(Y1Squared, T);
+
+ boolean Z1IsOne = Z1.isOne();
+
+ int[] Z1Squared = Z1.x;
+ if (!Z1IsOne)
+ {
+ Z1Squared = t2;
+ SecP384R1Field.square(Z1.x, Z1Squared);
+ }
+
+ SecP384R1Field.subtract(X1.x, Z1Squared, t1);
+
+ int[] M = t2;
+ SecP384R1Field.add(X1.x, Z1Squared, M);
+ SecP384R1Field.multiply(M, t1, M);
+ c = Nat.addBothTo(12, M, M, M);
+ SecP384R1Field.reduce32(c, M);
+
+ int[] S = Y1Squared;
+ SecP384R1Field.multiply(Y1Squared, X1.x, S);
+ c = Nat.shiftUpBits(12, S, 2, 0);
+ SecP384R1Field.reduce32(c, S);
+
+ c = Nat.shiftUpBits(12, T, 3, 0, t1);
+ SecP384R1Field.reduce32(c, t1);
+
+ SecP384R1FieldElement X3 = new SecP384R1FieldElement(T);
+ SecP384R1Field.square(M, X3.x);
+ SecP384R1Field.subtract(X3.x, S, X3.x);
+ SecP384R1Field.subtract(X3.x, S, X3.x);
+
+ SecP384R1FieldElement Y3 = new SecP384R1FieldElement(S);
+ SecP384R1Field.subtract(S, X3.x, Y3.x);
+ SecP384R1Field.multiply(Y3.x, M, Y3.x);
+ SecP384R1Field.subtract(Y3.x, t1, Y3.x);
+
+ SecP384R1FieldElement Z3 = new SecP384R1FieldElement(M);
+ SecP384R1Field.twice(Y1.x, Z3.x);
+ if (!Z1IsOne)
+ {
+ SecP384R1Field.multiply(Z3.x, Z1.x, Z3.x);
+ }
+
+ return new SecP384R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression);
+ }
+
+ public ECPoint twicePlus(ECPoint b)
+ {
+ if (this == b)
+ {
+ return threeTimes();
+ }
+ if (this.isInfinity())
+ {
+ return b;
+ }
+ if (b.isInfinity())
+ {
+ return twice();
+ }
+
+ ECFieldElement Y1 = this.y;
+ if (Y1.isZero())
+ {
+ return b;
+ }
+
+ return twice().add(b);
+ }
+
+ public ECPoint threeTimes()
+ {
+ if (this.isInfinity() || this.y.isZero())
+ {
+ return this;
+ }
+
+ // NOTE: Be careful about recursions between twicePlus and threeTimes
+ return twice().add(this);
+ }
+
+ public ECPoint subtract(ECPoint b)
+ {
+ if (b.isInfinity())
+ {
+ return this;
+ }
+
+ // Add -b
+ return add(b.negate());
+ }
+
+ public ECPoint negate()
+ {
+ if (this.isInfinity())
+ {
+ return this;
+ }
+
+ return new SecP384R1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Curve.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Curve.java
index b58e34b7..ea42b578 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Curve.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Curve.java
@@ -69,6 +69,11 @@ public class SecP521R1Curve extends ECCurve
return new SecP521R1Point(this, x, y, withCompression);
}
+ protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+ {
+ return new SecP521R1Point(this, x, y, zs, withCompression);
+ }
+
protected ECPoint decompressPoint(int yTilde, BigInteger X1)
{
ECFieldElement x = fromBigInteger(X1);
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Field.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Field.java
index 2d3c6ffa..33f4a342 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Field.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Field.java
@@ -16,7 +16,7 @@ public class SecP521R1Field
int c = Nat.add(16, x, y, z) + x[16] + y[16];
if (c > P16 || (c == P16 && Nat.eq(16, z, P)))
{
- c += Nat.inc(16, z, 0);
+ c += Nat.inc(16, z);
c &= P16;
}
z[16] = c;
@@ -24,11 +24,10 @@ public class SecP521R1Field
public static void addOne(int[] x, int[] z)
{
- System.arraycopy(x, 0, z, 0, 16);
- int c = Nat.inc(16, z, 0) + x[16];
+ int c = Nat.inc(16, x, z) + x[16];
if (c > P16 || (c == P16 && Nat.eq(16, z, P)))
{
- c += Nat.inc(16, z, 0);
+ c += Nat.inc(16, z);
c &= P16;
}
z[16] = c;
@@ -75,12 +74,12 @@ public class SecP521R1Field
// assert xx[32] >>> 18 == 0;
int xx32 = xx[32];
- int c = Nat.shiftDownBits(16, xx, 16, 9, xx32, z) >>> 23;
+ int c = Nat.shiftDownBits(16, xx, 16, 9, xx32, z, 0) >>> 23;
c += xx32 >>> 9;
- c += Nat.add(16, z, xx, z);
+ c += Nat.addTo(16, xx, z);
if (c > P16 || (c == P16 && Nat.eq(16, z, P)))
{
- c += Nat.inc(16, z, 0);
+ c += Nat.inc(16, z);
c &= P16;
}
z[16] = c;
@@ -89,10 +88,10 @@ public class SecP521R1Field
public static void reduce23(int[] z)
{
int z16 = z[16];
- int c = Nat.addWord(16, z16 >>> 9, z) + (z16 & P16);
+ int c = Nat.addWordTo(16, z16 >>> 9, z) + (z16 & P16);
if (c > P16 || (c == P16 && Nat.eq(16, z, P)))
{
- c += Nat.inc(16, z, 0);
+ c += Nat.inc(16, z);
c &= P16;
}
z[16] = c;
@@ -125,7 +124,7 @@ public class SecP521R1Field
int c = Nat.sub(16, x, y, z) + x[16] - y[16];
if (c < 0)
{
- c += Nat.dec(16, z, 0);
+ c += Nat.dec(16, z);
c &= P16;
}
z[16] = c;
@@ -133,13 +132,9 @@ public class SecP521R1Field
public static void twice(int[] x, int[] z)
{
- int c = Nat.shiftUpBit(16, x, 0, z) | (x[16] << 1);
- if (c > P16 || (c == P16 && Nat.eq(16, z, P)))
- {
- c += Nat.inc(16, z, 0);
- c &= P16;
- }
- z[16] = c;
+ int x16 = x[16];
+ int c = Nat.shiftUpBit(16, x, x16 << 23, z) | (x16 << 1);
+ z[16] = c & P16;
}
protected static void implMultiply(int[] x, int[] y, int[] zz)
@@ -155,6 +150,6 @@ public class SecP521R1Field
Nat512.square(x, zz);
int x16 = x[16];
- zz[32] = Nat.mulWordAdd(16, x16 << 1, x, zz, 16) + (x16 * x16);
+ zz[32] = Nat.mulWordAddTo(16, x16 << 1, x, 0, zz, 16) + (x16 * x16);
}
}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1FieldElement.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1FieldElement.java
index 0a395a76..785abaa1 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1FieldElement.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1FieldElement.java
@@ -143,7 +143,7 @@ public class SecP521R1FieldElement extends ECFieldElement
SecP521R1Field.squareN(x1, 519, t1);
SecP521R1Field.square(t1, t2);
- return Arrays.areEqual(x1, t2) ? new SecP521R1FieldElement(t1) : null;
+ return Nat.eq(17, x1, t2) ? new SecP521R1FieldElement(t1) : null;
}
public boolean equals(Object other)
@@ -159,11 +159,11 @@ public class SecP521R1FieldElement extends ECFieldElement
}
SecP521R1FieldElement o = (SecP521R1FieldElement)other;
- return Arrays.areEqual(x, o.x);
+ return Nat.eq(17, x, o.x);
}
public int hashCode()
{
- return Q.hashCode() ^ Arrays.hashCode(x);
+ return Q.hashCode() ^ Arrays.hashCode(x, 0, 17);
}
}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Point.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Point.java
index 4b4e5b3b..12fcecda 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Point.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Point.java
@@ -230,8 +230,8 @@ public class SecP521R1Point extends ECPoint
int[] M = t2;
SecP521R1Field.add(X1.x, Z1Squared, M);
SecP521R1Field.multiply(M, t1, M);
- SecP521R1Field.twice(M, t1);
- SecP521R1Field.add(M, t1, M);
+ Nat.addBothTo(17, M, M, M);
+ SecP521R1Field.reduce23(M);
int[] S = Y1Squared;
SecP521R1Field.multiply(Y1Squared, X1.x, S);
diff --git a/core/src/main/java/org/bouncycastle/math/ec/endo/ECEndomorphism.java b/core/src/main/java/org/bouncycastle/math/ec/endo/ECEndomorphism.java
new file mode 100644
index 00000000..2be0c01d
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/endo/ECEndomorphism.java
@@ -0,0 +1,10 @@
+package org.bouncycastle.math.ec.endo;
+
+import org.bouncycastle.math.ec.ECPointMap;
+
+public interface ECEndomorphism
+{
+ ECPointMap getPointMap();
+
+ boolean hasEfficientPointMap();
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/endo/GLVEndomorphism.java b/core/src/main/java/org/bouncycastle/math/ec/endo/GLVEndomorphism.java
new file mode 100644
index 00000000..8897bb38
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/endo/GLVEndomorphism.java
@@ -0,0 +1,8 @@
+package org.bouncycastle.math.ec.endo;
+
+import java.math.BigInteger;
+
+public interface GLVEndomorphism extends ECEndomorphism
+{
+ BigInteger[] decomposeScalar(BigInteger k);
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/endo/GLVTypeBEndomorphism.java b/core/src/main/java/org/bouncycastle/math/ec/endo/GLVTypeBEndomorphism.java
new file mode 100644
index 00000000..ab710d1a
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/endo/GLVTypeBEndomorphism.java
@@ -0,0 +1,58 @@
+package org.bouncycastle.math.ec.endo;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.math.ec.ECConstants;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPointMap;
+import org.bouncycastle.math.ec.ScaleXPointMap;
+
+public class GLVTypeBEndomorphism implements GLVEndomorphism
+{
+ protected final ECCurve curve;
+ protected final GLVTypeBParameters parameters;
+ protected final ECPointMap pointMap;
+
+ public GLVTypeBEndomorphism(ECCurve curve, GLVTypeBParameters parameters)
+ {
+ this.curve = curve;
+ this.parameters = parameters;
+ this.pointMap = new ScaleXPointMap(curve.fromBigInteger(parameters.getBeta()));
+ }
+
+ public BigInteger[] decomposeScalar(BigInteger k)
+ {
+ int bits = parameters.getBits();
+ BigInteger b1 = calculateB(k, parameters.getG1(), bits);
+ BigInteger b2 = calculateB(k, parameters.getG2(), bits);
+
+ BigInteger[] v1 = parameters.getV1(), v2 = parameters.getV2();
+ BigInteger a = k.subtract((b1.multiply(v1[0])).add(b2.multiply(v2[0])));
+ BigInteger b = (b1.multiply(v1[1])).add(b2.multiply(v2[1])).negate();
+
+ return new BigInteger[]{ a, b };
+ }
+
+ public ECPointMap getPointMap()
+ {
+ return pointMap;
+ }
+
+ public boolean hasEfficientPointMap()
+ {
+ return true;
+ }
+
+ protected BigInteger calculateB(BigInteger k, BigInteger g, int t)
+ {
+ boolean negative = (g.signum() < 0);
+ BigInteger b = k.multiply(g.abs());
+ boolean extra = b.testBit(t - 1);
+ b = b.shiftRight(t);
+ if (extra)
+ {
+ b = b.add(ECConstants.ONE);
+ }
+ return negative ? b.negate() : b;
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/endo/GLVTypeBParameters.java b/core/src/main/java/org/bouncycastle/math/ec/endo/GLVTypeBParameters.java
new file mode 100644
index 00000000..f02a882f
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/endo/GLVTypeBParameters.java
@@ -0,0 +1,59 @@
+package org.bouncycastle.math.ec.endo;
+
+import java.math.BigInteger;
+
+public class GLVTypeBParameters
+{
+ protected final BigInteger beta;
+ protected final BigInteger lambda;
+ protected final BigInteger[] v1, v2;
+ protected final BigInteger g1, g2;
+ protected final int bits;
+
+ public GLVTypeBParameters(BigInteger beta, BigInteger lambda, BigInteger[] v1, BigInteger[] v2, BigInteger g1,
+ BigInteger g2, int bits)
+ {
+ this.beta = beta;
+ this.lambda = lambda;
+ this.v1 = v1;
+ this.v2 = v2;
+ this.g1 = g1;
+ this.g2 = g2;
+ this.bits = bits;
+ }
+
+ public BigInteger getBeta()
+ {
+ return beta;
+ }
+
+ public BigInteger getLambda()
+ {
+ return lambda;
+ }
+
+ public BigInteger[] getV1()
+ {
+ return v1;
+ }
+
+ public BigInteger[] getV2()
+ {
+ return v2;
+ }
+
+ public BigInteger getG1()
+ {
+ return g1;
+ }
+
+ public BigInteger getG2()
+ {
+ return g2;
+ }
+
+ public int getBits()
+ {
+ return bits;
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/tools/DiscoverEndomorphisms.java b/core/src/main/java/org/bouncycastle/math/ec/tools/DiscoverEndomorphisms.java
new file mode 100644
index 00000000..3b332978
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/tools/DiscoverEndomorphisms.java
@@ -0,0 +1,373 @@
+package org.bouncycastle.math.ec.tools;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bouncycastle.asn1.x9.ECNamedCurveTable;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.math.ec.ECAlgorithms;
+import org.bouncycastle.math.ec.ECConstants;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECFieldElement;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.util.BigIntegers;
+
+public class DiscoverEndomorphisms
+{
+ private static final int radix = 16;
+
+ public static void main(String[] args)
+ {
+ if (args.length < 1)
+ {
+ System.err.println("Expected a list of curve names as arguments");
+ return;
+ }
+
+ for (int i = 0; i < args.length; ++i)
+ {
+ discoverEndomorphism(args[i]);
+ }
+ }
+
+ private static void discoverEndomorphism(String curveName)
+ {
+ X9ECParameters x9 = ECNamedCurveTable.getByName(curveName);
+ if (x9 == null)
+ {
+ System.err.println("Unknown curve: " + curveName);
+ return;
+ }
+
+ ECCurve c = x9.getCurve();
+ if (ECAlgorithms.isFpCurve(c))
+ {
+ BigInteger characteristic = c.getField().getCharacteristic();
+
+ if (c.getA().isZero() && characteristic.mod(ECConstants.THREE).equals(ECConstants.ONE))
+ {
+ System.out.println("Curve '" + curveName + "' has a 'GLV Type B' endomorphism with these parameters: ");
+ printGLVTypeBParameters(x9);
+ }
+ }
+ }
+
+ private static void printGLVTypeBParameters(X9ECParameters x9)
+ {
+ BigInteger n = x9.getN();
+ BigInteger[] v1 = null;
+ BigInteger[] v2 = null;
+
+ // x^2 + x + 1 = 0 mod n
+ BigInteger lambda = solveQuadraticEquation(n, ECConstants.ONE, ECConstants.ONE);
+
+ BigInteger[] rt = extEuclidGLV(n, lambda);
+ v1 = new BigInteger[]{ rt[2], rt[3].negate() };
+ v2 = chooseShortest(new BigInteger[]{ rt[0], rt[1].negate() }, new BigInteger[]{ rt[4], rt[5].negate() });
+
+ /*
+ * If elements of v2 are not bounded by sqrt(n), then if r1/t1 are relatively prime there
+ * _may_ yet be a GLV generator, so search for it. See
+ * "Integer Decomposition for Fast Scalar Multiplication on Elliptic Curves", D. Kim, S. Lim
+ * (SAC 2002)
+ */
+ if (!isVectorBoundedBySqrt(v2, n) && areRelativelyPrime(v1[0], v1[1]))
+ {
+ BigInteger r = v1[0], t = v1[1], s = r.add(t.multiply(lambda)).divide(n);
+
+ BigInteger[] vw = extEuclidBezout(new BigInteger[]{ s.abs(), t.abs() });
+ BigInteger v = vw[0], w = vw[1];
+
+ if (s.signum() < 0)
+ {
+ v = v.negate();
+ }
+ if (t.signum() > 0)
+ {
+ w = w.negate();
+ }
+
+ BigInteger check = s.multiply(v).subtract(t.multiply(w));
+ if (!check.equals(ECConstants.ONE))
+ {
+ throw new IllegalStateException();
+ }
+
+ BigInteger x = w.multiply(n).subtract(v.multiply(lambda));
+
+ BigInteger base1 = v.negate();
+ BigInteger base2 = x.negate();
+
+ /*
+ * We calculate the range(s) conservatively large to avoid messy rounding issues, so
+ * there may be spurious candidate generators, but we won't miss any.
+ */
+ BigInteger sqrtN = isqrt(n.subtract(ECConstants.ONE)).add(ECConstants.ONE);
+
+ BigInteger[] I1 = calculateRange(base1, sqrtN, t);
+ BigInteger[] I2 = calculateRange(base2, sqrtN, r);
+
+ BigInteger[] range = intersect(I1, I2);
+ if (range != null)
+ {
+ for (BigInteger alpha = range[0]; alpha.compareTo(range[1]) <= 0; alpha = alpha.add(ECConstants.ONE))
+ {
+ BigInteger[] candidate = new BigInteger[]{ x.add(alpha.multiply(r)), v.add(alpha.multiply(t)) };
+ if (isShorter(candidate, v2))
+ {
+ v2 = candidate;
+ }
+ }
+ }
+ }
+
+ /*
+ * 'Beta' is a field element of order 3. There are only two such values besides 1; determine which of them
+ * corresponds to our choice for 'Lambda'.
+ */
+ ECFieldElement beta;
+ {
+ ECPoint G = x9.getG().normalize();
+ ECPoint mapG = G.multiply(lambda).normalize();
+ if (!G.getYCoord().equals(mapG.getYCoord()))
+ {
+ throw new IllegalStateException("Derivation of GLV Type B parameters failed unexpectedly");
+ }
+
+ BigInteger q = x9.getCurve().getField().getCharacteristic();
+ BigInteger e = q.divide(ECConstants.THREE);
+
+ SecureRandom random = new SecureRandom();
+ BigInteger b;
+ do
+ {
+ BigInteger r = BigIntegers.createRandomInRange(ECConstants.TWO, q.subtract(ECConstants.TWO), random);
+ b = r.modPow(e, q);
+ }
+ while (b.equals(ECConstants.ONE));
+
+ beta = x9.getCurve().fromBigInteger(ECConstants.TWO.modPow(e, q));
+
+ if (!G.getXCoord().multiply(beta).equals(mapG.getXCoord()))
+ {
+ beta = beta.square();
+ if (!G.getXCoord().multiply(beta).equals(mapG.getXCoord()))
+ {
+ throw new IllegalStateException("Derivation of GLV Type B parameters failed unexpectedly");
+ }
+ }
+ }
+
+ /*
+ * These parameters are used to avoid division when decomposing the scalar in a GLV point multiplication
+ */
+ BigInteger d = (v1[0].multiply(v2[1])).subtract(v1[1].multiply(v2[0]));
+
+ int bits = n.bitLength() + 2;
+ BigInteger g1 = roundQuotient(v2[1].shiftLeft(bits), d);
+ BigInteger g2 = roundQuotient(v1[1].shiftLeft(bits), d).negate();
+
+ printProperty("Beta", beta.toBigInteger().toString(radix));
+ printProperty("Lambda", lambda.toString(radix));
+ printProperty("v1", "{ " + v1[0].toString(radix) + ", " + v1[1].toString(radix) + " }");
+ printProperty("v2", "{ " + v2[0].toString(radix) + ", " + v2[1].toString(radix) + " }");
+ printProperty("(OPT) g1", g1.toString(radix));
+ printProperty("(OPT) g2", g2.toString(radix));
+ printProperty("(OPT) bits", bits);
+ }
+
+ private static void printProperty(String name, Object value)
+ {
+ StringBuffer sb = new StringBuffer(" ");
+ sb.append(name);
+ while (sb.length() < 20)
+ {
+ sb.append(' ');
+ }
+ sb.append("= ");
+ sb.append(value.toString());
+ System.out.println(sb.toString());
+ }
+
+ private static boolean areRelativelyPrime(BigInteger a, BigInteger b)
+ {
+ return a.gcd(b).equals(ECConstants.ONE);
+ }
+
+ private static BigInteger[] calculateRange(BigInteger mid, BigInteger off, BigInteger div)
+ {
+ BigInteger i1 = mid.subtract(off).divide(div);
+ BigInteger i2 = mid.add(off).divide(div);
+ return order(i1, i2);
+ }
+
+ private static BigInteger[] extEuclidBezout(BigInteger[] ab)
+ {
+ boolean swap = ab[0].compareTo(ab[1]) < 0;
+ if (swap)
+ {
+ swap(ab);
+ }
+
+ BigInteger r0 = ab[0], r1 = ab[1];
+ BigInteger s0 = ECConstants.ONE, s1 = ECConstants.ZERO;
+ BigInteger t0 = ECConstants.ZERO, t1 = ECConstants.ONE;
+
+ while (r1.compareTo(BigInteger.ONE) > 0)
+ {
+ BigInteger[] qr = r0.divideAndRemainder(r1);
+ BigInteger q = qr[0], r2 = qr[1];
+
+ BigInteger s2 = s0.subtract(q.multiply(s1));
+ BigInteger t2 = t0.subtract(q.multiply(t1));
+
+ r0 = r1;
+ r1 = r2;
+ s0 = s1;
+ s1 = s2;
+ t0 = t1;
+ t1 = t2;
+ }
+
+ if (r1.signum() <= 0)
+ {
+ throw new IllegalStateException();
+ }
+
+ BigInteger[] st = new BigInteger[]{ s1, t1 };
+ if (swap)
+ {
+ swap(st);
+ }
+ return st;
+ }
+
+ private static BigInteger[] extEuclidGLV(BigInteger n, BigInteger lambda)
+ {
+ BigInteger r0 = n, r1 = lambda;
+ // BigInteger s0 = ECConstants.ONE, s1 = ECConstants.ZERO;
+ BigInteger t0 = ECConstants.ZERO, t1 = ECConstants.ONE;
+
+ for (;;)
+ {
+ BigInteger[] qr = r0.divideAndRemainder(r1);
+ BigInteger q = qr[0], r2 = qr[1];
+
+ // BigInteger s2 = s0.subtract(q.multiply(s1));
+ BigInteger t2 = t0.subtract(q.multiply(t1));
+
+ if (isLessThanSqrt(r1, n))
+ {
+ return new BigInteger[]{ r0, t0, r1, t1, r2, t2 };
+ }
+
+ r0 = r1;
+ r1 = r2;
+ // s0 = s1;
+ // s1 = s2;
+ t0 = t1;
+ t1 = t2;
+ }
+ }
+
+ private static BigInteger[] chooseShortest(BigInteger[] u, BigInteger[] v)
+ {
+ return isShorter(u, v) ? u : v;
+ }
+
+ private static BigInteger[] intersect(BigInteger[] ab, BigInteger[] cd)
+ {
+ BigInteger min = ab[0].max(cd[0]);
+ BigInteger max = ab[1].min(cd[1]);
+ if (min.compareTo(max) > 0)
+ {
+ return null;
+ }
+ return new BigInteger[]{ min, max };
+ }
+
+ private static boolean isLessThanSqrt(BigInteger a, BigInteger b)
+ {
+ a = a.abs();
+ b = b.abs();
+ int target = b.bitLength(), maxBits = a.bitLength() * 2, minBits = maxBits - 1;
+ return minBits <= target && (maxBits < target || a.multiply(a).compareTo(b) < 0);
+ }
+
+ private static boolean isShorter(BigInteger[] u, BigInteger[] v)
+ {
+ BigInteger u1 = u[0].abs(), u2 = u[1].abs(), v1 = v[0].abs(), v2 = v[1].abs();
+
+ // TODO Check whether "shorter" just means by rectangle norm:
+ // return u1.max(u2).compareTo(v1.max(v2)) < 0;
+
+ boolean c1 = u1.compareTo(v1) < 0, c2 = u2.compareTo(v2) < 0;
+ if (c1 == c2)
+ {
+ return c1;
+ }
+
+ BigInteger du = u1.multiply(u1).add(u2.multiply(u2));
+ BigInteger dv = v1.multiply(v1).add(v2.multiply(v2));
+
+ return du.compareTo(dv) < 0;
+ }
+
+ private static boolean isVectorBoundedBySqrt(BigInteger[] v, BigInteger n)
+ {
+ BigInteger max = v[0].abs().max(v[1].abs());
+ return isLessThanSqrt(max, n);
+ }
+
+ private static BigInteger[] order(BigInteger a, BigInteger b)
+ {
+ if (a.compareTo(b) <= 0)
+ {
+ return new BigInteger[]{ a, b };
+ }
+ return new BigInteger[]{ b, a };
+ }
+
+ private static BigInteger roundQuotient(BigInteger x, BigInteger y)
+ {
+ boolean negative = (x.signum() != y.signum());
+ x = x.abs();
+ y = y.abs();
+ BigInteger result = x.add(y.shiftRight(1)).divide(y);
+ return negative ? result.negate() : result;
+ }
+
+ private static BigInteger solveQuadraticEquation(BigInteger n, BigInteger r, BigInteger s)
+ {
+ BigInteger det = r.multiply(r).subtract(s.shiftLeft(2)).mod(n);
+
+ BigInteger root = new ECFieldElement.Fp(n, det).sqrt().toBigInteger();
+ if (!root.testBit(0))
+ {
+ root = n.subtract(root);
+ }
+
+ return root.shiftRight(1); // NOTE: implicit -1 of the low-bit
+ }
+
+ private static BigInteger isqrt(BigInteger x)
+ {
+ BigInteger g0 = x.shiftRight(x.bitLength() / 2);
+ for (;;)
+ {
+ BigInteger g1 = g0.add(x.divide(g0)).shiftRight(1);
+ if (g1.equals(g0))
+ {
+ return g1;
+ }
+ g0 = g1;
+ }
+ }
+
+ private static void swap(BigInteger[] ab)
+ {
+ BigInteger tmp = ab[0];
+ ab[0] = ab[1];
+ ab[1] = tmp;
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/util/Arrays.java b/core/src/main/java/org/bouncycastle/util/Arrays.java
index 9390fbed..3de0f7a2 100644
--- a/core/src/main/java/org/bouncycastle/util/Arrays.java
+++ b/core/src/main/java/org/bouncycastle/util/Arrays.java
@@ -323,6 +323,25 @@ public final class Arrays
return hc;
}
+
+ public static int hashCode(byte[] data, int off, int len)
+ {
+ if (data == null)
+ {
+ return 0;
+ }
+
+ int i = len;
+ int hc = i + 1;
+
+ while (--i >= 0)
+ {
+ hc *= 257;
+ hc ^= data[off + i];
+ }
+
+ return hc;
+ }
public static int hashCode(char[] data)
{
@@ -374,6 +393,25 @@ public final class Arrays
return hc;
}
+ public static int hashCode(int[] data, int off, int len)
+ {
+ if (data == null)
+ {
+ return 0;
+ }
+
+ int i = len;
+ int hc = i + 1;
+
+ while (--i >= 0)
+ {
+ hc *= 257;
+ hc ^= data[off + i];
+ }
+
+ return hc;
+ }
+
public static int hashCode(short[][][] shorts)
{
int hc = 0;
diff --git a/core/src/main/java/org/bouncycastle/util/encoders/Base64Encoder.java b/core/src/main/java/org/bouncycastle/util/encoders/Base64Encoder.java
index 1ef8f51b..ddcfc34f 100644
--- a/core/src/main/java/org/bouncycastle/util/encoders/Base64Encoder.java
+++ b/core/src/main/java/org/bouncycastle/util/encoders/Base64Encoder.java
@@ -7,20 +7,20 @@ public class Base64Encoder
implements Encoder
{
protected final byte[] encodingTable =
- {
- (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
- (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
- (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
- (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
- (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
- (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
- (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
- (byte)'v',
- (byte)'w', (byte)'x', (byte)'y', (byte)'z',
- (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6',
- (byte)'7', (byte)'8', (byte)'9',
- (byte)'+', (byte)'/'
- };
+ {
+ (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
+ (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
+ (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
+ (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
+ (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
+ (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
+ (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
+ (byte)'v',
+ (byte)'w', (byte)'x', (byte)'y', (byte)'z',
+ (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6',
+ (byte)'7', (byte)'8', (byte)'9',
+ (byte)'+', (byte)'/'
+ };
protected byte padding = (byte)'=';
diff --git a/core/src/main/java/org/bouncycastle/util/encoders/HexEncoder.java b/core/src/main/java/org/bouncycastle/util/encoders/HexEncoder.java
index 3bb594b0..3069c77d 100644
--- a/core/src/main/java/org/bouncycastle/util/encoders/HexEncoder.java
+++ b/core/src/main/java/org/bouncycastle/util/encoders/HexEncoder.java
@@ -7,11 +7,11 @@ public class HexEncoder
implements Encoder
{
protected final byte[] encodingTable =
- {
- (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7',
- (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f'
- };
-
+ {
+ (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7',
+ (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f'
+ };
+
/*
* set up the decoding table.
*/