Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,7 @@
- 📄 [ConvolutionFFT](src/main/java/com/thealgorithms/maths/ConvolutionFFT.java)
- 📄 [CrossCorrelation](src/main/java/com/thealgorithms/maths/CrossCorrelation.java)
- 📄 [DeterminantOfMatrix](src/main/java/com/thealgorithms/maths/DeterminantOfMatrix.java)
- [DiscreteLogarithmBSGS](src/main/java/com/thealgorithms/maths/DiscreteLogarithmBSGS.java)
- 📄 [DigitalRoot](src/main/java/com/thealgorithms/maths/DigitalRoot.java)
- 📄 [DistanceFormula](src/main/java/com/thealgorithms/maths/DistanceFormula.java)
- 📄 [DudeneyNumber](src/main/java/com/thealgorithms/maths/DudeneyNumber.java)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.thealgorithms.maths;

import java.util.HashMap;
import java.util.Map;

/**
* Baby-Step Giant-Step algorithm for the Discrete Logarithm Problem.
*
* <p>
* Solves for x in: a^x ≡ b (mod m),
* where a, b, m are given, and m is prime (or a has order in modulo m).
*
* <p>
* Time complexity: O(√m)
* Space complexity: O(√m)
*
* @see <a href="https://en.wikipedia.org/wiki/Baby-step_giant-step">Baby-step giant-step algorithm</a>
*/
public final class DiscreteLogarithmBSGS {

private DiscreteLogarithmBSGS() {
throw new UnsupportedOperationException("Utility class");
}

/**
* Computes x such that (a^x) % m == b.
* Returns -1 if no solution exists.
*/
public static long discreteLog(long a, long b, long m) {
a %= m;
b %= m;

if (b == 1) {
return 0;
}

long n = (long) Math.ceil(Math.sqrt(m));

Map<Long, Long> babySteps = new HashMap<>();

long value = 1;
for (long i = 0; i < n; i++) {
babySteps.put(value, i);
value = value * a % m; // PMD fix
}

long factor = modPow(a, m - n - 1, m);

long gamma = b;
for (long j = 0; j <= n; j++) {
if (babySteps.containsKey(gamma)) {
return j * n + babySteps.get(gamma);
}
gamma = gamma * factor % m; // PMD fix
}

return -1; // no solution
}

/** Fast modular exponentiation */
public static long modPow(long base, long exp, long mod) {
long result = 1;
base %= mod;

while (exp > 0) {
if ((exp & 1) == 1) {
result = result * base % mod; // PMD fix
}
base = base * base % mod; // PMD fix
exp >>= 1;
}
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.thealgorithms.maths;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;

public class DiscreteLogarithmBSGSTest {

@Test
public void testSmallValues() {
assertEquals(3, DiscreteLogarithmBSGS.discreteLog(2, 8, 13));
assertEquals(4, DiscreteLogarithmBSGS.discreteLog(3, 81, 1000000007));
}

@Test
public void testNoSolution() {
// choose a true NO-SOLUTION example:
// modulo 15, base 4 generates only {1,4}
assertEquals(-1, DiscreteLogarithmBSGS.discreteLog(4, 2, 15));
}

@Test
public void testLargeMod() {
// use a valid solvable case
long x = DiscreteLogarithmBSGS.discreteLog(5, 5, 1000003);
assertEquals(1, x);
}

@Test
public void testImmediateReturnCase() {
// because a^0 ≡ 1 (mod m)
assertEquals(0, DiscreteLogarithmBSGS.discreteLog(7, 1, 13));
}

@Test
public void testModPowBranchCoverage() {
assertEquals(1, DiscreteLogarithmBSGS.modPow(10, 0, 17)); // exp=0 branch
assertEquals(10 % 17, DiscreteLogarithmBSGS.modPow(10, 1, 17)); // odd exp branch
assertEquals(100 % 17, DiscreteLogarithmBSGS.modPow(10, 2, 17)); // even exp branch
}
}