PollardRho 算法Java实现
以下代码基于Java实现,目前只能在整数群上使用。
package top.metadev.algorithms;
import java.math.BigInteger;
import java.util.LinkedHashMap;
public class PollardRho {
// sa+tb=(a,b)
public static BigInteger[] ext_gcd(BigInteger a, BigInteger b) {
BigInteger s1 = BigInteger.ONE, t1 = BigInteger.ZERO, r1 = a;
BigInteger s2 = BigInteger.ZERO, t2 = BigInteger.ONE, r2 = b;
BigInteger q = BigInteger.ZERO, temp1, temp2, temp3;
while (!r2.equals(BigInteger.ZERO)) {
q = r1.divide(r2);
temp1 = s1.subtract(q.multiply(s2));
temp2 = t1.subtract(q.multiply(t2));
temp3 = r1.subtract(q.multiply(r2));
s1 = s2;
t1 = t2;
r1 = r2;
s2 = temp1;
t2 = temp2;
r2 = temp3;
}
return new BigInteger[]{s1, t1, r1};
}
private final BigInteger THREE = BigInteger.valueOf(3);
private LinkedHashMap<BigInteger, Tuple> tupleMap = new LinkedHashMap<>();
public PollardRho(BigInteger alpha, BigInteger beta, BigInteger p, BigInteger ord) {
this.alpha = alpha;
this.beta = beta;
P = p;
this.ord = ord;
tupleMap.put(BigInteger.ZERO, new Tuple(BigInteger.ONE, BigInteger.ZERO, BigInteger.ZERO));
}
private class Tuple {
private BigInteger x;
private BigInteger a;
private BigInteger b;
public Tuple(BigInteger x, BigInteger a, BigInteger b) {
this.x = x;
this.a = a;
this.b = b;
}
public Tuple() {
}
public BigInteger getX() {
return x;
}
public void setX(BigInteger x) {
this.x = x;
}
public BigInteger getA() {
return a;
}
public void setA(BigInteger a) {
this.a = a;
}
public BigInteger getB() {
return b;
}
public void setB(BigInteger b) {
this.b = b;
}
}
private final BigInteger alpha, beta, P, ord;
private Tuple f(Tuple tuple) {
BigInteger mod = tuple.getX().mod(THREE);
Tuple res = new Tuple();
if (mod.equals(BigInteger.ONE)) {
//1 class
res.setX(tuple.getX().multiply(beta).mod(P));
res.setA(tuple.getA().mod(ord));//不模ord结果会非常大的
res.setB(tuple.getB().add(BigInteger.ONE).mod(ord));
} else if (mod.equals(BigInteger.ZERO)) {
//2 class
res.setX(tuple.getX().modPow(BigInteger.TWO, P));
res.setA(tuple.getA().multiply(BigInteger.TWO).mod(ord));
res.setB(tuple.getB().multiply(BigInteger.TWO).mod(ord));
} else {
//3 class
res.setX(tuple.getX().multiply(alpha).mod(P));
res.setA(tuple.getA().add(BigInteger.ONE).mod(ord));
res.setB(tuple.getB().mod(ord));
}
return res;
}
// res = log alpha {beta}
public BigInteger getResult() {
BigInteger index = BigInteger.ONE;
BigInteger res = BigInteger.ZERO;
while (index.compareTo(ord) < 0) {
Tuple temp = tupleMap.get(index.subtract(BigInteger.ONE));
Tuple next = f(temp);
tupleMap.put(index, next);
if (index.mod(BigInteger.TWO).equals(BigInteger.ZERO)) {
Tuple res1 = tupleMap.get(index);
Tuple res2 = tupleMap.get(index.divide(BigInteger.TWO));
if (res1.getX().equals(res2.getX())) {
if (!ord.gcd(res2.getB().subtract(res1.getB())).equals(BigInteger.ONE)) {
System.out.println("用线性同余式求解");
BigInteger b = res2.getB().subtract(res1.getB());
BigInteger d = ord.gcd(b);
BigInteger a = res1.getA().subtract(res2.getA());
if (!a.divideAndRemainder(d)[1].equals(BigInteger.ZERO)) {
System.out.println("无解");
break;
}
BigInteger c0 = a.divide(d).multiply(b.divide(d).modInverse(ord.divide(d))).mod(ord.divide(d));
// for (BigInteger i = BigInteger.ZERO; i.compareTo(d) < 0; i = i.add(BigInteger.ONE)) {
// System.out.println(alpha.modPow(c0.add(ord.divide(d).multiply(i)), P));
// System.out.println(c0.add(ord.divide(d).multiply(i)));
//
// }
res = c0;
break;
}else{
res = res1.getA().subtract(res2.getA()).multiply(res2.getB().subtract(res1.getB()).modInverse(ord)).mod(ord);
System.out.println("计算完成。");
break;
}
}
}
index = index.add(BigInteger.ONE);
}
return res;
}
//测试结果
public static void main(String[] args) {
PollardRho pollardRho = new PollardRho(BigInteger.valueOf(89), BigInteger.valueOf(618),
BigInteger.valueOf(809), BigInteger.valueOf(101));
BigInteger result = pollardRho.getResult();
System.out.println(result);
}
}