Custom Java public key generation (Bitcoin)

podludek :

A private key is random generated and it is not correlated with any wallet.

I want to prepare custom (naive) implementation of public key generation for a Bitcoin. However, after a few attempts my results was incorrect. I compared them with online generators. I've recognized I used division instead of modinv. Unfortunately, after changing division into modinv I got "java.lang.ArithmeticException: BigInteger not invertible.". I tired to follow https://www.mobilefish.com/services/cryptocurrency/cryptocurrency.html#refProdedure and https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication Could you help me recognize where I did a mistake?

public class ECDSAUtils {

    private static final CurvePoint G = new CurvePoint(new BigInteger("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16), new BigInteger("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16));
    private static CurvePoint zero;
    private static BigInteger base;
    private static final BigInteger three = new BigInteger("3", 10);

    public static void main(String[] args){
        ECDSAUtils e = new ECDSAUtils();
        BigInteger privateKey = new BigInteger("fdc668381ab251673ef8552851a2c7cf346a6e09ea86be0f55a94d2a12253557", 16);
        CurvePoint r = e.mult(G, privateKey);
        System.out.println(r.x.toString(16).toUpperCase() + " " + r.y.toString(16).toUpperCase());
    }

    public ECDSAUtils(){
        zero = new CurvePoint(new BigInteger("0", 16), new BigInteger("0", 16));
        base = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16);
    }

    public static CurvePoint add(CurvePoint p, CurvePoint q){
        CurvePoint result = null;
        if (p.equals(zero)){
            result = q;
        } else if (q.equals(zero)){
            result = p;
        } else {
            BigInteger lambda = q.y.subtract(p.y).modInverse(q.x.subtract(p.x)).mod(base);
            BigInteger x = lambda.multiply(lambda).subtract(p.x).subtract(q.x).mod(base);
            BigInteger y = lambda.multiply(p.x.subtract(x)).subtract(p.y).mod(base);
            result = new CurvePoint(x, y);
        }
        return result;
    }

    public static CurvePoint doublePoint(CurvePoint p){
        BigInteger lambda = p.x.multiply(p.x).multiply(three).modInverse(p.y.add(p.y)).mod(base);
        BigInteger x = lambda.multiply(lambda).subtract(p.x).subtract(p.x).mod(base);
        BigInteger y = lambda.multiply(p.x.subtract(x)).subtract(p.y).mod(base);
        return new CurvePoint(x, y);
    }

    public CurvePoint mult(CurvePoint N, BigInteger p) {
        CurvePoint Q = zero;
//EDIT:
        for (int i = p.bitLength() - 1; i > -1; i --) {
            if (p.testBit(i)) {
                Q = add(Q, N);
            }
            N = doublePoint(N);
        }

        return Q;
    }
}

public class CurvePoint {
    BigInteger x;
    BigInteger y;

    public CurvePoint(BigInteger x, BigInteger y) {
        this.x = x;
        this.y = y;
    }
}

Exception in thread "main" java.lang.ArithmeticException: BigInteger not invertible.
    at java.math.MutableBigInteger.mutableModInverse(MutableBigInteger.java:1986)
    at java.math.BigInteger.modInverse(BigInteger.java:3154)
    at naive.ECDSAUtils.doublePoint(ECDSAUtils.java:41)
    at naive.ECDSAUtils.mult(ECDSAUtils.java:51)
    at naive.ECDSAUtils.main(ECDSAUtils.java:15)
Topaco :
  • Currently the expression

    is coded as follows:

    y.modInverse(x).mod(p)
    

    This is wrong and causes the observed error message. The following applies:

    which must be coded as follows:

    y.multiply(x.modInverse(p)).mod(p)
    
  • In the add method, the case:

    is not handled. Here, the add method must return zero (i.e. the point representing the point at infinity). Geometrically, this case corresponds to a vertical secant (2 intersections).

  • Analogously, the case

    is not handled in the doublePoint method. Here, the doublePoint method must return zero as well. Geometrically, this case corresponds to a vertical tangent (1 intersection).

  • The mult method doesn't work. But with regard to the comment in the code this is probably known.

  • Testing is easier if a small prime finite field is used. Here you can specify elliptical curves and determine the corresponding points. Note, that a curve with b != 0 must be used, otherwise the point (0,0) is a regular point of the curve and could not be used as a representative of the point at infinity.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=125512&siteId=1