椭圆曲线乘法函数

时间:2017-07-16 21:33:25

标签: java cryptography multiplication elliptic-curve

我正在尝试为椭圆曲线创建自己的库。 有些事情有效,但有些事情没有。

要从私钥计算公钥,您应该将Generator Point与私钥相乘,然后得到另一个点:公钥Point(ECPoint = BigInteger * ECPoint)。

现在,我有一个私钥,我将它与Secp256k1曲线的Generator Point相乘。我得到一把钥匙,但这不是我应该得到的钥匙。

这是我的JAVA代码:

import java.math.BigInteger;

public class Point{

    public static final Point INFINITY = new Point();

    private final BigInteger x;
    private final BigInteger y;

    private Point(){
        this.x = null;
        this.y = null;
    }

    public Point(BigInteger x,BigInteger y){
        if(x==null || y==null){
            throw new NullPointerException("x or y is null");
        }
        this.x = x;
        this.y = y;
    }

    public BigInteger getX(){
        return this.x;
    }

    public BigInteger getY(){
        return this.y;
    }

    public boolean isInfinite(){
        return this.x==null || this.y==null;
    }

    public Point add(Curve ec,Point Q){
        Point P = this;

        if(P.isInfinite()){
            return Q;
        }
        if(Q.isInfinite()){
            return P;
        }
        if(P.getX().equals(Q.getX()) && P.getY().equals(Q.getY())){
            return this.twice(ec);
        }

        BigInteger lambda = Q.getY().subtract(P.getY()).divide(Q.getX().subtract(P.getX()));

        BigInteger xR = lambda.pow(2).subtract(P.getX()).subtract(Q.getX());
        BigInteger yR = lambda.multiply(P.getX().subtract(xR)).subtract(P.getY());

        Point R = new Point(xR,yR);

        return R;
    }

    public Point twice(Curve ec){
        if(this.isInfinite()){
            return this;
        }

        BigInteger lambda = BigInteger.valueOf(3).multiply(this.getX().pow(2)).add(ec.getA()).divide(BigInteger.valueOf(2).multiply(this.getY()));

        BigInteger xR = lambda.pow(2).subtract(this.getX()).subtract(this.getX());
        BigInteger yR = lambda.multiply(this.getX().subtract(xR)).subtract(this.getY());

        Point R = new Point(xR,yR);

        return R;
    }

    public Point multiply(Curve ec,BigInteger k){
        //Point P = this;
        //Point R = Point.INFINITY;

        if(this.isInfinite()){
            return this;
        }

        if(k.signum()==0){
            return Point.INFINITY;
        }

        BigInteger h = k.multiply(BigInteger.valueOf(3));
        Point neg = this.negate();
        Point R = this;

        for(int i=h.bitLength()-2;i>0;i--){
            R = R.twice(ec);

            boolean hBit = h.testBit(i);
            boolean eBit = k.testBit(i);

            if(hBit!=eBit){
                R = R.add(ec,(hBit?this:neg));
            }
        }

        return R;
    }

    public Point negate(){
        if(this.isInfinite()){
            return this;
        }

        return new Point(this.x,this.y.negate());
    }

}

我的代码有什么问题吗? secp256k1是否有特定的乘数算法?

1 个答案:

答案 0 :(得分:1)

是的,您的代码有问题;当你需要划分Zp(又名Z / pZ)时,你试图划分Z(使用BigInteger),其中p是定义基础场的曲线参数(对于secp256k1,见SEC2)。模块化划分采用Java实现,采用模块化逆和模乘法;见Scalar Multiplication of Point over elliptic Curve。您还需要至少获取最终结果mod p,并且通常也可以更有效地执行逐步结果。