more-speech/java/schnorr/Point.java

200 lines
5.7 KiB
Java

package schnorr;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class Point {
final static private BigInteger p = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16);
final static private BigInteger n = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16);
final static public Point G = new Point(
new BigInteger("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16),
new BigInteger("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16)
);
private static final BigInteger BI_TWO = BigInteger.valueOf(2);
private final Pair<BigInteger,BigInteger> pair;
public Point(BigInteger x , BigInteger y) {
pair = Pair.of(x, y);
}
public Point(byte[] b0, byte[] b1) {
pair = Pair.of(new BigInteger(1, b0), new BigInteger(1, b1));
}
public static BigInteger getp() {
return p;
}
public static BigInteger getn() {
return n;
}
public static Point getG() {
return G;
}
public BigInteger getX() {
return pair.getLeft();
}
public BigInteger getY() {
return pair.getRight();
}
public static BigInteger getX(Point P) {
assert !P.isInfinite();
return P.getX();
}
public static BigInteger getY(Point P) {
assert !P.isInfinite();
return P.getY();
}
public Pair<BigInteger,BigInteger> getPair() {
return pair;
}
public boolean isInfinite() {
return pair == null || pair.getLeft() == null || pair.getRight() == null;
}
public static boolean isInfinite(Point P) {
return P.isInfinite();
}
public Point add(Point P) {
return add(this, P);
}
public static Point add(Point P1, Point P2) {
if((P1 != null && P2 != null && P1.isInfinite() && P2.isInfinite())) {
return infinityPoint();
}
if(P1 == null || P1.isInfinite()) {
return P2;
}
if(P2 == null || P2.isInfinite()) {
return P1;
}
if(P1.getX().equals(P2.getX()) && !P1.getY().equals(P2.getY())) {
return infinityPoint();
}
BigInteger lam;
if(P1.equals(P2)) {
BigInteger base = P2.getY().multiply(BI_TWO);
lam = (BigInteger.valueOf(3L).multiply(P1.getX()).multiply(P1.getX()).multiply(base.modPow(p.subtract(BI_TWO), p))).mod(p);
}
else {
BigInteger base = P2.getX().subtract(P1.getX());
lam = ((P2.getY().subtract(P1.getY())).multiply(base.modPow(p.subtract(BI_TWO), p))).mod(p);
}
BigInteger x3 = (lam.multiply(lam).subtract(P1.getX()).subtract(P2.getX())).mod(p);
return new Point(x3, lam.multiply(P1.getX().subtract(x3)).subtract(P1.getY()).mod(p));
}
public Point mul(BigInteger n) {
return mul(this, n);
}
public static Point mul(Point P, BigInteger n) {
Point R = null;
for(int i = 0; i < 256; i++) {
if (n.shiftRight(i).and(BigInteger.ONE).compareTo(BigInteger.ZERO) > 0) {
R = add(R, P);
}
P = add(P, P);
}
return R;
}
public boolean hasEvenY() {
return hasEvenY(this);
}
public static boolean hasEvenY(Point P) {
return P.getY().mod(BI_TWO).compareTo(BigInteger.ZERO) == 0;
}
public static boolean isSquare(BigInteger x) {
return x.modPow(p.subtract(BigInteger.ONE).mod(BI_TWO), p).longValue() == 1L;
}
public boolean hasSquareY() {
return hasSquareY(this);
}
public static boolean hasSquareY(Point P) {
assert !isInfinite(P);
return isSquare(P.getY());
}
public static byte[] taggedHash(String tag, byte[] msg) throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] tagHash = Util.sha256(tag.getBytes());
int len = (tagHash.length * 2) + msg.length;
byte[] buf = new byte[len];
System.arraycopy(tagHash, 0, buf, 0, tagHash.length);
System.arraycopy(tagHash, 0, buf, tagHash.length, tagHash.length);
System.arraycopy(msg, 0, buf, tagHash.length * 2, msg.length);
return Util.sha256(buf);
}
public static byte[] genPubKey(byte[] secKey) throws Exception {
BigInteger x = Util.bigIntFromBytes(secKey);
if(!(BigInteger.ONE.compareTo(x) <= 0 && x.compareTo(getn().subtract(BigInteger.ONE)) <= 0)) {
throw new Exception("The secret key must be an integer in the range 1..n-1.");
}
Point ret = Point.mul(G, x);
return bytesFromPoint(ret);
}
public byte[] toBytes() {
return bytesFromPoint(this);
}
public static byte[] bytesFromPoint(Point P) {
return Util.bytesFromBigInteger(P.getX());
}
// previously 'pointFromBytes()'
public static Point liftX(byte[] b) {
BigInteger x = Util.bigIntFromBytes(b);
if(x.compareTo(p) >= 0) {
return null;
}
BigInteger y_sq = x.modPow(BigInteger.valueOf(3L), p).add(BigInteger.valueOf(7L)).mod(p);
BigInteger y = y_sq.modPow(p.add(BigInteger.ONE).divide(BigInteger.valueOf(4L)), p);
if(y.modPow(BI_TWO, p).compareTo(y_sq) != 0) {
return null;
}
else {
return new Point(x, y.and(BigInteger.ONE).compareTo(BigInteger.ZERO) == 0 ? y : p.subtract(y));
}
}
public static Point infinityPoint() {
return new Point(null, (BigInteger) null);
}
public boolean equals(Point P) {
return getPair().equals(P.getPair());
}
}