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:
authorDavid Hook <dgh@cryptoworkshop.com>2014-01-03 13:11:55 +0400
committerDavid Hook <dgh@cryptoworkshop.com>2014-01-03 13:11:55 +0400
commita65ee18c49c5636b706ab56a0085da3b79a91e97 (patch)
tree8bb8361fc2ea82fa23870766a47081c1602c54b3
parenta337d00780b0110bddcedc8bbfd305d13ff3d3f1 (diff)
parent9f93f7bf294d6dcd4711fa9ab3bd7b5743049e99 (diff)
Merge remote-tracking branch 'origin/master'
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/ECCurve.java2
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/ECPoint.java32
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/CustomNamedCurves.java120
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/Mont256.java152
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat256.java281
-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.java24
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Point.java4
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Curve.java121
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java123
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1FieldElement.java151
-rw-r--r--core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Point.java321
-rw-r--r--core/src/test/java/org/bouncycastle/math/ec/test/ECPointPerformanceTest.java66
-rw-r--r--core/src/test/java/org/bouncycastle/math/ec/test/ECPointTest.java40
14 files changed, 1334 insertions, 174 deletions
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 f44a3756..0bc0dce4 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/ECCurve.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/ECCurve.java
@@ -789,7 +789,7 @@ public abstract class ECCurve
*/
public boolean isKoblitz()
{
- return order != null && cofactor != null && a.bitLength() <= 1 && b.bitLength() == 1;
+ return order != null && cofactor != null && a.bitLength() <= 1 && b.isOne();
}
/**
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 c6ec37da..9cd51b6e 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/ECPoint.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/ECPoint.java
@@ -196,7 +196,7 @@ public abstract class ECPoint
return coord == ECCurve.COORD_AFFINE
|| coord == ECCurve.COORD_LAMBDA_AFFINE
|| isInfinity()
- || zs[0].bitLength() == 1;
+ || zs[0].isOne();
}
/**
@@ -222,7 +222,7 @@ public abstract class ECPoint
default:
{
ECFieldElement Z1 = getZCoord(0);
- if (Z1.bitLength() == 1)
+ if (Z1.isOne())
{
return this;
}
@@ -569,8 +569,8 @@ public abstract class ECPoint
ECFieldElement Z1 = this.zs[0];
ECFieldElement Z2 = b.zs[0];
- boolean Z1IsOne = Z1.bitLength() == 1;
- boolean Z2IsOne = Z2.bitLength() == 1;
+ boolean Z1IsOne = Z1.isOne();
+ boolean Z2IsOne = Z2.isOne();
ECFieldElement u1 = Z1IsOne ? Y2 : Y2.multiply(Z1);
ECFieldElement u2 = Z2IsOne ? Y1 : Y1.multiply(Z2);
@@ -612,7 +612,7 @@ public abstract class ECPoint
ECFieldElement Z1 = this.zs[0];
ECFieldElement Z2 = b.zs[0];
- boolean Z1IsOne = Z1.bitLength() == 1;
+ boolean Z1IsOne = Z1.isOne();
ECFieldElement X3, Y3, Z3, Z3Squared = null;
@@ -662,7 +662,7 @@ public abstract class ECPoint
S2 = Z1Cubed.multiply(Y2);
}
- boolean Z2IsOne = Z2.bitLength() == 1;
+ boolean Z2IsOne = Z2.isOne();
ECFieldElement Z2Squared, U1, S1;
if (Z2IsOne)
{
@@ -778,7 +778,7 @@ public abstract class ECPoint
{
ECFieldElement Z1 = this.zs[0];
- boolean Z1IsOne = Z1.bitLength() == 1;
+ boolean Z1IsOne = Z1.isOne();
// TODO Optimize for small negative a4 and -3
ECFieldElement w = curve.getA();
@@ -806,7 +806,7 @@ public abstract class ECPoint
{
ECFieldElement Z1 = this.zs[0];
- boolean Z1IsOne = Z1.bitLength() == 1;
+ boolean Z1IsOne = Z1.isOne();
ECFieldElement Y1Squared = Y1.square();
ECFieldElement T = Y1Squared.square();
@@ -1107,7 +1107,7 @@ public abstract class ECPoint
ECFieldElement _8T = eight(T);
ECFieldElement Y3 = M.multiply(S.subtract(X3)).subtract(_8T);
ECFieldElement W3 = calculateW ? two(_8T.multiply(W1)) : null;
- ECFieldElement Z3 = two(Z1.bitLength() == 1 ? Y1 : Y1.multiply(Z1));
+ ECFieldElement Z3 = two(Z1.isOne() ? Y1 : Y1.multiply(Z1));
return new ECPoint.Fp(this.getCurve(), X3, Y3, new ECFieldElement[]{ Z3, W3 }, this.withCompression);
}
@@ -1194,7 +1194,7 @@ public abstract class ECPoint
if (ECCurve.COORD_LAMBDA_PROJECTIVE == coord)
{
ECFieldElement Z = zs[0];
- if (Z.bitLength() != 1)
+ if (!Z.isOne())
{
Y = Y.divide(Z);
}
@@ -1317,7 +1317,7 @@ public abstract class ECPoint
ECFieldElement Y1 = this.y, Z1 = this.zs[0];
ECFieldElement Y2 = b.y, Z2 = b.zs[0];
- boolean Z2IsOne = Z2.bitLength() == 1;
+ boolean Z2IsOne = Z2.isOne();
ECFieldElement U1 = Z1.multiply(Y2);
ECFieldElement U2 = Z2IsOne ? Y1 : Y1.multiply(Z2);
@@ -1357,7 +1357,7 @@ public abstract class ECPoint
ECFieldElement L1 = this.y, Z1 = this.zs[0];
ECFieldElement L2 = b.y, Z2 = b.zs[0];
- boolean Z1IsOne = Z1.bitLength() == 1;
+ boolean Z1IsOne = Z1.isOne();
ECFieldElement U2 = X2, S2 = L2;
if (!Z1IsOne)
{
@@ -1365,7 +1365,7 @@ public abstract class ECPoint
S2 = S2.multiply(Z1);
}
- boolean Z2IsOne = Z2.bitLength() == 1;
+ boolean Z2IsOne = Z2.isOne();
ECFieldElement U1 = X1, S1 = L1;
if (!Z2IsOne)
{
@@ -1527,7 +1527,7 @@ public abstract class ECPoint
{
ECFieldElement Y1 = this.y, Z1 = this.zs[0];
- boolean Z1IsOne = Z1.bitLength() == 1;
+ boolean Z1IsOne = Z1.isOne();
ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.multiply(Z1);
ECFieldElement Y1Z1 = Z1IsOne ? Y1 : Y1.multiply(Z1);
@@ -1547,7 +1547,7 @@ public abstract class ECPoint
{
ECFieldElement L1 = this.y, Z1 = this.zs[0];
- boolean Z1IsOne = Z1.bitLength() == 1;
+ boolean Z1IsOne = Z1.isOne();
ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.multiply(Z1);
ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.square();
ECFieldElement a = curve.getA();
@@ -1609,7 +1609,7 @@ public abstract class ECPoint
{
// NOTE: twicePlus() only optimized for lambda-affine argument
ECFieldElement X2 = b.x, Z2 = b.zs[0];
- if (X2.isZero() || Z2.bitLength() != 1)
+ if (X2.isZero() || !Z2.isOne())
{
return twice().add(b);
}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/CustomNamedCurves.java b/core/src/main/java/org/bouncycastle/math/ec/custom/CustomNamedCurves.java
new file mode 100644
index 00000000..4a788128
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/CustomNamedCurves.java
@@ -0,0 +1,120 @@
+package org.bouncycastle.math.ec.custom;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.sec.SECObjectIdentifiers;
+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.sec.SecP256K1Curve;
+import org.bouncycastle.math.ec.custom.sec.SecP256R1Curve;
+import org.bouncycastle.util.Strings;
+import org.bouncycastle.util.encoders.Hex;
+
+public class CustomNamedCurves
+{
+ private static ECCurve configureCurve(ECCurve curve)
+ {
+ return curve;
+ }
+
+ /*
+ * secp256k1
+ */
+ static X9ECParametersHolder secp256k1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ byte[] S = null;
+ ECCurve curve = configureCurve(new SecP256K1Curve());
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
+ + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"));
+ return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+ }
+ };
+
+ /*
+ * secp256r1
+ */
+ static X9ECParametersHolder secp256r1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ byte[] S = Hex.decode("C49D360886E704936A6678E1139D26B7819F7E90");
+ ECCurve curve = configureCurve(new SecP256R1Curve());
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"
+ + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"));
+ return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+ }
+ };
+
+ static final Hashtable objIds = new Hashtable();
+ static final Hashtable curves = new Hashtable();
+ static final Hashtable names = new Hashtable();
+
+ static void defineCurve(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder)
+ {
+ objIds.put(name, oid);
+ names.put(oid, name);
+ curves.put(oid, holder);
+ }
+
+ static
+ {
+ defineCurve("secp256k1", SECObjectIdentifiers.secp256k1, secp256k1);
+ defineCurve("secp256r1", SECObjectIdentifiers.secp256r1, secp256r1);
+
+ objIds.put(Strings.toLowerCase("P-256"), SECObjectIdentifiers.secp256r1);
+ }
+
+ public static X9ECParameters getByName(String name)
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name));
+ return oid == null ? null : getByOID(oid);
+ }
+
+ /**
+ * return the X9ECParameters object for the named curve represented by the passed in object
+ * identifier. Null if the curve isn't present.
+ *
+ * @param oid
+ * an object identifier representing a named curve, if present.
+ */
+ public static X9ECParameters getByOID(ASN1ObjectIdentifier oid)
+ {
+ X9ECParametersHolder holder = (X9ECParametersHolder)curves.get(oid);
+ return holder == null ? null : holder.getParameters();
+ }
+
+ /**
+ * return the object identifier signified by the passed in name. Null if there is no object
+ * identifier associated with name.
+ *
+ * @return the object identifier associated with name, if present.
+ */
+ public static ASN1ObjectIdentifier getOID(String name)
+ {
+ return (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name));
+ }
+
+ /**
+ * return the named curve name represented by the given object identifier.
+ */
+ public static String getName(ASN1ObjectIdentifier oid)
+ {
+ return (String)names.get(oid);
+ }
+
+ /**
+ * returns an enumeration containing the name strings for curves contained in this structure.
+ */
+ public static Enumeration getNames()
+ {
+ return objIds.keys();
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Mont256.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Mont256.java
new file mode 100644
index 00000000..b0a415e7
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Mont256.java
@@ -0,0 +1,152 @@
+package org.bouncycastle.math.ec.custom.sec;
+
+public abstract class Mont256
+{
+ private static final long M = 0xFFFFFFFFL;
+
+ public static int inverse32(int x)
+ {
+ assert (x & 1) == 1;
+ int z = x; // x.z == 1 mod 2**3
+ z *= 2 - x * z; // x.z == 1 mod 2**6
+ z *= 2 - x * z; // x.z == 1 mod 2**12
+ z *= 2 - x * z; // x.z == 1 mod 2**24
+ z *= 2 - x * z; // x.z == 1 mod 2**48
+ assert x * z == 1;
+ return z;
+ }
+
+ public static void multAdd(int[] x, int[] y, int[] z, int[] m, int mInv32)
+ {
+ int z_8 = 0;
+ long y_0 = y[0] & M;
+
+ for (int i = 0; i < 8; ++i)
+ {
+ long z_0 = z[0] & M;
+ long x_i = x[i] & M;
+
+ long prod1 = x_i * y_0;
+ long carry = (prod1 & M) + z_0;
+
+ long t = ((int)carry * mInv32) & M;
+
+ long prod2 = t * (m[0] & M);
+ carry += (prod2 & M);
+ assert (int)carry == 0;
+ carry = (carry >>> 32) + (prod1 >>> 32) + (prod2 >>> 32);
+
+ for (int j = 1; j < 8; ++j)
+ {
+ prod1 = x_i * (y[j] & M);
+ prod2 = t * (m[j] & M);
+
+ carry += (prod1 & M) + (prod2 & M) + (z[j] & M);
+ z[j - 1] = (int)carry;
+ carry = (carry >>> 32) + (prod1 >>> 32) + (prod2 >>> 32);
+ }
+
+ carry += (z_8 & M);
+ z[7] = (int)carry;
+ z_8 = (int)(carry >>> 32);
+ }
+
+ if (z_8 != 0 || Nat256.gte(z, m))
+ {
+ Nat256.sub(z, m, z);
+ }
+ }
+
+ public static void multAddXF(int[] x, int[] y, int[] z, int[] m)
+ {
+ assert m[0] == M;
+
+ int z_8 = 0;
+ long y_0 = y[0] & M;
+
+ for (int i = 0; i < 8; ++i)
+ {
+ long x_i = x[i] & M;
+
+ long carry = x_i * y_0 + (z[0] & M);
+ long t = carry & M;
+ carry = (carry >>> 32) + t;
+
+ for (int j = 1; j < 8; ++j)
+ {
+ long prod1 = x_i * (y[j] & M);
+ long prod2 = t * (m[j] & M);
+
+ carry += (prod1 & M) + (prod2 & M) + (z[j] & M);
+ z[j - 1] = (int)carry;
+ carry = (carry >>> 32) + (prod1 >>> 32) + (prod2 >>> 32);
+ }
+
+ carry += (z_8 & M);
+ z[7] = (int)carry;
+ z_8 = (int)(carry >>> 32);
+ }
+
+ if (z_8 != 0 || Nat256.gte(z, m))
+ {
+ Nat256.sub(z, m, z);
+ }
+ }
+
+ public static void reduce(int[] z, int[] m, int mInv32)
+ {
+ for (int i = 0; i < 8; ++i)
+ {
+ int z_0 = z[0];
+
+ long t = (z_0 * mInv32) & M;
+
+ long carry = t * (m[0] & M) + (z_0 & M);
+ assert (int)carry == 0;
+ carry >>>= 32;
+
+ for (int j = 1; j < 8; ++j)
+ {
+ carry += t * (m[j] & M) + (z[j] & M);
+ z[j - 1] = (int)carry;
+ carry >>>= 32;
+ }
+
+ z[7] = (int)carry;
+ assert carry >>> 32 == 0;
+ }
+
+ if (Nat256.gte(z, m))
+ {
+ Nat256.sub(z, m, z);
+ }
+ }
+
+ public static void reduceXF(int[] z, int[] m)
+ {
+ assert m[0] == M;
+
+ for (int i = 0; i < 8; ++i)
+ {
+ int z_0 = z[0];
+
+ long t = z_0 & M;
+ long carry = t;
+
+ for (int j = 1; j < 8; ++j)
+ {
+ carry += t * (m[j] & M) + (z[j] & M);
+ z[j - 1] = (int)carry;
+ carry >>>= 32;
+ }
+
+ z[7] = (int)carry;
+ assert carry >>> 32 == 0;
+ }
+
+ if (Nat256.gte(z, m))
+ {
+ Nat256.sub(z, m, z);
+ }
+ }
+}
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 91ae8406..9bd1d0dd 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
@@ -1,5 +1,9 @@
package org.bouncycastle.math.ec.custom.sec;
+import java.math.BigInteger;
+
+import org.bouncycastle.crypto.util.Pack;
+
public abstract class Nat256
{
private static final long M = 0xFFFFFFFFL;
@@ -34,6 +38,36 @@ public abstract class Nat256
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;
+ c += (x[7] & M) + (y[7] & M) + (z[7] & M);
+ z[7] = (int)c;
+ c >>>= 32;
+ return (int)c;
+ }
+
public static int addDWord(long x, int[] z, int zOff)
{
assert zOff < 6;
@@ -87,6 +121,16 @@ public abstract class Nat256
return c == 0 ? 0 : incExt(zz, zzOff + 1);
}
+ public static int[] create()
+ {
+ return new int[8];
+ }
+
+ public static int[] createExt()
+ {
+ return new int[16];
+ }
+
public static int dec(int[] z, int zOff)
{
assert zOff < 8;
@@ -98,10 +142,42 @@ public abstract class Nat256
return 0;
}
}
- while(++i < 8);
+ while (++i < 8);
return -1;
}
+ public static int[] fromBigInteger(BigInteger x)
+ {
+ if (x.signum() < 0 || x.bitLength() > 256)
+ {
+ 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;
+ }
+ if ((bit & 255) != bit)
+ {
+ return 0;
+ }
+ int w = bit >>> 5;
+ int b = bit & 31;
+ return (x[w] >>> b) & 1;
+ }
+
public static boolean gte(int[] x, int[] y)
{
for (int i = 7; i >= 0; --i)
@@ -176,19 +252,122 @@ public abstract class Nat256
public static void mul(int[] x, int[] y, int[] zz)
{
- zz[8] = mulWordExt(x[0], y, zz, 0);
+ 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 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;
+ c += x_0 * y_7;
+ zz[7] = (int)c;
+ c >>>= 32;
+ zz[8] = (int)c;
+ }
+
for (int i = 1; i < 8; ++i)
{
- zz[i + 8] = mulWordAddExt(x[i], y, 0, zz, 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;
+ zz[i + 8] = (int)c;
}
}
- public static void mulAdd(int[] x, int[] y, int[] zz)
+ public static int mulAdd(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 t = 0;
+
for (int i = 0; i < 8; ++i)
{
- zz[i + 8] += mulWordAddExt(x[i], y, 0, zz, 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 += t + (zz[i + 8] & M);
+ zz[i + 8] = (int)c;
+ c >>>= 32;
+ t = c;
}
+
+ return (int)t;
}
public static int mulWordAddExt(int x, int[] yy, int yyOff, int[] zz, int zzOff)
@@ -204,30 +383,6 @@ public abstract class Nat256
c >>>= 32;
}
while (++i < 8);
-// c += xVal * (yy[yyOff + 0] & M) + (zz[zzOff + 0] & M);
-// zz[zzOff + 0] = (int)c;
-// c >>>= 32;
-// c += xVal * (yy[yyOff + 1] & M) + (zz[zzOff + 1] & M);
-// zz[zzOff + 1] = (int)c;
-// c >>>= 32;
-// c += xVal * (yy[yyOff + 2] & M) + (zz[zzOff + 2] & M);
-// zz[zzOff + 2] = (int)c;
-// c >>>= 32;
-// c += xVal * (yy[yyOff + 3] & M) + (zz[zzOff + 3] & M);
-// zz[zzOff + 3] = (int)c;
-// c >>>= 32;
-// c += xVal * (yy[yyOff + 4] & M) + (zz[zzOff + 4] & M);
-// zz[zzOff + 4] = (int)c;
-// c >>>= 32;
-// c += xVal * (yy[yyOff + 5] & M) + (zz[zzOff + 5] & M);
-// zz[zzOff + 5] = (int)c;
-// c >>>= 32;
-// c += xVal * (yy[yyOff + 6] & M) + (zz[zzOff + 6] & M);
-// zz[zzOff + 6] = (int)c;
-// c >>>= 32;
-// c += xVal * (yy[yyOff + 7] & M) + (zz[zzOff + 7] & M);
-// zz[zzOff + 7] = (int)c;
-// c >>>= 32;
return (int)c;
}
@@ -274,30 +429,6 @@ public abstract class Nat256
c >>>= 32;
}
while (++i < 8);
-// c += xVal * (y[0] & M);
-// zz[zzOff + 0] = (int)c;
-// c >>>= 32;
-// c += xVal * (y[1] & M);
-// zz[zzOff + 1] = (int)c;
-// c >>>= 32;
-// c += xVal * (y[2] & M);
-// zz[zzOff + 2] = (int)c;
-// c >>>= 32;
-// c += xVal * (y[3] & M);
-// zz[zzOff + 3] = (int)c;
-// c >>>= 32;
-// c += xVal * (y[4] & M);
-// zz[zzOff + 4] = (int)c;
-// c >>>= 32;
-// c += xVal * (y[5] & M);
-// zz[zzOff + 5] = (int)c;
-// c >>>= 32;
-// c += xVal * (y[6] & M);
-// zz[zzOff + 6] = (int)c;
-// c >>>= 32;
-// c += xVal * (y[7] & M);
-// zz[zzOff + 7] = (int)c;
-// c >>>= 32;
return (int)c;
}
@@ -367,6 +498,36 @@ public abstract class Nat256
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;
+ c += (z[7] & M) - (x[7] & M) - (y[7] & M);
+ z[7] = (int)c;
+ c >>= 32;
+ return (int)c;
+ }
+
public static int subDWord(long x, int[] z)
{
x = -x;
@@ -379,6 +540,20 @@ public abstract class Nat256
return x == 0 ? 0 : dec(z, 2);
}
+ public static BigInteger toBigInteger(int[] x)
+ {
+ byte[] bs = new byte[32];
+ for (int i = 0; i < 8; ++i)
+ {
+ int x_i = x[i];
+ if (x_i != 0)
+ {
+ Pack.intToBigEndian(x_i, bs, (7 - i) << 2);
+ }
+ }
+ return new BigInteger(1, bs);
+ }
+
public static void zero(int[] z)
{
z[0] = 0;
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 c58c91d2..bc86385a 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,8 +2,6 @@ package org.bouncycastle.math.ec.custom.sec;
import java.math.BigInteger;
-import org.bouncycastle.crypto.util.Pack;
-
public class SecP256K1Field
{
private static final long M = 0xFFFFFFFFL;
@@ -11,22 +9,13 @@ public class SecP256K1Field
// 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
private static final int[] P = new int[] { 0xFFFFFC2F, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF };
+ private static final int P7 = 0xFFFFFFFF;
private static final long PInv = 0x00000001000003D1L;
- public static int[] create()
- {
- return new int[8];
- }
-
- public static int[] createDouble()
- {
- return new int[16];
- }
-
public static void add(int[] x, int[] y, int[] z)
{
int c = Nat256.add(x, y, z);
- if (c != 0 || (z[7] == -1 && Nat256.gte(z, P)))
+ if (c != 0 || (z[7] == P7 && Nat256.gte(z, P)))
{
Nat256.addDWord(PInv, z, 0);
}
@@ -36,7 +25,7 @@ public class SecP256K1Field
{
System.arraycopy(x, 0, z, 0, 8);
int c = Nat256.inc(z, 0);
- if (c != 0 || (z[7] == -1 && Nat256.gte(z, P)))
+ if (c != 0 || (z[7] == P7 && Nat256.gte(z, P)))
{
Nat256.addDWord(PInv, z, 0);
}
@@ -44,38 +33,17 @@ public class SecP256K1Field
public static int[] fromBigInteger(BigInteger x)
{
- if (x.signum() < 0 || x.bitLength() > 256)
- {
- throw new IllegalArgumentException();
- }
-
- int[] z = create();
- int i = 0;
- while (x.bitLength() > 0)
- {
- z[i++] = x.intValue();
- x = x.shiftRight(32);
- }
- if (z[7] == -1 && Nat256.gte(z, P))
+ int[] z = Nat256.fromBigInteger(x);
+ if (z[7] == P7 && Nat256.gte(z, P))
{
Nat256.addDWord(PInv, z, 0);
}
return z;
}
- public static boolean isOne(int[] x)
- {
- return Nat256.isOne(x);
- }
-
- public static boolean isZero(int[] x)
- {
- return Nat256.isZero(x);
- }
-
public static void multiply(int[] x, int[] y, int[] z)
{
- int[] tt = createDouble();
+ int[] tt = Nat256.createExt();
Nat256.mul(x, y, tt);
reduce(tt, z);
}
@@ -104,9 +72,9 @@ public class SecP256K1Field
assert c == 0L || c == 1L;
- if (c != 0 || (tt[7] == -1 && Nat256.gte(tt, P)))
+ if (c != 0 || (tt[7] == P7 && Nat256.gte(tt, P)))
{
- Nat256.addDWord(PInv, z, 0);
+ Nat256.addDWord(PInv, tt, 0);
}
System.arraycopy(tt, 0, z, 0, 8);
@@ -114,7 +82,7 @@ public class SecP256K1Field
public static void square(int[] x, int[] z)
{
- int[] tt = createDouble();
+ int[] tt = Nat256.createExt();
// NOTE: The simpler 'mul' performs better than 'square'
// Nat256.square(x, tt);
Nat256.mul(x, x, tt);
@@ -129,25 +97,4 @@ public class SecP256K1Field
Nat256.subDWord(PInv, z);
}
}
-
- public static boolean testBit(int[] x, int bit)
- {
- if (bit < 0 || bit > 255)
- {
- return false;
- }
- int w = bit >>> 5;
- int b = bit & 31;
- return (x[w] & (1 << b)) != 0;
- }
-
- public static BigInteger toBigInteger(int[] x)
- {
- byte[] bs = new byte[32];
- for (int i = 0; i < 8; ++i)
- {
- Pack.intToBigEndian(x[i], bs, (7 - i) << 2);
- }
- return new BigInteger(1, bs);
- }
}
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 92a4f3e5..37122ccc 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
@@ -29,27 +29,27 @@ public class SecP256K1FieldElement extends ECFieldElement
public boolean isZero()
{
- return SecP256K1Field.isZero(x);
+ return Nat256.isZero(x);
}
public boolean isOne()
{
- return SecP256K1Field.isOne(x);
+ return Nat256.isOne(x);
}
public boolean testBitZero()
{
- return SecP256K1Field.testBit(x, 0);
+ return Nat256.getBit(x, 0) == 1;
}
public BigInteger toBigInteger()
{
- return SecP256K1Field.toBigInteger(x);
+ return Nat256.toBigInteger(x);
}
public String getFieldName()
{
- return "FEp256k1";
+ return "SecP256K1Field";
}
public int getFieldSize()
@@ -64,28 +64,28 @@ public class SecP256K1FieldElement extends ECFieldElement
public ECFieldElement add(ECFieldElement b)
{
- int[] z = SecP256K1Field.create();
+ int[] z = Nat256.create();
SecP256K1Field.add(x, ((SecP256K1FieldElement)b).x, z);
return new SecP256K1FieldElement(z);
}
public ECFieldElement addOne()
{
- int[] z = SecP256K1Field.create();
+ int[] z = Nat256.create();
SecP256K1Field.addOne(x, z);
return new SecP256K1FieldElement(z);
}
public ECFieldElement subtract(ECFieldElement b)
{
- int[] z = SecP256K1Field.create();
+ int[] z = Nat256.create();
SecP256K1Field.subtract(x, ((SecP256K1FieldElement)b).x, z);
return new SecP256K1FieldElement(z);
}
public ECFieldElement multiply(ECFieldElement b)
{
- int[] z = SecP256K1Field.create();
+ int[] z = Nat256.create();
SecP256K1Field.multiply(x, ((SecP256K1FieldElement)b).x, z);
return new SecP256K1FieldElement(z);
}
@@ -93,21 +93,21 @@ public class SecP256K1FieldElement extends ECFieldElement
public ECFieldElement divide(ECFieldElement b)
{
int[] y = SecP256K1Field.fromBigInteger(b.invert().toBigInteger());
- int[] z = SecP256K1Field.create();
+ int[] z = Nat256.create();
SecP256K1Field.multiply(x, y, z);
return new SecP256K1FieldElement(z);
}
public ECFieldElement negate()
{
- int[] z = SecP256K1Field.create();
+ int[] z = Nat256.create();
SecP256K1Field.negate(x, z);
return new SecP256K1FieldElement(z);
}
public ECFieldElement square()
{
- int[] z = SecP256K1Field.create();
+ int[] z = Nat256.create();
SecP256K1Field.square(x, z);
return new SecP256K1FieldElement(z);
}
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 847a824d..8a3f55c7 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
@@ -50,7 +50,7 @@ public class SecP256K1Point extends ECPoint
this.withCompression = withCompression;
}
- public SecP256K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs,
+ SecP256K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs,
boolean withCompression)
{
super(curve, x, y, zs);
@@ -206,7 +206,7 @@ public class SecP256K1Point extends ECPoint
ECFieldElement X1Squared = X1.square();
ECFieldElement M = three(X1Squared);
- ECFieldElement S = four(X1.multiply(Y1Squared));
+ ECFieldElement S = four(Y1Squared.multiply(X1));
ECFieldElement X3 = M.square().subtract(two(S));
ECFieldElement Y3 = S.subtract(X3).multiply(M).subtract(eight(T));
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
new file mode 100644
index 00000000..04faa974
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Curve.java
@@ -0,0 +1,121 @@
+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.ECPoint;
+import org.bouncycastle.util.encoders.Hex;
+
+public class SecP256R1Curve extends ECCurve
+{
+ public static final BigInteger q = new BigInteger(1,
+ Hex.decode("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"));
+ public static final BigInteger r = ECConstants.ONE.shiftLeft(256).subtract(q);
+
+ private static final int SecP256R1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+ protected SecP256R1Point infinity;
+
+ public SecP256R1Curve()
+ {
+ this.infinity = new SecP256R1Point(this, null, null);
+
+ this.a = fromBigInteger(new BigInteger(1,
+ Hex.decode("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC")));
+ this.b = fromBigInteger(new BigInteger(1,
+ Hex.decode("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B")));
+ this.order = new BigInteger(1, Hex.decode("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"));
+ this.cofactor = BigInteger.valueOf(1);
+
+ this.coord = SecP256R1_DEFAULT_COORDS;
+ }
+
+ protected ECCurve cloneCurve()
+ {
+ return new SecP256R1Curve();
+ }
+
+ 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 SecP256R1FieldElement(x);
+ }
+
+ protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)
+ {
+ return new SecP256R1Point(this, x, y, withCompression);
+ }
+
+ protected ECPoint decompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement x = fromBigInteger(X1);
+ ECFieldElement alpha = x.square().add(a).multiply(x).add(b);
+ ECFieldElement beta = alpha.sqrt();
+
+ //
+ // if we can't find a sqrt we haven't got a point on the
+ // curve - run!
+ //
+ if (beta == null)
+ {
+ throw new RuntimeException("Invalid point compression");
+ }
+
+ if (beta.testBitZero() != (yTilde == 1))
+ {
+ // Use the other root
+ beta = beta.negate();
+ }
+
+ return new SecP256R1Point(this, x, beta, true);
+ }
+
+ public ECPoint getInfinity()
+ {
+ return infinity;
+ }
+
+ public boolean equals(Object anObject)
+ {
+ if (anObject == this)
+ {
+ return true;
+ }
+
+ if (!(anObject instanceof SecP256R1Curve))
+ {
+ return false;
+ }
+
+ SecP256R1Curve other = (SecP256R1Curve)anObject;
+
+ return this.q.equals(other.q) && a.equals(other.a) && b.equals(other.b);
+ }
+
+ public int hashCode()
+ {
+ return a.hashCode() ^ b.hashCode() ^ q.hashCode();
+ }
+}
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
new file mode 100644
index 00000000..5647e8f5
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java
@@ -0,0 +1,123 @@
+package org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+public class SecP256R1Field
+{
+ // 2^256 - 2^224 + 2^192 + 2^96 - 1
+ private static final int[] P = new int[] { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000001, 0xFFFFFFFF };
+ private static final int P7 = 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);
+ }
+ }
+
+ public static void addOne(int[] x, int[] z)
+ {
+ System.arraycopy(x, 0, z, 0, 8);
+ int c = Nat256.inc(z, 0);
+ if (c != 0 || (z[7] == P7 && Nat256.gte(z, P)))
+ {
+ Nat256.sub(z, P, z);
+ }
+ }
+
+ public static int[] fromBigInteger(BigInteger x)
+ {
+ int[] z = Nat256.fromBigInteger(x);
+ if (z[7] == P7 && Nat256.gte(z, P))
+ {
+ Nat256.sub(z, P, z);
+ }
+ return z;
+ }
+
+ public static void multiply(int[] x, int[] y, int[] z)
+ {
+ int[] tt = Nat256.createExt();
+ Nat256.mul(x, y, tt);
+ reduce(tt, z);
+ }
+
+ public static void negate(int[] x, int[] z)
+ {
+ if (Nat256.isZero(x))
+ {
+ Nat256.zero(z);
+ }
+ else
+ {
+ Nat256.sub(P, x, z);
+ }
+ }
+
+ private static void reduce(int[] tt, int[] z)
+ {
+ int c = 0;
+
+ System.arraycopy(tt, 0, z, 0, 8); //s1
+
+ int[] s2 = new int[] { 0, 0, 0, tt[11], tt[12], tt[13], tt[14], tt[15] };
+ c += Nat256.addBothTo(s2, s2, z);
+ int[] s3 = new int[] { 0, 0, 0, tt[12], tt[13], tt[14], tt[15], 0 };
+ c += Nat256.addBothTo(s3, s3, z);
+ int[] s4 = new int[] { tt[8], tt[9], tt[10], 0, 0, 0, tt[14], tt[15] };
+ int[] s5 = new int[] { tt[9], tt[10], tt[11], tt[13], tt[14], tt[15], tt[13], tt[8] };
+ c += Nat256.addBothTo(s4, s5, z);
+
+ int[] s6 = new int[] { tt[11], tt[12], tt[13], 0, 0, 0, tt[8], tt[10] };
+ int[] s7 = new int[] { tt[12], tt[13], tt[14], tt[15], 0, 0, tt[9], tt[11] };
+ c += Nat256.subBothFrom(s6, s7, z);
+ int[] s8 = new int[] { tt[13], tt[14], tt[15], tt[8], tt[9], tt[10], 0, tt[12] };
+ int[] s9 = new int[] { tt[14], tt[15], 0, tt[9], tt[10], tt[11], 0, tt[13] };
+ c += Nat256.subBothFrom(s8, s9, z);
+
+ if (c > 0)
+ {
+ do
+ {
+ c += Nat256.sub(z, P, z);
+ }
+ while (c != 0);
+ }
+ else if (c < 0)
+ {
+ do
+ {
+ c += Nat256.add(z, P, z);
+ }
+ while (c != 0);
+ }
+
+ assert c == 0;
+
+ if (z[7] == P7 && Nat256.gte(z, P))
+ {
+ Nat256.sub(z, P, z);
+ }
+ }
+
+ public static void square(int[] x, int[] z)
+ {
+ int[] tt = Nat256.createExt();
+ // NOTE: The simpler 'mul' performs better than 'square'
+ // Nat256.square(x, tt);
+ Nat256.mul(x, x, tt);
+ reduce(tt, z);
+ }
+
+ public static void subtract(int[] x, int[] y, int[] z)
+ {
+ int c = Nat256.sub(x, y, z);
+ if (c != 0)
+ {
+ Nat256.add(z, P, z);
+ }
+ }
+}
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
new file mode 100644
index 00000000..5c04f788
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1FieldElement.java
@@ -0,0 +1,151 @@
+package org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.math.ec.ECFieldElement;
+import org.bouncycastle.util.Arrays;
+
+public class SecP256R1FieldElement extends ECFieldElement
+{
+ public static final BigInteger Q = SecP256R1Curve.q;
+ public static final BigInteger Qr = SecP256R1Curve.r;
+
+ protected int[] x;
+
+ public SecP256R1FieldElement(BigInteger x)
+ {
+ if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0)
+ {
+ throw new IllegalArgumentException("x value invalid in FEp256k1 field element");
+ }
+
+ this.x = SecP256R1Field.fromBigInteger(x);
+ }
+
+ protected SecP256R1FieldElement(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 "SecP256R1Field";
+ }
+
+ public int getFieldSize()
+ {
+ return Q.bitLength();
+ }
+
+ public BigInteger getQ()
+ {
+ return Q;
+ }
+
+ public ECFieldElement add(ECFieldElement b)
+ {
+ int[] z = Nat256.create();
+ SecP256R1Field.add(x, ((SecP256R1FieldElement)b).x, z);
+ return new SecP256R1FieldElement(z);
+ }
+
+ public ECFieldElement addOne()
+ {
+ int[] z = Nat256.create();
+ SecP256R1Field.addOne(x, z);
+ return new SecP256R1FieldElement(z);
+ }
+
+ public ECFieldElement subtract(ECFieldElement b)
+ {
+ int[] z = Nat256.create();
+ SecP256R1Field.subtract(x, ((SecP256R1FieldElement)b).x, z);
+ return new SecP256R1FieldElement(z);
+ }
+
+ public ECFieldElement multiply(ECFieldElement b)
+ {
+ int[] z = Nat256.create();
+ SecP256R1Field.multiply(x, ((SecP256R1FieldElement)b).x, z);
+ return new SecP256R1FieldElement(z);
+ }
+
+ public ECFieldElement divide(ECFieldElement b)
+ {
+ int[] y = SecP256R1Field.fromBigInteger(b.invert().toBigInteger());
+ int[] z = Nat256.create();
+ SecP256R1Field.multiply(x, y, z);
+ return new SecP256R1FieldElement(z);
+ }
+
+ public ECFieldElement negate()
+ {
+ int[] z = Nat256.create();
+ SecP256R1Field.negate(x, z);
+ return new SecP256R1FieldElement(z);
+ }
+
+ public ECFieldElement square()
+ {
+ int[] z = Nat256.create();
+ SecP256R1Field.square(x, z);
+ return new SecP256R1FieldElement(z);
+ }
+
+ public ECFieldElement invert()
+ {
+ return new SecP256R1FieldElement(toBigInteger().modInverse(Q));
+ }
+
+ // D.1.4 91
+ /**
+ * return a sqrt root - the routine verifies that the calculation returns the right value - if
+ * none exists it returns null.
+ */
+ public ECFieldElement sqrt()
+ {
+ ECFieldElement root = new ECFieldElement.Fp(Q, toBigInteger()).sqrt();
+ return root == null ? null : new SecP256R1FieldElement(root.toBigInteger());
+ }
+
+ public boolean equals(Object other)
+ {
+ if (other == this)
+ {
+ return true;
+ }
+
+ if (!(other instanceof SecP256R1FieldElement))
+ {
+ return false;
+ }
+
+ SecP256R1FieldElement o = (SecP256R1FieldElement)other;
+ return Arrays.areEqual(x, o.x);
+ }
+
+ public int hashCode()
+ {
+ return Q.hashCode() ^ Arrays.hashCode(x);
+ }
+}
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
new file mode 100644
index 00000000..a9e5ab86
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Point.java
@@ -0,0 +1,321 @@
+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;
+
+public class SecP256R1Point 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 SecP256R1Point(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 SecP256R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
+ {
+ super(curve, x, y);
+
+ if ((x != null && y == null) || (x == null && y != null))
+ {
+ throw new IllegalArgumentException("Exactly one of the field elements is null");
+ }
+
+ this.withCompression = withCompression;
+ }
+
+ SecP256R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+ {
+ super(curve, x, y, zs);
+
+ this.withCompression = withCompression;
+ }
+
+ 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();
+ }
+
+ 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 X3, Y3, Z3;
+
+ // if (!Z1IsOne && Z1.equals(Z2))
+ // {
+ // // TODO Make this available as public method coZAdd?
+ //
+ // ECFieldElement dx = X1.subtract(X2), dy = Y1.subtract(Y2);
+ // if (dx.isZero())
+ // {
+ // if (dy.isZero())
+ // {
+ // return twice();
+ // }
+ // return curve.getInfinity();
+ // }
+ //
+ // ECFieldElement C = dx.square();
+ // ECFieldElement W1 = X1.multiply(C), W2 = X2.multiply(C);
+ // ECFieldElement A1 = W1.subtract(W2).multiply(Y1);
+ //
+ // X3 = dy.square().subtract(W1).subtract(W2);
+ // Y3 = W1.subtract(X3).multiply(dy).subtract(A1);
+ // Z3 = dx;
+ //
+ // if (Z1IsOne)
+ // {
+ // Z3Squared = C;
+ // }
+ // else
+ // {
+ // Z3 = Z3.multiply(Z1);
+ // }
+ // }
+ // else
+ {
+ 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);
+
+ X3 = R.square().add(G).subtract(two(V));
+ Y3 = V.subtract(X3).multiply(R).subtract(S1.multiply(G));
+
+ Z3 = H;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.multiply(Z1);
+ }
+ if (!Z2IsOne)
+ {
+ Z3 = Z3.multiply(Z2);
+ }
+ }
+
+ ECFieldElement[] zs = new ECFieldElement[] { Z3 };
+
+ return new SecP256R1Point(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();
+ }
+
+ ECFieldElement X1 = this.x, Z1 = this.zs[0];
+
+ ECFieldElement Y1Squared = Y1.square();
+ ECFieldElement T = Y1Squared.square();
+
+ boolean Z1IsOne = Z1.isOne();
+
+ ECFieldElement Z1Squared = Z1IsOne ? Z1 : Z1.square();
+ ECFieldElement M = three(X1.add(Z1Squared).multiply(X1.subtract(Z1Squared)));
+ ECFieldElement S = four(Y1Squared.multiply(X1));
+
+ ECFieldElement X3 = M.square().subtract(two(S));
+ ECFieldElement Y3 = S.subtract(X3).multiply(M).subtract(eight(T));
+
+ ECFieldElement Z3 = two(Y1);
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.multiply(Z1);
+ }
+
+ return new SecP256R1Point(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);
+ }
+
+ protected ECFieldElement two(ECFieldElement x)
+ {
+ return x.add(x);
+ }
+
+ protected ECFieldElement three(ECFieldElement x)
+ {
+ return two(x).add(x);
+ }
+
+ protected ECFieldElement four(ECFieldElement x)
+ {
+ return two(two(x));
+ }
+
+ protected ECFieldElement eight(ECFieldElement x)
+ {
+ return four(two(x));
+ }
+
+ protected ECFieldElement doubleProductFromSquares(ECFieldElement a, ECFieldElement b, ECFieldElement aSquared,
+ ECFieldElement bSquared)
+ {
+ /*
+ * NOTE: If squaring in the field is faster than multiplication, then this is a quicker way
+ * to calculate 2.A.B, if A^2 and B^2 are already known.
+ */
+ return a.add(b).square().subtract(aSquared).subtract(bSquared);
+ }
+
+ // 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 SecP256R1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression);
+ }
+}
diff --git a/core/src/test/java/org/bouncycastle/math/ec/test/ECPointPerformanceTest.java b/core/src/test/java/org/bouncycastle/math/ec/test/ECPointPerformanceTest.java
index 7e8a7f29..95acfb60 100644
--- a/core/src/test/java/org/bouncycastle/math/ec/test/ECPointPerformanceTest.java
+++ b/core/src/test/java/org/bouncycastle/math/ec/test/ECPointPerformanceTest.java
@@ -9,10 +9,11 @@ import org.bouncycastle.asn1.x9.ECNamedCurveTable;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.ec.custom.CustomNamedCurves;
/**
- * Compares the performance of the the window NAF point multiplication against
- * conventional point multiplication.
+ * Compares the performance of the the window NAF point multiplication against conventional point
+ * multiplication.
*/
public class ECPointPerformanceTest extends TestCase
{
@@ -22,17 +23,31 @@ public class ECPointPerformanceTest extends TestCase
private static String[] COORD_NAMES = new String[]{ "AFFINE", "HOMOGENEOUS", "JACOBIAN", "JACOBIAN-CHUDNOVSKY",
"JACOBIAN-MODIFIED", "LAMBDA-AFFINE", "LAMBDA-PROJECTIVE", "SKEWED" };
- private void randMult(final String curveName) throws Exception
+ private void randMult(String curveName) throws Exception
{
X9ECParameters spec = ECNamedCurveTable.getByName(curveName);
+ if (spec != null)
+ {
+ randMult(curveName, spec);
+ }
+
+ spec = CustomNamedCurves.getByName(curveName);
+ if (spec != null)
+ {
+ randMult(curveName + " (custom)", spec);
+ }
+ }
+
+ private void randMult(String label, X9ECParameters spec) throws Exception
+ {
ECCurve C = spec.getCurve();
- ECPoint G = (ECPoint) spec.getG();
+ ECPoint G = (ECPoint)spec.getG();
BigInteger n = spec.getN();
SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
random.setSeed(System.currentTimeMillis());
- System.out.println(curveName);
+ System.out.println(label);
int[] coords = ECCurve.getAllCoordinateSystems();
for (int i = 0; i < coords.length; ++i)
@@ -100,18 +115,17 @@ public class ECPointPerformanceTest extends TestCase
}
long endTime = System.currentTimeMillis();
- return (double) (endTime - startTime) / NUM_ROUNDS;
+ return (double)(endTime - startTime) / NUM_ROUNDS;
}
public void testMultiply() throws Exception
{
-// Enumeration e = SECNamedCurves.getNames();
-// while (e.hasMoreElements())
-// {
-// String name = (String)e.nextElement();
-// randMult(name);
-// }
-
+ // Enumeration e = SECNamedCurves.getNames();
+ // while (e.hasMoreElements())
+ // {
+ // String name = (String)e.nextElement();
+ // randMult(name);
+ // }
randMult("sect113r1");
randMult("sect113r2");
@@ -147,7 +161,7 @@ public class ECPointPerformanceTest extends TestCase
randMult("secp256r1");
randMult("secp384r1");
randMult("secp521r1");
-
+
randMult("brainpoolp160r1");
randMult("brainpoolp160t1");
randMult("brainpoolp192r1");
@@ -162,6 +176,30 @@ public class ECPointPerformanceTest extends TestCase
randMult("brainpoolp384t1");
randMult("brainpoolp512r1");
randMult("brainpoolp512t1");
+
+ randMult("prime192v1");
+ randMult("prime192v2");
+ randMult("prime192v3");
+ randMult("prime239v1");
+ randMult("prime239v2");
+ randMult("prime239v3");
+ randMult("prime256v1");
+ randMult("c2pnb163v1");
+ randMult("c2pnb163v2");
+ randMult("c2pnb163v3");
+ randMult("c2pnb176w1");
+ randMult("c2tnb191v1");
+ randMult("c2tnb191v2");
+ randMult("c2tnb191v3");
+ randMult("c2pnb208w1");
+ randMult("c2tnb239v1");
+ randMult("c2tnb239v2");
+ randMult("c2tnb239v3");
+ randMult("c2pnb272w1");
+ randMult("c2pnb304w1");
+ randMult("c2tnb359v1");
+ randMult("c2pnb368w1");
+ randMult("c2tnb431r1");
}
// public static void main(String argv[]) throws Exception
diff --git a/core/src/test/java/org/bouncycastle/math/ec/test/ECPointTest.java b/core/src/test/java/org/bouncycastle/math/ec/test/ECPointTest.java
index 51244ad3..525bd1c3 100644
--- a/core/src/test/java/org/bouncycastle/math/ec/test/ECPointTest.java
+++ b/core/src/test/java/org/bouncycastle/math/ec/test/ECPointTest.java
@@ -12,6 +12,7 @@ import org.bouncycastle.asn1.sec.SECNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.ec.custom.CustomNamedCurves;
/**
* Test class for {@link org.bouncycastle.math.ec.ECPoint ECPoint}. All
@@ -413,6 +414,24 @@ public class ECPointTest extends TestCase
assertPointsEqual("Error decoding compressed point", p, decComp);
}
+ private void implAddSubtractMultiplyTwiceEncodingTest(X9ECParameters x9ECParameters)
+ {
+ BigInteger n = x9ECParameters.getN();
+
+ // The generator is multiplied by random b to get random q
+ BigInteger b = new BigInteger(n.bitLength(), secRand);
+ ECPoint g = x9ECParameters.getG();
+ ECPoint q = g.multiply(b).normalize();
+
+ // Get point at infinity on the curve
+ ECPoint infinity = x9ECParameters.getCurve().getInfinity();
+
+ implTestAddSubtract(q, infinity);
+ implTestMultiply(q, n.bitLength());
+ implTestMultiply(infinity, n.bitLength());
+ implTestEncoding(q);
+ }
+
/**
* Calls <code>implTestAddSubtract()</code>,
* <code>implTestMultiply</code> and <code>implTestEncoding</code> for
@@ -424,22 +443,15 @@ public class ECPointTest extends TestCase
while (curveEnum.hasMoreElements())
{
String name = (String) curveEnum.nextElement();
- X9ECParameters x9ECParameters = SECNamedCurves.getByName(name);
-
- BigInteger n = x9ECParameters.getN();
-
- // The generator is multiplied by random b to get random q
- BigInteger b = new BigInteger(n.bitLength(), secRand);
- ECPoint g = x9ECParameters.getG();
- ECPoint q = g.multiply(b).normalize();
- // Get point at infinity on the curve
- ECPoint infinity = x9ECParameters.getCurve().getInfinity();
+ X9ECParameters x9ECParameters = SECNamedCurves.getByName(name);
+ implAddSubtractMultiplyTwiceEncodingTest(x9ECParameters);
- implTestAddSubtract(q, infinity);
- implTestMultiply(q, n.bitLength());
- implTestMultiply(infinity, n.bitLength());
- implTestEncoding(q);
+ x9ECParameters = CustomNamedCurves.getByName(name);
+ if (x9ECParameters != null)
+ {
+ implAddSubtractMultiplyTwiceEncodingTest(x9ECParameters);
+ }
}
}