All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.eosif.lib.ecc.Point Maven / Gradle / Ivy

package io.eosif.lib.ecc;

import java.math.BigInteger;

/**
 * Point
 * 
 * @author espritblock  http://eblock.io
 *
 */
public class Point {

	private Curve curve;

	private FieldElement x;

	private FieldElement y;

	private boolean compressed;

	public Point(Curve curve, FieldElement x, FieldElement y, boolean compressed) {
		this.curve = curve;
		this.x = x;
		this.y = y;
		this.compressed = compressed;
	}

	public Point(Curve curve, FieldElement x, FieldElement y) {
		this(curve, x, y, true);
	}

	public Curve getCurve() {
		return curve;
	}

	public FieldElement getX() {
		return x;
	}

	public FieldElement getY() {
		return y;
	}

	public boolean isInfinity() {
		return x == null && y == null;
	}

	public boolean isCompressed() {
		return compressed;
	}

	public byte[] getEncoded() {

		if (this.isInfinity()) {
			return new byte[1];
		}

		int length = getByteLength(x.getFieldSize());

		if (compressed) {
			byte PC;
			if (this.getY().toBigInteger().testBit(0)) {
				PC = 0x03;
			} else {
				PC = 0x02;
			}
			byte[] X = integerToBytes(this.getX().toBigInteger(), length);
			byte[] PO = new byte[X.length + 1];
			PO[0] = PC;
			System.arraycopy(X, 0, PO, 1, X.length);
			return PO;
		} else {
			byte[] X = integerToBytes(this.getX().toBigInteger(), length);
			byte[] Y = integerToBytes(this.getY().toBigInteger(), length);
			byte[] PO = new byte[X.length + Y.length + 1];
			PO[0] = 0x04;
			System.arraycopy(X, 0, PO, 1, X.length);
			System.arraycopy(Y, 0, PO, X.length + 1, Y.length);
			return PO;
		}
	}

	public Point add(Point b) {
		if (this.isInfinity()) {
			return b;
		}
		if (b.isInfinity()) {
			return this;
		}
		if (this.x.equals(b.x)) {
			if (this.y.equals(b.y)) {
				return this.twice();
			}
			return this.curve.getInfinity();
		}
		FieldElement gamma = b.y.subtract(this.y).divide(b.x.subtract(this.x));
		FieldElement x3 = gamma.square().subtract(this.x).subtract(b.x);
		FieldElement y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
		return new Point(curve, x3, y3);
	}

	public Point twice() {
		if (this.isInfinity()) {
			return this;
		}
		if (this.y.toBigInteger().signum() == 0) {
			return this.curve.getInfinity();
		}
		FieldElement TWO = this.curve.fromBigInteger(BigInteger.valueOf(2));
		FieldElement THREE = this.curve.fromBigInteger(BigInteger.valueOf(3));
		FieldElement gamma = this.x.square().multiply(THREE).add(curve.getA()).divide(y.multiply(TWO));
		FieldElement x3 = gamma.square().subtract(this.x.multiply(TWO));
		FieldElement y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
		return new Point(curve, x3, y3, this.compressed);
	}

	public Point subtract(Point b) {
		if (b.isInfinity()) {
			return this;
		}
		return add(b.negate());
	}

	public Point negate() {
		return new Point(curve, this.x, this.y.negate(), this.compressed);
	}

	public Point multiply(BigInteger k) {
		BigInteger e = k;
		BigInteger h = e.multiply(BigInteger.valueOf(3));
		Point neg = this.negate();
		Point R = this;
		for (int i = h.bitLength() - 2; i > 0; --i) {
			R = R.twice();
			boolean hBit = h.testBit(i);
			boolean eBit = e.testBit(i);
			if (hBit != eBit) {
				R = R.add(hBit ? this : neg);
			}
		}
		return R;
	}

	public Point multiplyTwo(BigInteger j, Point x, BigInteger k) {
		int i = Math.max(j.bitLength(), k.bitLength()) - 1;
		Point R = this.curve.getInfinity();
		Point both = this.add(x);
		while (i >= 0) {
			Boolean jBit = j.testBit(i);
			Boolean kBit = k.testBit(i);

			R = R.twice();

			if (jBit) {
				if (kBit) {
					R = R.add(both);
				} else {
					R = R.add(this);
				}
			} else if (kBit) {
				R = R.add(x);
			}
			--i;
		}
		return R;
	}

	public static int getByteLength(int fieldSize) {
		return (fieldSize + 7) / 8;
	}

	public static byte[] integerToBytes(BigInteger s, int length) {
		byte[] bytes = s.toByteArray();
		if (length < bytes.length) {
			byte[] tmp = new byte[length];
			System.arraycopy(bytes, bytes.length - tmp.length, tmp, 0, tmp.length);
			return tmp;
		} else if (length > bytes.length) {
			byte[] tmp = new byte[length];
			System.arraycopy(bytes, 0, tmp, tmp.length - bytes.length, bytes.length);
			return tmp;
		}
		return bytes;
	}

	@Override
	public boolean equals(Object other) {
		if (other == this) {
			return true;
		}

		if (!(other instanceof Point)) {
			return false;
		}

		Point o = (Point) other;

		if (this.isInfinity()) {
			return o.isInfinity();
		}

		return x.equals(o.x) && y.equals(o.y);
	}

	@Override
	public int hashCode() {
		if (this.isInfinity()) {
			return 0;
		}

		return x.hashCode() ^ y.hashCode();
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy