椭圆曲线乘法函数
Elliptic Curve Multiplication Function
我正在尝试制作我自己的椭圆曲线库。
有些东西有效,有些则无效。
要从私钥计算public密钥,您应该将生成器点乘以私钥,然后得到另一个点:public密钥点(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有没有具体的乘法算法?
是的,您的代码有问题;当您需要除以 Zp(又名 Z/pZ)时,您正在尝试除以 Z(使用 BigInteger),其中 p 是定义基础字段的曲线参数(对于 secp256k1,请参见 SEC2)。在 Java 中,模块化除法是通过采用 modular 逆和 modular 乘法实现的;见 Scalar Multiplication of Point over elliptic Curve 。另外你需要至少取最终结果mod p,而且通常也做逐步结果更有效率。
我正在尝试制作我自己的椭圆曲线库。 有些东西有效,有些则无效。
要从私钥计算public密钥,您应该将生成器点乘以私钥,然后得到另一个点:public密钥点(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有没有具体的乘法算法?
是的,您的代码有问题;当您需要除以 Zp(又名 Z/pZ)时,您正在尝试除以 Z(使用 BigInteger),其中 p 是定义基础字段的曲线参数(对于 secp256k1,请参见 SEC2)。在 Java 中,模块化除法是通过采用 modular 逆和 modular 乘法实现的;见 Scalar Multiplication of Point over elliptic Curve 。另外你需要至少取最终结果mod p,而且通常也做逐步结果更有效率。