赞
踩
前段时间写一个审计系统时,用到了椭圆曲线的数字签名技术。 在计算其倍点时,一开始我使用点与点相加的基本算式进行迭代运算。 但发现效率很低。最后想了想,进行了如下的改进(其实也是参考《密码编码学与网络安全》第6版一书中的一个思路,进行了如下的书写)。
package com.pathfinder.function;
import java.io.FileInputStream;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName: Algorithm
* @Description:倍点运算
* @author: muliming / mulming@163.com
* @date: 2017年10月29日 下午6:56:39
* @Copyright: 2017
*/
public class Algorithm {
private int a;
private int b;
private int q;
public Algorithm(int a, int b, int q) {
this.a = a;
this.b = b;
this.q = q;
}
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public int getB() {
return b;
}
public void setB(int b) {
this.b = b;
}
public int getQ() {
return q;
}
public void setQ(int q) {
this.q = q;
}
/**
* @Title: OutsAlgorithm
* @Description: 倍点运算,给定一个点,进行倍数的计算【具体:把要计算的值,转为二进制数,然后在二进制的每位上做相应的二倍运算,最后再把所有的相加】
* @param: @param s: 点 n: 需要计算的倍数
* @return: String
*/
public String OutsAlgorithm(long n,String s)
{
List<Byte> er=new ArrayList<Byte>();//存放转化为二进制的数
List<String> dian=new ArrayList<String>();
if(n!=0)
{
//把要计算的值,转为二进制数,然后在二进制的每位上做相应的二倍运算,最后再把所有的相加
while(n!=0)
{
byte i=(byte)(n%2);
er.add(i);
n=n/2;
}
for(int i=0;i<er.size();i++)
{
if(er.get(i)==1)
dian.add(s);
s=multiple2Operation(s);//二倍 倍点运算算法 计算一个点的n倍的算法
}
s=dian.get(0);
for(int i=1;i<dian.size();i++)
{
s=addOperation(s, dian.get(i));//计算两个不同点相加的运算
}
return s;
}
else
{
return "0v0";
}
}
/**
* @Title: multiple2Operation
* @Description:计算一个点的2倍的值
* @param: @param g:要计算的点
* @return: String v点的2倍的值
*/
public String multiple2Operation(String g)
{
int x=2;
String[] vp=g.split("v");
int xp=Integer.parseInt(vp[0]);
int yp=Integer.parseInt(vp[1]);
if(yp==0)
{
return "0v0"; //TODO y为0的时候怎么办?
}
else
{
long Numerator=3*xp*xp+a;//分子
long denominator=2*yp;//分母
denominator=niyuan(denominator,q,1,0);// 计算分母的逆元
while(denominator<0)
{
denominator=denominator+q;
}
long ratio=(long)(Numerator*denominator)%q;//计算 入 的值 及斜率
long xrr=(long)(ratio*ratio-2*xp);
while(xrr<0)
{
xrr=xrr+q;
}
int Xr=(int)(xrr%q);//横坐标
long Yrr=(long)(ratio*(xp-Xr)-yp);
while(Yrr<0)
{
Yrr=Yrr+q;
}
int Yr=(int)(Yrr%q);
return Xr+"v"+Yr;//返回2倍点的坐标
}
}
/**
* @Title: addOperation
* @Description: 计算两个不同点相加的运算
* @param: @param V 点
* @param: @param v1 点
* @return: String
*/
public String addOperation(String V,String v1)
{
if(v1.equals(V))
{
return multiple2Operation(V);//如果两个点相等,直接调用倍点运算
}
else
{
String[] vp=V.split("v");
String[] vq=v1.split("v");
if(vp[0].equals(vq[0]))//两个的x值相等
{
return "0v0";
}
else
{
//排错
if(v1.equals("0v0"))
return V;
else if(V.equals("0v0"))
return v1;
//运算
else
{
//第一个点的x y坐标
int xp=Integer.parseInt(vp[0]);
int yp=Integer.parseInt(vp[1]);
//第二个点的x y坐标
int xq=Integer.parseInt(vq[0]);
int yq=Integer.parseInt(vq[1]);
long DValueY=(long)yq-yp;//y的差值
while(DValueY<0)
{
DValueY=DValueY+q;
}
long DValueX=(long)xq-xp;//x的差值
while(DValueX<0)
{
DValueX=DValueX+q;
}
DValueX=niyuan(DValueX,q,1,0);
while(DValueX<0)
{
DValueX=DValueX+q;
}
long ratio=(long)(DValueY*DValueX)%q;
long xrr=(long)(ratio*ratio-xp-xq);
while(xrr<0)
{
xrr=xrr+q;
}
int xr=(int)(xrr%q);
long yrr=(long)(ratio*(xp-xr)-yp);
while(yrr<0)
{
yrr=yrr+q;
}
int yr=(int)(yrr%q);
//返回值
return xr+"v"+yr;
}
}
}
}
/**
* @Title: niyuan 就是扩展的欧几里得算法,具体可参看我的另一篇
* @Description: 计算逆元 及分数得模运算
* @param: @param r1L2 --》2yp 先计算r1分之1关于r2的逆元
* @param: @param r2p:椭圆曲线参数p
* @param: @param x11
* @param: @param x20
* @param: @return 分母的逆元
* @return: long
*/
public long niyuan(long r1,long r2,long x1,long x2)
{
long qr=r1/r2;
long r=r1%r2;
long x=x1-qr*x2;
if(r==1)
{
return x;
}
else
return niyuan(r2,r,x2,x);
}
//END
}
欢迎各位大侠提出意见。相互学习
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。