public static Point addition(Point p, Point q){
	
		Point r = new Point();
		BigInteger lambda = BigInteger.ZERO;
		
		if(!(p.getX().equals(q.getX()))){
			lambda = (p.getY().subtract(q.getY()).mod(Main.ellipticCurve.getP())).multiply((p.getX().subtract(q.getX()).mod(Main.ellipticCurve.getP())).modInverse(Main.ellipticCurve.getP()));
			r.setX(lambda.modPow(new BigInteger("2"), Main.ellipticCurve.getP()).subtract(p.getX()).mod(Main.ellipticCurve.getP()).subtract(q.getX()).mod(Main.ellipticCurve.getP()));
			r.setY(lambda.negate().multiply(r.getX()).mod(Main.ellipticCurve.getP()).add(lambda.multiply(p.getX()).mod(Main.ellipticCurve.getP())).mod(Main.ellipticCurve.getP()).subtract(p.getY()).mod(Main.ellipticCurve.getP()));
		}

		// Point at infinite
		else if(p.getX().equals(q.getX()) && !(p.getY().equals(q.getY()))){
			r.setX(BigInteger.ZERO);
			r.setY(BigInteger.ZERO);
			r.setIsInfinite(true);
		}
		
		else if(p.getX().equals(q.getX()) && p.getY().equals(q.getY()) && !(p.getY().equals(BigInteger.ZERO))){
			lambda = (new BigInteger("3").multiply(p.getX().modPow(new BigInteger("2"), Main.ellipticCurve.getP())).mod(Main.ellipticCurve.getP()).add(Main.ellipticCurve.getA4()).mod(Main.ellipticCurve.getP())).multiply(p.getY().multiply(new BigInteger("2")).modInverse(Main.ellipticCurve.getP())).mod(Main.ellipticCurve.getP());
			r.setX(lambda.modPow(new BigInteger("2"), Main.ellipticCurve.getP()).subtract(p.getX()).mod(Main.ellipticCurve.getP()).subtract(q.getX()).mod(Main.ellipticCurve.getP()));
			r.setY(lambda.negate().multiply(r.getX()).mod(Main.ellipticCurve.getP()).add(lambda.multiply(p.getX()).mod(Main.ellipticCurve.getP())).subtract(p.getY()).mod(Main.ellipticCurve.getP()));
		}
		
		// Point at infinite
		else if(p.getX().equals(q.getX()) && p.getY().equals(q.getY()) && p.getY().equals(BigInteger.ZERO)){
			r.setX(BigInteger.ZERO);
			r.setY(BigInteger.ZERO);
			r.setIsInfinite(true);
		}
		
		return r;
	}