2017-07-16 232 views
1

我想为椭圆曲线制作自己的库。 有些事情可以工作,但有些则不行。椭圆曲线乘法函数

要从私钥计算公钥,您应该将发生器点与私钥相乘,并获得另一个点:公钥点(ECPoint = BigInteger * ECPoint)。

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

这是我的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有一个特定的乘法器算法吗?

+0

什么是您的输入,预期输出和当前输出? – tima

+0

输入= 059E2BF5E2C7A4098C164B29A91CF70508D2FD1A256A60656FD2593BDB980FAA /输出中预计04 = +(DA43096D079CED007CDF810ECB27030FFBDBCCAB0400A5A040D282EF8049805B,A4F8D0BE0BDABE528524245B5BBD5A125835A302F61156CE6BE48530B8F53C66) –

回答

1

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

+0

它的工作原理,但此功能仅适用于secp256k1或只为总理曲线?哪里可以找到椭圆曲线(Prime,F2M等)的完整文档? –

+0

@BenvanHartingsveldt:这些公式适用于Weierstrass格式的主要字段上的曲线,其中包括常用字段。我认为任何一个地方都没有完整的文档,因为这是一个新的且仍在不断变化的领域,但对于它所覆盖的曲线,我喜欢www.secg.org上的SECG文档 - 它们包括我你)需要没有大量的离题和绒毛。当然,Stack总是很好,尤其是crypto.SX和security.SX :-) –