Skip to content

Commit

Permalink
new unit test for modular sqrts with int arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
TilmanNeumann committed Dec 31, 2024
1 parent 6b85bfe commit 80bf7cc
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@
import org.apache.logging.log4j.LogManager;

import de.tilman_neumann.jml.primes.probable.BPSWTest;
import de.tilman_neumann.util.Ensure;
import de.tilman_neumann.util.ConfigUtil;

public class ModularSqrtTest {
private static final Logger LOG = LogManager.getLogger(ModularSqrtTest.class);
public class ModularSqrtPerformanceTest {
private static final Logger LOG = LogManager.getLogger(ModularSqrtPerformanceTest.class);

private static final int NCOUNT = 100000;

private static final SecureRandom rng = new SecureRandom();
private static final BPSWTest bpsw = new BPSWTest();
private static final JacobiSymbol jacobiEngine = new JacobiSymbol();
Expand Down Expand Up @@ -65,26 +66,8 @@ private static int[] createNArray(int[] pList) {
}
return nArray;
}

private static void testCorrectness(int NCOUNT) {
ModularSqrt31 mse31 = new ModularSqrt31();

LOG.info("Test correctness of " + NCOUNT + " p with p%8==5");
int[] pArray = createPArray(5, NCOUNT);
int[] nArray = createNArray(pArray);
for (int i=0; i<NCOUNT; i++) {
int a = nArray[i];
int p = pArray[i];
int tonelli = mse31.Tonelli_Shanks(a, p);
Ensure.ensureEquals((tonelli * (long)tonelli) % p, a%p);

int case5Mod8 = mse31.case5Mod8(a, p);
Ensure.ensureEquals((case5Mod8 * (long)case5Mod8) % p, a%p);
Ensure.ensureEquals(tonelli, case5Mod8); // both returned the smaller sqrt
}
}

private static void testPerformance(int NCOUNT) {
private static void testPerformance() {
long t;
ModularSqrt31 mse31 = new ModularSqrt31();
LOG.info("Test performance with " + NCOUNT + " test numbers:");
Expand Down Expand Up @@ -150,7 +133,6 @@ private static void testPerformance(int NCOUNT) {
*/
public static void main(String[] args) {
ConfigUtil.initProject();
testCorrectness(100000);
testPerformance(100000);
testPerformance();
}
}
96 changes: 96 additions & 0 deletions src/test/java/de/tilman_neumann/jml/modular/ModularSqrtTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* java-math-library is a Java library focused on number theory, but not necessarily limited to it. It is based on the PSIQS 4.0 factoring project.
* Copyright (C) 2018-2024 Tilman Neumann - tilman.neumann@web.de
*
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, see <http://www.gnu.org/licenses/>.
*/
package de.tilman_neumann.jml.modular;

import static org.junit.Assert.assertEquals;

import java.security.SecureRandom;

import org.apache.logging.log4j.Logger;
import org.junit.BeforeClass;
import org.junit.Test;
import org.apache.logging.log4j.LogManager;

import de.tilman_neumann.jml.primes.probable.BPSWTest;
import de.tilman_neumann.util.ConfigUtil;

public class ModularSqrtTest {
private static final Logger LOG = LogManager.getLogger(ModularSqrtTest.class);

private static final int NCOUNT = 100000;

private static final SecureRandom rng = new SecureRandom();
private static final BPSWTest bpsw = new BPSWTest();
private static final JacobiSymbol jacobiEngine = new JacobiSymbol();
private static final ModularSqrt31 mse31 = new ModularSqrt31();

@BeforeClass
public static void setup() {
ConfigUtil.initProject();
}

@Test
public void testCase5Mod8() {
LOG.info("Test correctness of " + NCOUNT + " p with p%8==5");
int[] pArray = createPArray(5, NCOUNT);
int[] nArray = createNArray(pArray);
for (int i=0; i<NCOUNT; i++) {
int a = nArray[i];
int p = pArray[i];
int tonelli = mse31.Tonelli_Shanks(a, p);
assertEquals((tonelli * (long)tonelli) % p, a%p);

int case5Mod8 = mse31.case5Mod8(a, p);
assertEquals((case5Mod8 * (long)case5Mod8) % p, a%p);
assertEquals(tonelli, case5Mod8); // both returned the smaller sqrt
}
}

private static int[] createPArray(int wantedPMod8, int count) {
int[] pArray = new int[count];
int i = 0;
while (i<count) {
// get non-negative random n
int n = rng.nextInt(Integer.MAX_VALUE);
// add n to the test set if it is an odd prime with the wanted modulus mod 8
if (n>2 && (n&7) == wantedPMod8 && bpsw.isProbablePrime(n)) {
pArray[i] = n;
i++;
}
}
return pArray;
}

/**
* Create positive n having Jacobi(n|p) == 1 for all p in pArray.
* @param pList
* @return
*/
private static int[] createNArray(int[] pList) {
int count = pList.length;
int[] nArray = new int[count];
int i = 0;
while (i<count) {
// get non-negative random n
int n = rng.nextInt(Integer.MAX_VALUE);
// add n if it has Jacobi(n|p) = 1
int p = pList[i];
if (jacobiEngine.jacobiSymbol(n, p) == 1) {
nArray[i] = n;
i++;
}
}
return nArray;
}
}

0 comments on commit 80bf7cc

Please sign in to comment.