//
// Discrete logarithm calculator
//
// Written by Dario Alejandro Alpern (Buenos Aires - Argentina)
// Last updated April 15th, 2005, See http://www.alpertron.com.ar/DILOG.HTM
//
// No part of this code can be used for commercial purposes without
// the written consent from the author. Otherwise it can be used freely
// except that you have to write somewhere in the code this header.
//
import java.applet.*;
import java.util.*;
import java.awt.*;
import java.math.*;
public final class logdi extends ecm {
private TextField textBase, textPower, textMod, textExp, textPeriod;
private Button btnSolve;
private BigInteger base, power, modulus;
private BigInteger LastModulus = BigInt0;
private Frame factorWindow;
private ecm factorPanel;
private BigInteger PrimesMod[]; // Mod = Modulus.
private int ExponentsMod[];
private BigInteger PrimesModBak[];
private int ExponentsModBak[];
private BigInteger PrimesGO[]; // GO = Group Order.
private int ExponentsGO[];
private BigInteger PrimesGOBak[];
private int ExponentsGOBak[];
private BigInteger nbrV[];
private int NumberLengthOther;
private int NbrFactorsMod=0;
private long TestNbrOther[] = new long[NLen];
private long nbrA[] = new long[NLen];
private long nbrA2[] = new long[NLen];
private long nbrB[] = new long[NLen];
private long nbrB2[] = new long[NLen];
private long nbrK[] = new long[NLen];
private long nbrR[] = new long[NLen];
private long nbrROther[] = new long[NLen];
private long nbrR2[] = new long[NLen];
private long nbrPower[] = new long[NLen];
private long nbrBase[] = new long[NLen];
private double dNOther;
public void init() {
Label labelBase, labelPower, labelMod, labelExp, labelPeriod, labelBottom;
PrimesMod=new BigInteger[400];
ExponentsMod=new int[400];
PrimesModBak=new BigInteger[400];
ExponentsModBak=new int[400];
PrimesGO=new BigInteger[400];
ExponentsGO=new int[400];
nbrV = new BigInteger[400];
setLayout(null);
labelBase = new Label("Base");
labelBase.reshape(5, 15, 60, 14);
labelBase.setFont(new Font("Courier", Font.PLAIN, 12));
labelBase.setAlignment(Label.CENTER);
add(labelBase);
textBase = new TextField(64);
textBase.reshape(70, 10, 510, 30);
textBase.setEditable(true);
add(textBase);
labelPower = new Label("Potencia");
labelPower.reshape(5, 65, 60, 14);
labelPower.setFont(new Font("Courier", Font.PLAIN, 12));
labelPower.setAlignment(Label.CENTER);
add(labelPower);
textPower = new TextField(64);
textPower.reshape(70, 60, 510, 30);
textPower.setEditable(true);
add(textPower);
labelMod = new Label("Módulo");
labelMod.reshape(5, 115, 60, 14);
labelMod.setFont(new Font("Courier", Font.PLAIN, 12));
labelMod.setAlignment(Label.CENTER);
add(labelMod);
textMod = new TextField(64);
textMod.reshape(70, 110, 510, 30);
textMod.setEditable(true);
add(textMod);
btnSolve = new Button("Hallar logaritmo discreto");
btnSolve.reshape(210, 160, 180, 30);
btnSolve.setFont(new Font("Courier", Font.PLAIN, 12));
add(btnSolve);
labelStatus = new Label("");
labelStatus.reshape(30, 205, 520, 14);
labelStatus.setFont(new Font("Courier", Font.PLAIN, 12));
labelStatus.setAlignment(Label.CENTER);
add(labelStatus);
textExp = new TextField(64);
labelExp = new Label("Expon");
labelExp.reshape(5, 235, 60, 14);
labelExp.setFont(new Font("Courier", Font.PLAIN, 12));
labelExp.setAlignment(Label.CENTER);
add(labelExp);
textExp = new TextField(64);
textExp.reshape(70, 230, 510, 30);
textExp.setEditable(false);
add(textExp);
textPeriod = new TextField(64);
labelPeriod = new Label("Período");
labelPeriod.reshape(5, 285, 60, 14);
labelPeriod.setFont(new Font("Courier", Font.PLAIN, 12));
labelPeriod.setAlignment(Label.CENTER);
add(labelPeriod);
textPeriod = new TextField(64);
textPeriod.reshape(70, 280, 510, 30);
textPeriod.setEditable(false);
add(textPeriod);
labelBottom = new Label("Escrito por Dario Alejandro Alpern. Actualizado el 15 de abril de 2005");
labelBottom.reshape(10, 330, 570, 14);
labelBottom.setFont(new Font("Courier", Font.PLAIN, 12));
labelBottom.setAlignment(Label.CENTER);
add(labelBottom);
validate();
textBase.requestFocus();
}
public boolean handleEvent(Event e) {
if (e.id == Event.ACTION_EVENT && e.target == btnSolve ||
e.id == Event.KEY_PRESS && e.key == 13) {
if (calcThread != null) {
TerminateThread = true;
try {
calcThread.join(); /* Wait until the solving thread dies */
} catch (InterruptedException ie) {};
}
calcThread = new Thread(this); /* Start solving thread */
calcThread.start();
return true;
}
if (e.id == Event.KEY_PRESS && e.key == Event.TAB) {
if (e.target == textBase) {textPower.requestFocus();}
if (e.target == textPower) {textMod.requestFocus();}
if (e.target == textMod) {textBase.requestFocus();}
return true;
}
return super.handleEvent(e);
}
public void run() {
BigInteger groupOrder, subGroupOrder, range, powSubGroupOrder;
BigInteger GroupOrder = null;
BigInteger Exponent, runningExp, baseExp, mod;
BigInteger basePH, powerPH;
BigInteger logar=null, logarMult;
BigInteger divideExp, nbrD;
BigInteger bigNbrA2, bigNbrB2;
BigInteger DiscreteLog, DiscreteLogPeriod;
int d, j, indexBase, indexExp;
int i, index;
long addA, addB, addA2, addB2;
long mult1, mult2;
long magnitude;
int mostSignificantDword, leastSignificantDword;
long firstLimit, secondLimit;
long brentK, brentR;
int ExpressionRC;
BigInteger ExpressionResult[] = new BigInteger[1];
Old=System.currentTimeMillis();
OldTimeElapsed = 0;
lModularMult = 0;
TerminateThread = false;
try {
try {
ExpressionRC = expression.ComputeExpression(textMod.getText().trim(),1,ExpressionResult);
} catch (OutOfMemoryError e) {
textExp.setText("Sin memoria.");
return;
} catch (ArithmeticException e) {
return;
}
modulus= ExpressionResult[0].abs();
if (ExpressionRC != 0) {
textExp.setText("Módulo: "+expressionText[-1-ExpressionRC]);
return;
}
try {
ExpressionRC = expression.ComputeExpression(textBase.getText().trim(),1,ExpressionResult);
} catch (OutOfMemoryError e) {
textExp.setText("Sin memoria.");
return;
} catch (ArithmeticException e) {
return;
}
base = ExpressionResult[0].mod(modulus);
if (ExpressionRC != 0) {
textExp.setText("Base: "+expressionText[-1-ExpressionRC]);
return;
}
try {
ExpressionRC = expression.ComputeExpression(textPower.getText().trim(),1,ExpressionResult);
} catch (OutOfMemoryError e) {
textExp.setText("Sin memoria.");
return;
} catch (ArithmeticException e) {
return;
}
power = ExpressionResult[0].abs();
if (ExpressionRC != 0) {
textExp.setText("Potencia: "+expressionText[-1-ExpressionRC]);
return;
}
} catch (Exception e) {
textExp.setText("Datos inválidos");
return;
}
if (modulus.gcd(base).equals(BigInt1) == false) {
textExp.setText("El módulo y la base no son primos entre si.");
return;
}
if (modulus.gcd(power).equals(BigInt1) == false) {
textExp.setText("El módulo y la potencia no son primos entre si.");
return;
}
if (modulus.compareTo(BigInt1) <= 0) {
textExp.setText("El módulo debe ser mayor que 1.");
return;
}
if (LastModulus.equals(modulus) == false) {
if (GetSmallFactors(modulus, PrimesModBak, ExponentsModBak, Typ, 0) != 1) {
LastModulus = modulus;
factorPanel = new ecm();
factorWindow = new Frame("Factorización del módulo");
factorWindow.setResizable(false);
factorWindow.add(factorPanel);
factorPanel.setSize(600, 390);
Insets in = factorWindow.getInsets();
factorWindow.setSize(600+in.right+in.left, 390+in.top+in.bottom);
factorWindow.show();
NbrFactorsMod = factorPanel.getFactors(modulus, PrimesModBak, ExponentsModBak);
factorWindow.remove(factorPanel);
factorWindow.dispose();
}
else {
NbrFactorsMod = NbrFactors;
}
for (j=0; j 1) {
dN += (double)TestNbr[NumberLength-2]/dDosALa31;
}
if (NumberLength > 2) {
dN += (double)TestNbr[NumberLength-3]/dDosALa62;
}
ExchangeMods(); // TestNbr <- modulus
baseExp = groupOrder;
powSubGroupOrder = BigInt1;
for (indexExp = 0; indexExp < ExponentsGO[indexBase]; indexExp++) {
/* PH below comes from Pohlig-Hellman algorithm */
divideExp = BigInt1;
j = ExponentsGO[indexBase] - indexExp;
do {
divideExp = divideExp.multiply(subGroupOrder);
basePH = base.modPow(groupOrder.divide(divideExp), mod);
j--;
} while (j>0 && basePH.equals(BigInt1));
powerPH = power.multiply(base.modPow(runningExp.negate(), mod)).
modPow(baseExp.divide(divideExp),mod);
baseExp = baseExp.divide(subGroupOrder);
if (subGroupOrder.compareTo(BigInteger.valueOf(20L)) < 0) {
for (j=subGroupOrder.intValue()-1; j>=0; j--) {
if (basePH.modPow(BigInteger.valueOf(j), mod).equals(powerPH)) {
break;
}
}
if (j<0) {
textExp.setText("No se puede calcular el logaritmo discreto subgrupo="+PrimesGO[indexBase]+" exponente="+indexExp);
return;
}
Exponent = BigInteger.valueOf(j);
}
else { // Use Pollard's rho method with Brent's modification
BigNbrToMont(powerPH, nbrPower);
BigNbrToMont(basePH, nbrBase);
for (j=0; j 10000000) {
ExchangeMods(); // TestNbr <- subGroupOrder
AdjustExponent(nbrA2, mult2, addA2);
AdjustExponent(nbrB2, mult2, addB2);
ExchangeMods(); // TestNbr <- modulus
mult2 = 1;
addA2 = addB2 = 0;
}
for (j=0; j No se puede calcular el logaritmo discreto");
}
else {
textExp.setText("No existe el logaritmo discreto");
}
return;
}
logar = logar.add(Num.multiply(Den.modInverse(F)).
mod(F).multiply(G));
G = G.multiply(F);
F = H;
}
GroupOrder = GroupOrder.
multiply(PrimesMod[index].pow(ExponentsMod[index]-1));
logar = logar.mod(GroupOrder);
if (DiscreteLogPeriod.equals(BigInt1)) {
DiscreteLogPeriod = GroupOrder;
DiscreteLog = logar;
}
else {
BigInteger gcd = GroupOrder.gcd(DiscreteLogPeriod);
if (logar.mod(gcd).equals(DiscreteLog.mod(gcd)) == false) {
textExp.setText("No existe el logaritmo discreto");
return;
}
if (GroupOrder.divide(gcd).gcd(gcd).equals(BigInt1) == false) {
BigInteger tmp = GroupOrder;
GroupOrder = DiscreteLogPeriod;
DiscreteLogPeriod = tmp;
tmp = logar;
logar = DiscreteLog;
DiscreteLog = tmp;
}
GroupOrder = GroupOrder.divide(gcd);
logar = logar.mod(GroupOrder);
DiscreteLog = (logar.subtract(DiscreteLog)).
multiply(DiscreteLogPeriod.modInverse(GroupOrder)).
mod(GroupOrder).multiply(DiscreteLogPeriod).add(DiscreteLog);
DiscreteLogPeriod = DiscreteLogPeriod.multiply(GroupOrder);
}
}
textExp.setText(DiscreteLog.toString());
textPeriod.setText(DiscreteLogPeriod.toString());
long t=OldTimeElapsed/1000;
labelStatus.setText("Tiempo transcurrido: "+
t/86400+"d "+(t%86400)/3600+"h "+((t%3600)/60)+"m "+(t%60)+
"s mult mod: "+lModularMult);
}
private void BigNbrToMont(BigInteger bigNbr, long [] nbr) {
int i;
long tmp;
int NumberLengthBak = NumberLength;
System.arraycopy(TestNbr, 0, CalcAuxGcdU, 0, NLen);
BigNbrToBigInt(bigNbr);
for (i=NumberLength; i>> 31) + mult*nbr[j];
nbr[j] = Pr & 0x7FFFFFFFl;
}
nbr[j] = (Pr >>> 31);
AdjustModN(nbr);
}
private void ExchangeMods() {
long [] Tmp;
int Temp;
double dTemp;
Tmp = TestNbr;
TestNbr = TestNbrOther;
TestNbrOther = Tmp;
Temp = NumberLength;
NumberLength = NumberLengthOther;
NumberLengthOther = Temp;
dTemp = dN;
dN = dNOther;
dNOther = dTemp;
}
} // End applet class
//