自定义Java公钥生成(比特币)

自定义Java公钥生成(比特币),java,encryption,bitcoin,public-key,encryption-asymmetric,Java,Encryption,Bitcoin,Public Key,Encryption Asymmetric,私钥是随机生成的,它与任何钱包都不相关 我想为比特币准备公钥生成的定制(简单)实现。然而,经过几次尝试,我的结果是不正确的。我将它们与在线生成器进行了比较。我认识到我用除法而不是modinv。不幸的是,在将除法改为modinv之后,我得到了“java.lang.arithmetricException:BigInteger不可逆”。我跟不上了,你能帮我认清哪里出了错吗 public class ECDSAUtils { private static final CurvePoint G

私钥是随机生成的,它与任何钱包都不相关

我想为比特币准备公钥生成的定制(简单)实现。然而,经过几次尝试,我的结果是不正确的。我将它们与在线生成器进行了比较。我认识到我用除法而不是modinv。不幸的是,在将除法改为modinv之后,我得到了“java.lang.arithmetricException:BigInteger不可逆”。我跟不上了,你能帮我认清哪里出了错吗

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;
    }
}

  • 当前的表达式

    代码如下:

     y.modInverse(x).mod(p)
    
     y.multiply(x.modInverse(p)).mod(p)
    
    这是错误的,并导致观察到的错误消息。以下规定适用:

    必须按照以下方式对其进行编码:

     y.modInverse(x).mod(p)
    
     y.multiply(x.modInverse(p)).mod(p)
    
  • add
    方法中,案例:

    没有处理。这里,
    add
    方法必须返回
    zero
    (即表示无穷远处点的点)。几何上,这种情况对应于垂直割线(2个交点)

  • 类似地,情况也是如此

    未在
    双点
    方法中处理。这里,
    doublePoint
    方法也必须返回
    zero
    。在几何上,这种情况对应于一个垂直切线(1个交点)

  • mult
    方法不起作用。但是关于代码中的注释,这可能是已知的

  • 如果使用一个小的素数有限域,则测试更容易。可以指定椭圆曲线并确定相应的点。请注意,
    b!=必须使用0,否则点
    (0,0)
    是曲线的规则点,不能用作无穷远处点的代表


您的目标是手动实现椭圆曲线加法、倍增和乘法?另外,什么是
CurvePoint
?是的,一般来说,我想使用secp256k1实现生成公钥的过程,我想以清晰、易读的方式一步一步地完成。
public class CurvePoint{biginger x;biginger y;public CurvePoint(biginger x,biginger y){this.x=x;this.y=y;}
您的
p
值不正确,它不是secp256k1素数。事实上,它甚至都不是黄金!p是我代码中的私钥。字段的基是“基”变量。我将对其进行编辑。Seminitpick:对于Weierstrass E(Fp)加法,一般来说,如果Px=Qx mod p,Py=-Qy同上(相当于Px!=Qx,因为给定x的可能y必须是加法倒数),则结果是PAI;而如果Py=Qy,则必须使用加倍公式。但是对于此处预期的privatekey小于n的double和add乘法,不会出现Py=Qy的情况。