summaryrefslogtreecommitdiff
path: root/src/cz/crcs/ectester/common/util/ECUtil.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/cz/crcs/ectester/common/util/ECUtil.java')
-rw-r--r--src/cz/crcs/ectester/common/util/ECUtil.java172
1 files changed, 172 insertions, 0 deletions
diff --git a/src/cz/crcs/ectester/common/util/ECUtil.java b/src/cz/crcs/ectester/common/util/ECUtil.java
new file mode 100644
index 0000000..973b813
--- /dev/null
+++ b/src/cz/crcs/ectester/common/util/ECUtil.java
@@ -0,0 +1,172 @@
+package cz.crcs.ectester.common.util;
+
+import java.math.BigInteger;
+import java.security.spec.*;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class ECUtil {
+
+ public static byte[] toByteArray(BigInteger what, int bits) {
+ byte[] raw = what.toByteArray();
+ int bytes = (bits + 7) / 8;
+ if (raw.length < bytes) {
+ byte[] result = new byte[bytes];
+ System.arraycopy(raw, 0, result, bytes - raw.length, raw.length);
+ return result;
+ }
+ if (bytes < raw.length) {
+ byte[] result = new byte[bytes];
+ System.arraycopy(raw, raw.length - bytes, result, 0, bytes);
+ return result;
+ }
+ return raw;
+ }
+
+ public static byte[] toX962Compressed(ECPoint point, int bits) {
+ if (point.equals(ECPoint.POINT_INFINITY)) {
+ return new byte[]{0};
+ }
+ byte[] x = toByteArray(point.getAffineX(), bits);
+ byte marker = (byte) (0x02 | point.getAffineY().mod(BigInteger.valueOf(2)).byteValue());
+ return ByteUtil.concatenate(new byte[]{marker}, x);
+ }
+
+ public static byte[] toX962Compressed(ECPoint point, EllipticCurve curve) {
+ return toX962Compressed(point, curve.getField().getFieldSize());
+ }
+
+ public static byte[] toX962Compressed(ECPoint point, ECParameterSpec spec) {
+ return toX962Compressed(point, spec.getCurve());
+ }
+
+ public static byte[] toX962Uncompressed(ECPoint point, int bits) {
+ if (point.equals(ECPoint.POINT_INFINITY)) {
+ return new byte[]{0};
+ }
+ byte[] x = toByteArray(point.getAffineX(), bits);
+ byte[] y = toByteArray(point.getAffineY(), bits);
+ return ByteUtil.concatenate(new byte[]{0x04}, x, y);
+ }
+
+ public static byte[] toX962Uncompressed(ECPoint point, EllipticCurve curve) {
+ return toX962Uncompressed(point, curve.getField().getFieldSize());
+ }
+
+ public static byte[] toX962Uncompressed(ECPoint point, ECParameterSpec spec) {
+ return toX962Uncompressed(point, spec.getCurve());
+ }
+
+ public static byte[] toX962Hybrid(ECPoint point, int bits) {
+ if (point.equals(ECPoint.POINT_INFINITY)) {
+ return new byte[]{0};
+ }
+ byte[] x = toByteArray(point.getAffineX(), bits);
+ byte[] y = toByteArray(point.getAffineY(), bits);
+ byte marker = (byte) (0x06 | point.getAffineY().mod(BigInteger.valueOf(2)).byteValue());
+ return ByteUtil.concatenate(new byte[]{marker}, x, y);
+ }
+
+ public static byte[] toX962Hybrid(ECPoint point, EllipticCurve curve) {
+ return toX962Hybrid(point, curve.getField().getFieldSize());
+ }
+
+ public static byte[] toX962Hybrid(ECPoint point, ECParameterSpec spec) {
+ return toX962Hybrid(point, spec.getCurve());
+ }
+
+ private static boolean isResidue(BigInteger a, BigInteger p) {
+ BigInteger exponent = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2));
+ BigInteger result = a.modPow(exponent, p);
+ return result.intValueExact() == 1;
+ }
+
+ private static BigInteger modSqrt(BigInteger a, BigInteger p) {
+ BigInteger q = p.subtract(BigInteger.ONE);
+ int s = 0;
+ while (q.mod(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) {
+ q = q.divide(BigInteger.valueOf(2));
+ s++;
+ }
+
+ BigInteger z = BigInteger.ONE;
+ do {
+ z = z.add(BigInteger.ONE);
+ } while (isResidue(z, p));
+
+ BigInteger m = BigInteger.valueOf(s);
+ BigInteger c = z.modPow(q, p);
+ BigInteger t = a.modPow(q, p);
+ BigInteger rExponent = q.add(BigInteger.ONE).divide(BigInteger.valueOf(2));
+ BigInteger r = a.modPow(rExponent, p);
+
+ while (!t.equals(BigInteger.ONE)) {
+ int i = 0;
+ BigInteger exponent;
+ do {
+ exponent = BigInteger.valueOf(2).pow(++i);
+ } while (!t.modPow(exponent, p).equals(BigInteger.ONE));
+
+ BigInteger twoExponent = m.subtract(BigInteger.valueOf(i + 1));
+ BigInteger b = c.modPow(BigInteger.valueOf(2).modPow(twoExponent, p), p);
+ m = BigInteger.valueOf(i);
+ c = b.modPow(BigInteger.valueOf(2), p);
+ t = t.multiply(c).mod(p);
+ r = r.multiply(b).mod(p);
+ }
+ return r;
+ }
+
+ public static ECPoint fromX962(byte[] data, EllipticCurve curve) {
+ if (data == null) {
+ return null;
+ }
+ if (data[0] == 0x04 || data[0] == 0x06 || data[0] == 0x07) {
+ int len = (data.length - 1) / 2;
+ byte[] xbytes = new byte[len];
+ System.arraycopy(data, 1, xbytes, 0, len);
+ byte[] ybytes = new byte[len];
+ System.arraycopy(data, 1 + len, ybytes, 0, len);
+ return new ECPoint(new BigInteger(1, xbytes), new BigInteger(1, ybytes));
+ } else if (data[0] == 0x02 || data[0] == 0x03) {
+ if (curve == null) {
+ throw new IllegalArgumentException();
+ }
+ byte[] xbytes = new byte[data.length - 1];
+ System.arraycopy(data, 1, xbytes, 0, data.length - 1);
+ BigInteger x = new BigInteger(1, xbytes);
+ BigInteger a = curve.getA();
+ BigInteger b = curve.getB();
+
+ ECField field = curve.getField();
+ if (field instanceof ECFieldFp) {
+ BigInteger p = ((ECFieldFp) field).getP();
+ BigInteger alpha = x.modPow(BigInteger.valueOf(3), p);
+ alpha = alpha.add(x.multiply(a));
+ alpha = alpha.add(b);
+
+ BigInteger beta = modSqrt(alpha, p);
+ if (beta.getLowestSetBit() == 0) {
+ // rightmost bit is one
+ if (data[0] == 0x02) {
+ beta = beta.negate();
+ }
+ } else {
+ // rightmost bit is zero
+ if (data[0] == 0x03) {
+ beta = beta.negate();
+ }
+ }
+
+ return new ECPoint(x, beta);
+ } else if (field instanceof ECFieldF2m) {
+ //TODO
+ throw new UnsupportedOperationException();
+ }
+ return null;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+}