/* This file is part of Wattzap Community Edition.
*
* Wattzap Community Edtion is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Wattzap Community Edition is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Wattzap. If not, see <http://www.gnu.org/licenses/>.
*/
package ecc.elliptic;
import java.math.BigInteger;
public class ECPoint {
public final static BigInteger TWO = new BigInteger("2");
public final static BigInteger THREE = new BigInteger("3");
private EllipticCurve mother;
private BigInteger x, y;
private boolean iszero;
private ECPoint[] fastcache = null;
private ECPoint[] cache = null;
public void fastCache() {
try {
if (fastcache == null) {
fastcache = new ECPoint[256];
fastcache[0] = new ECPoint(mother);
for (int i = 1; i < fastcache.length; i++) {
fastcache[i] = fastcache[i - 1].add(this);
}
}
} catch (NoCommonMotherException e) {
System.out.println("ECPoint.fastcache: THIS CANNOT HAPPEN!!!");
}
}
/**
* Constructs a point on an elliptic curve.
*
* @param mother
* The elliptic curve on wich the point is surposed to lie
* @param x
* the x coordinate of the point
* @param y
* the y coordinate of the point
* @exception Throws
* a NotOnMotherException if (x,y) is not on the mother
* curve.
*/
public ECPoint(EllipticCurve mother, BigInteger x, BigInteger y)
throws NotOnMotherException {
this.mother = mother;
this.x = x;
this.y = y;
if (!mother.onCurve(this))
throw new NotOnMotherException(this);
iszero = false;
}
/**
* Decompresses a compressed point stored in a byte-array into a new
* ECPoint.
*
* @param bytes
* the array of bytes to be decompressed
* @param mother
* the EllipticCurve the decompressed point is supposed to lie
* on.
*/
public ECPoint(byte[] bytes, EllipticCurve mother) {
this.mother = mother;
if (bytes[0] == 2) {
iszero = true;
return;
}
boolean ymt = false;
if (bytes[0] != 0)
ymt = true;
bytes[0] = 0;
x = new BigInteger(bytes);
if (mother.getPPODBF() == null)
System.out.println("Fuck dig!!!");
y = x.multiply(x).add(mother.geta()).multiply(x).add(mother.getb())
.modPow(mother.getPPODBF(), mother.getp());
if (ymt != y.testBit(0)) {
y = mother.getp().subtract(y);
}
iszero = false;
}
/**
* IMPORTANT this renders the values of x and y to be null! Use this
* constructor only to create instances of a Zero class!
*/
public ECPoint(EllipticCurve e) {
x = y = BigInteger.ZERO;
mother = e;
iszero = true;
}
public byte[] compress() {
byte[] cmp = new byte[mother.getPCS()];
if (iszero) {
cmp[0] = 2;
}
byte[] xb = x.toByteArray();
System.arraycopy(xb, 0, cmp, mother.getPCS() - xb.length, xb.length);
if (y.testBit(0))
cmp[0] = 1;
return cmp;
}
/**
* Adds another elliptic curve point to this point.
*
* @param q
* The point to be added
* @return the sum of this point on the argument
* @exception Throws
* a NoCommonMotherException if the two points don't lie on
* the same elliptic curve.
*/
public ECPoint add(ECPoint q) throws NoCommonMotherException {
if (!hasCommonMother(q))
throw new NoCommonMotherException();
if (this.iszero)
return q;
else if (q.isZero())
return this;
BigInteger y1 = y;
BigInteger y2 = q.gety();
BigInteger x1 = x;
BigInteger x2 = q.getx();
BigInteger alpha;
if (x2.compareTo(x1) == 0) {
if (!(y2.compareTo(y1) == 0))
return new ECPoint(mother);
else {
alpha = ((x1.modPow(TWO, mother.getp())).multiply(THREE))
.add(mother.geta());
alpha = (alpha.multiply((TWO.multiply(y1)).modInverse(mother
.getp()))).mod(mother.getp());
}
} else {
alpha = ((y2.subtract(y1)).multiply((x2.subtract(x1))
.modInverse(mother.getp()))).mod(mother.getp());
}
BigInteger x3, y3;
x3 = (((alpha.modPow(TWO, mother.getp())).subtract(x2)).subtract(x1))
.mod(mother.getp());
y3 = ((alpha.multiply(x1.subtract(x3))).subtract(y1))
.mod(mother.getp());
try {
return new ECPoint(mother, x3, y3);
} catch (NotOnMotherException e) {
System.out.println("Error in add!!! Result not on mother!");
return null;
}
}
public ECPoint multiply(BigInteger coef) {
try {
ECPoint result = new ECPoint(mother);
byte[] coefb = coef.toByteArray();
if (fastcache != null) {
for (int i = 0; i < coefb.length; i++) {
result = result.times256().add(fastcache[coefb[i] & 255]);
}
return result;
}
if (cache == null) {
cache = new ECPoint[16];
cache[0] = new ECPoint(mother);
for (int i = 1; i < cache.length; i++) {
cache[i] = cache[i - 1].add(this);
}
}
for (int i = 0; i < coefb.length; i++) {
result = result.times16().add(cache[(coefb[i] >> 4) & 15])
.times16().add(cache[coefb[i] & 15]);
}
return result;
} catch (NoCommonMotherException e) {
System.out.println("Error in pow!!!");
return null;
}
}
private ECPoint times16() {
try {
ECPoint result = this;
for (int i = 0; i < 4; i++) {
result = result.add(result);
}
return result;
} catch (Exception e) {
System.out.println("ECPoint.times16: THIS CANNOT HAPPEN!!!");
return null;
}
}
private ECPoint times256() {
try {
ECPoint result = this;
for (int i = 0; i < 8; i++) {
result = result.add(result);
}
return result;
} catch (Exception e) {
System.out.println("ECPoint.times256: THIS CANNOT HAPPEN!!!");
return null;
}
}
public BigInteger getx() {
return x;
}
public BigInteger gety() {
return y;
}
public EllipticCurve getMother() {
return mother;
}
public String toString() {
return "(" + x.toString() + ", " + y.toString() + ")";
}
public boolean hasCommonMother(ECPoint p) {
if (this.mother.equals(p.getMother()))
return true;
else
return false;
}
public boolean isZero() {
return iszero;
}
}