【问题标题】:Custom Java public key generation (Bitcoin)自定义 Java 公钥生成(比特币)
【发布时间】:2019-07-17 09:35:26
【问题描述】:

私钥是随机生成的,与任何钱包无关。

我想为比特币准备公钥生成的自定义(简单)实现。然而,经过几次尝试,我的结果是不正确的。我将它们与在线生成器进行了比较。我已经认识到我使用除法而不是 modinv。不幸的是,在将除法更改为 modinv 后,我得到了“java.lang.ArithmeticException:BigInteger not invertible.”。我厌倦了关注https://www.mobilefish.com/services/cryptocurrency/cryptocurrency.html#refProdedurehttps://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication 你能帮我找出我做错的地方吗?

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)

【问题讨论】:

  • 所以你的目标是手动实现椭圆曲线的加、倍、乘?另外,CurvePoint 是什么?
  • 是的,一般来说,我想实现使用 secp256k1 生成公钥的过程,我想以清晰、易读的方式逐步完成。
  • public class CurvePoint { BigInteger x; BigInteger y; public CurvePoint(BigInteger x, BigInteger y) { this.x = x; this.y = y; } }
  • 您的 p 值不正确,它不是 secp256k1 素数。事实上,它甚至不是素数!
  • p 是我代码中的私钥。字段的基础是“base” var。我会编辑它。

标签: java encryption bitcoin public-key encryption-asymmetric


【解决方案1】:
  • 当前表达式

    编码如下:

     y.modInverse(x).mod(p)
    

    这是错误的,会导致观察到的错误消息。以下适用:

    必须编码如下:

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

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

  • 类似情况

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

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

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

【讨论】:

  • Seminitpick:如果 Px=Qx mod p 和 Py=-Qy 同上,则对于 Weierstrass E(Fp) 加法(等效于 Px!=Qx,因为给定 x 的可能 y 必须是加法逆元) ) 那么结果就是 PAI;而如果 Py=Qy 则必须使用加倍公式。但是对于这里预期的私钥小于 n 的双加乘法,不会出现 Py=Qy 的情况。
猜你喜欢
  • 2021-12-25
  • 2013-07-14
  • 1970-01-01
  • 1970-01-01
  • 2019-05-16
  • 1970-01-01
  • 2023-03-13
  • 2014-01-17
  • 2020-06-02
相关资源
最近更新 更多