Data update
This commit is contained in:
parent
4d5544505c
commit
4924dd0264
3073 changed files with 55820 additions and 4408 deletions
122
Task/Tonelli-Shanks-algorithm/Dart/tonelli-shanks-algorithm.dart
Normal file
122
Task/Tonelli-Shanks-algorithm/Dart/tonelli-shanks-algorithm.dart
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
class Pair {
|
||||
final int n;
|
||||
final int p;
|
||||
|
||||
Pair(this.n, this.p);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
final int root1;
|
||||
final int root2;
|
||||
final bool isSquare;
|
||||
|
||||
Solution(this.root1, this.root2, this.isSquare);
|
||||
}
|
||||
|
||||
int multiplyModulus(int a, int b, int modulus) {
|
||||
a %= modulus;
|
||||
b %= modulus;
|
||||
if (b < a) {
|
||||
var temp = a;
|
||||
a = b;
|
||||
b = temp;
|
||||
}
|
||||
|
||||
int result = 0;
|
||||
while (a > 0) {
|
||||
if (a % 2 == 1) {
|
||||
result = (result + b) % modulus;
|
||||
}
|
||||
b = (b << 1) % modulus;
|
||||
a >>= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int powerModulus(int base, int exponent, int modulus) {
|
||||
if (modulus == 1) return 0;
|
||||
|
||||
base %= modulus;
|
||||
int result = 1;
|
||||
while (exponent > 0) {
|
||||
if ((exponent & 1) == 1) {
|
||||
result = multiplyModulus(result, base, modulus);
|
||||
}
|
||||
base = multiplyModulus(base, base, modulus);
|
||||
exponent >>= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int legendre(int a, int p) {
|
||||
return powerModulus(a, (p - 1) ~/ 2, p);
|
||||
}
|
||||
|
||||
Solution tonelliShanks(int n, int p) {
|
||||
if (legendre(n, p) != 1) {
|
||||
return Solution(0, 0, false);
|
||||
}
|
||||
|
||||
// Factor out powers of 2 from p - 1
|
||||
int q = p - 1;
|
||||
int s = 0;
|
||||
while (q % 2 == 0) {
|
||||
q ~/= 2;
|
||||
s += 1;
|
||||
}
|
||||
|
||||
if (s == 1) {
|
||||
int result = powerModulus(n, (p + 1) ~/ 4, p);
|
||||
return Solution(result, p - result, true);
|
||||
}
|
||||
|
||||
// Find a non-square z such that (z | p) = -1
|
||||
int z = 2;
|
||||
while (legendre(z, p) != p - 1) {
|
||||
z += 1;
|
||||
}
|
||||
|
||||
int c = powerModulus(z, q, p);
|
||||
int t = powerModulus(n, q, p);
|
||||
int m = s;
|
||||
int result = powerModulus(n, (q + 1) ~/ 2, p);
|
||||
|
||||
while (t != 1) {
|
||||
int i = 1;
|
||||
int zTemp = multiplyModulus(t, t, p);
|
||||
while (zTemp != 1 && i < m - 1) {
|
||||
i += 1;
|
||||
zTemp = multiplyModulus(zTemp, zTemp, p);
|
||||
}
|
||||
|
||||
int b = powerModulus(c, 1 << (m - i - 1), p);
|
||||
c = multiplyModulus(b, b, p);
|
||||
t = multiplyModulus(t, c, p);
|
||||
m = i;
|
||||
result = multiplyModulus(result, b, p);
|
||||
}
|
||||
|
||||
return Solution(result, p - result, true);
|
||||
}
|
||||
|
||||
void main() {
|
||||
final List<Pair> tests = [
|
||||
Pair(10, 13),
|
||||
Pair(56, 101),
|
||||
Pair(1030, 1009),
|
||||
Pair(1032, 1009),
|
||||
Pair(44402, 100049),
|
||||
Pair(665820697, 1000000009),
|
||||
Pair(881398088036, 1000000000039),
|
||||
];
|
||||
|
||||
for (final test in tests) {
|
||||
final solution = tonelliShanks(test.n, test.p);
|
||||
print('n = ${test.n}, p = ${test.p}');
|
||||
if (solution.isSquare) {
|
||||
print('has solutions: ${solution.root1} and ${solution.root2}\n');
|
||||
} else {
|
||||
print('has no solutions because n is not a square modulo p\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
(* Legendre symbol *)
|
||||
LegendreSymbol[a_, p_] := PowerMod[a, (p - 1)/2, p]
|
||||
|
||||
(* Tonelli-Shanks Algorithm *)
|
||||
Tonelli[n_, p_] := Module[
|
||||
{q, s, z, c, r, t, m, t2, i, b},
|
||||
(* Check that n is a quadratic residue mod p *)
|
||||
If[LegendreSymbol[n, p] =!= 1,
|
||||
Message[Tonelli::notsquare, n, p]; Abort[]];
|
||||
|
||||
(* Step 1: Factor out powers of 2 from p - 1 *)
|
||||
q = p - 1;
|
||||
s = 0;
|
||||
While[EvenQ[q], q = q/2; s++];
|
||||
|
||||
(* Special case when s == 1 *)
|
||||
If[s == 1,
|
||||
Return[PowerMod[n, (p + 1)/4, p]]
|
||||
];
|
||||
|
||||
(* Find a non-residue z *)
|
||||
For[z = 2, z < p, z++,
|
||||
If[LegendreSymbol[z, p] == p - 1, Break[]]
|
||||
];
|
||||
|
||||
(* Initialize variables *)
|
||||
c = PowerMod[z, q, p];
|
||||
r = PowerMod[n, (q + 1)/2, p];
|
||||
t = PowerMod[n, q, p];
|
||||
m = s;
|
||||
|
||||
(* Main loop *)
|
||||
While[Mod[t - 1, p] =!= 0,
|
||||
t2 = Mod[t^2, p];
|
||||
For[i = 1, i < m, i++,
|
||||
If[Mod[t2 - 1, p] === 0, Break[]];
|
||||
t2 = Mod[t2^2, p];
|
||||
];
|
||||
b = PowerMod[c, 2^(m - i - 1), p];
|
||||
r = Mod[r*b, p];
|
||||
c = Mod[b^2, p];
|
||||
t = Mod[t*c, p];
|
||||
m = i;
|
||||
];
|
||||
r
|
||||
]
|
||||
|
||||
(* Test cases *)
|
||||
ttest = {
|
||||
{10, 13},
|
||||
{56, 101},
|
||||
{1030, 10009},
|
||||
{44402, 100049},
|
||||
{665820697, 1000000009},
|
||||
{881398088036, 1000000000039},
|
||||
{41660815127637347468140745042827704103445750172002, 10^50 + 577}
|
||||
};
|
||||
|
||||
Do[
|
||||
n = ttest[[i, 1]];
|
||||
p = ttest[[i, 2]];
|
||||
r = Tonelli[n, p];
|
||||
Assert[Mod[r^2 - n, p] == 0];
|
||||
Print["n = ", n, ", p = ", p];
|
||||
Print["\troots : ", r, " ", p - r],
|
||||
{i, Length[ttest]}
|
||||
]
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
/* Legendre symbol */
|
||||
legendresymbol(a, p) =
|
||||
{
|
||||
lift(Mod(a, p)^((p-1)/2));
|
||||
}
|
||||
|
||||
/* Tonelli-Shanks Algorithm */
|
||||
tonelli(n, p) =
|
||||
{
|
||||
local(q, s, z, c, r, t, m, t2, i, b);
|
||||
|
||||
/* Check that n is a quadratic residue mod p */
|
||||
if(legendresymbol(n, p) != 1,
|
||||
error("n is not a quadratic residue mod p"));
|
||||
|
||||
/* Step 1: Factor out powers of 2 from p - 1 */
|
||||
q = p - 1;
|
||||
s = 0;
|
||||
while(q % 2 == 0,
|
||||
q = q/2;
|
||||
s++
|
||||
);
|
||||
|
||||
/* Special case when s == 1 */
|
||||
if(s == 1,
|
||||
return(lift(Mod(n, p)^((p+1)/4)))
|
||||
);
|
||||
|
||||
/* Find a non-residue z */
|
||||
z = 2;
|
||||
while(z < p,
|
||||
if(legendresymbol(z, p) == p - 1, break());
|
||||
z++
|
||||
);
|
||||
|
||||
/* Initialize variables */
|
||||
c = lift(Mod(z, p)^q);
|
||||
r = lift(Mod(n, p)^((q+1)/2));
|
||||
t = lift(Mod(n, p)^q);
|
||||
m = s;
|
||||
|
||||
/* Main loop */
|
||||
while((t - 1) % p != 0,
|
||||
t2 = t^2 % p;
|
||||
i = 1;
|
||||
while(i < m,
|
||||
if((t2 - 1) % p == 0, break());
|
||||
t2 = t2^2 % p;
|
||||
i++
|
||||
);
|
||||
b = lift(Mod(c, p)^(2^(m - i - 1)));
|
||||
r = (r * b) % p;
|
||||
c = b^2 % p;
|
||||
t = (t * c) % p;
|
||||
m = i
|
||||
);
|
||||
|
||||
return(r);
|
||||
}
|
||||
|
||||
/* Test the functions */
|
||||
print("Testing Tonelli-Shanks algorithm:");
|
||||
print();
|
||||
|
||||
/* Test case 1 */
|
||||
n = 10; p = 13;
|
||||
r = tonelli(n, p);
|
||||
print("n = ", n, ", p = ", p);
|
||||
print("roots: ", r, ", ", p - r);
|
||||
print("verification: ", r, "^2 mod ", p, " = ", r^2 % p);
|
||||
print();
|
||||
|
||||
/* Test case 2 */
|
||||
n = 56; p = 101;
|
||||
r = tonelli(n, p);
|
||||
print("n = ", n, ", p = ", p);
|
||||
print("roots: ", r, ", ", p - r);
|
||||
print("verification: ", r, "^2 mod ", p, " = ", r^2 % p);
|
||||
print();
|
||||
|
||||
/* Test case 3 */
|
||||
n = 1030; p = 10009;
|
||||
r = tonelli(n, p);
|
||||
print("n = ", n, ", p = ", p);
|
||||
print("roots: ", r, ", ", p - r);
|
||||
print("verification: ", r, "^2 mod ", p, " = ", r^2 % p);
|
||||
print();
|
||||
|
||||
|
||||
/* Test case 4 */
|
||||
n = 44402; p = 100049;
|
||||
r = tonelli(n, p);
|
||||
print("n = ", n, ", p = ", p);
|
||||
print("roots: ", r, ", ", p - r);
|
||||
print("verification: ", r, "^2 mod ", p, " = ", r^2 % p);
|
||||
print();
|
||||
|
||||
|
||||
/* Test case 5 */
|
||||
n = 665820697; p = 1000000009;
|
||||
r = tonelli(n, p);
|
||||
print("n = ", n, ", p = ", p);
|
||||
print("roots: ", r, ", ", p - r);
|
||||
print("verification: ", r, "^2 mod ", p, " = ", r^2 % p);
|
||||
print();
|
||||
|
||||
|
||||
/* Test case 6 */
|
||||
n = 881398088036; p = 1000000000039;
|
||||
r = tonelli(n, p);
|
||||
print("n = ", n, ", p = ", p);
|
||||
print("roots: ", r, ", ", p - r);
|
||||
print("verification: ", r, "^2 mod ", p, " = ", r^2 % p);
|
||||
print();
|
||||
|
||||
|
||||
/* Test case 7 */
|
||||
n = 41660815127637347468140745042827704103445750172002; p = 100000000000000000000000000000000000000000000000577;
|
||||
r = tonelli(n, p);
|
||||
print("n = ", n, ", p = ", p);
|
||||
print("roots: ", r, ", ", p - r);
|
||||
print("verification: ", r, "^2 mod ", p, " = ", r^2 % p);
|
||||
print();
|
||||
98
Task/Tonelli-Shanks-algorithm/R/tonelli-shanks-algorithm.r
Normal file
98
Task/Tonelli-Shanks-algorithm/R/tonelli-shanks-algorithm.r
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
library(gmp) # For handling large integers and modular arithmetic
|
||||
|
||||
# Legendre symbol: a^((p-1)/2) mod p
|
||||
legendre <- function(a, p) {
|
||||
a <- as.bigz(a)
|
||||
p <- as.bigz(p)
|
||||
e <- div.bigz(sub.bigz(p, 1), 2)
|
||||
result <- powm(a, e, p)
|
||||
return(result)
|
||||
}
|
||||
|
||||
# Tonelli-Shanks algorithm to find square root of n mod p
|
||||
tonelli <- function(n, p) {
|
||||
n <- as.bigz(n)
|
||||
p <- as.bigz(p)
|
||||
|
||||
# Check that n is a quadratic residue
|
||||
leg <- legendre(n, p)
|
||||
if (!identical(as.character(leg), "1")) {
|
||||
stop("not a square (mod p)")
|
||||
}
|
||||
|
||||
q <- sub.bigz(p, 1)
|
||||
s <- 0
|
||||
while (mod.bigz(q, 2) == 0) {
|
||||
q <- div.bigz(q, 2)
|
||||
s <- s + 1
|
||||
}
|
||||
|
||||
if (s == 1) {
|
||||
e <- div.bigz(add.bigz(p, 1), 4)
|
||||
return(powm(n, e, p))
|
||||
}
|
||||
|
||||
z <- as.bigz(2)
|
||||
p_minus_1 <- sub.bigz(p, 1)
|
||||
while (z < p) {
|
||||
if (identical(as.character(legendre(z, p)), as.character(p_minus_1))) {
|
||||
break
|
||||
}
|
||||
z <- add.bigz(z, 1)
|
||||
}
|
||||
|
||||
c <- powm(z, q, p)
|
||||
r <- powm(n, div.bigz(add.bigz(q, 1), 2), p)
|
||||
t <- powm(n, q, p)
|
||||
m <- s
|
||||
|
||||
one <- as.bigz(1)
|
||||
two <- as.bigz(2)
|
||||
|
||||
while (!identical(mod.bigz(sub.bigz(t, one), p), as.bigz(0))) {
|
||||
t2 <- mod.bigz(mul.bigz(t, t), p)
|
||||
i <- 1
|
||||
while (i < m) {
|
||||
if (identical(mod.bigz(sub.bigz(t2, one), p), as.bigz(0))) {
|
||||
break
|
||||
}
|
||||
t2 <- mod.bigz(mul.bigz(t2, t2), p)
|
||||
i <- i + 1
|
||||
}
|
||||
|
||||
b_exp <- pow.bigz(two, m - i - 1)
|
||||
b <- powm(c, b_exp, p)
|
||||
r <- mod.bigz(mul.bigz(r, b), p)
|
||||
c <- mod.bigz(mul.bigz(b, b), p)
|
||||
t <- mod.bigz(mul.bigz(t, c), p)
|
||||
m <- i
|
||||
}
|
||||
|
||||
return(r)
|
||||
}
|
||||
|
||||
# Test cases
|
||||
ttest <- list(
|
||||
c("10", "13"),
|
||||
c("56", "101"),
|
||||
c("1030", "10009"),
|
||||
c("44402", "100049"),
|
||||
c("665820697", "1000000009"),
|
||||
c("881398088036", "1000000000039"),
|
||||
c("41660815127637347468140745042827704103445750172002", "100000000000000000000000000000000000000000000000577")
|
||||
)
|
||||
|
||||
for (case in ttest) {
|
||||
n <- as.bigz(case[1])
|
||||
p <- as.bigz(case[2])
|
||||
r <- tonelli(n, p)
|
||||
check <- mod.bigz(sub.bigz(mul.bigz(r, r), n), p)
|
||||
|
||||
# Verify the result
|
||||
if (!identical(as.character(check), "0")) {
|
||||
stop("Verification failed")
|
||||
}
|
||||
|
||||
cat("n =", as.character(n), "p =", as.character(p), "\n")
|
||||
cat("\troots :", as.character(r), as.character(sub.bigz(p, r)), "\n")
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
import java.math.BigInteger
|
||||
import scala.collection.immutable.List
|
||||
import scala.annotation.tailrec
|
||||
|
||||
object TonelliShanks {
|
||||
private val ZERO = BigInteger.ZERO
|
||||
private val ONE = BigInteger.ONE
|
||||
private val TEN = BigInteger.TEN
|
||||
private val TWO = BigInteger.valueOf(2)
|
||||
private val FOUR = BigInteger.valueOf(4)
|
||||
|
||||
private case class Solution(root1: BigInteger, root2: BigInteger, exists: Boolean)
|
||||
|
||||
private def ts(n: Long, p: Long): Solution = ts(BigInteger.valueOf(n), BigInteger.valueOf(p))
|
||||
|
||||
private def ts(n: BigInteger, p: BigInteger): Solution = {
|
||||
val powModP: (BigInteger, BigInteger) => BigInteger = (a, e) => a.modPow(e, p)
|
||||
val ls: BigInteger => BigInteger = a => powModP(a, p.subtract(ONE).divide(TWO))
|
||||
|
||||
if (!ls(n).equals(ONE)) return Solution(ZERO, ZERO, false)
|
||||
|
||||
var q = p.subtract(ONE)
|
||||
var ss = ZERO
|
||||
while (q.and(ONE).equals(ZERO)) {
|
||||
ss = ss.add(ONE)
|
||||
q = q.shiftRight(1)
|
||||
}
|
||||
|
||||
if (ss.equals(ONE)) {
|
||||
val r1 = powModP(n, p.add(ONE).divide(FOUR))
|
||||
return Solution(r1, p.subtract(r1), true)
|
||||
}
|
||||
|
||||
var z = TWO
|
||||
while (!ls(z).equals(p.subtract(ONE))) z = z.add(ONE)
|
||||
var c = powModP(z, q)
|
||||
var r = powModP(n, q.add(ONE).divide(TWO))
|
||||
var t = powModP(n, q)
|
||||
var m = ss
|
||||
|
||||
// Convert the while(true) loop to a tail-recursive function
|
||||
@tailrec
|
||||
def loop(r: BigInteger, c: BigInteger, t: BigInteger, m: BigInteger): Solution = {
|
||||
if (t.equals(ONE)) {
|
||||
Solution(r, p.subtract(r), true)
|
||||
} else {
|
||||
var i = ZERO
|
||||
var zz = t
|
||||
while (!zz.equals(BigInteger.ONE) && i.compareTo(m.subtract(ONE)) < 0) {
|
||||
zz = zz.multiply(zz).mod(p)
|
||||
i = i.add(ONE)
|
||||
}
|
||||
var b = c
|
||||
var e = m.subtract(i).subtract(ONE)
|
||||
while (e.compareTo(ZERO) > 0) {
|
||||
b = b.multiply(b).mod(p)
|
||||
e = e.subtract(ONE)
|
||||
}
|
||||
val newR = r.multiply(b).mod(p)
|
||||
val newC = b.multiply(b).mod(p)
|
||||
val newT = t.multiply(newC).mod(p)
|
||||
val newM = i
|
||||
loop(newR, newC, newT, newM)
|
||||
}
|
||||
}
|
||||
|
||||
loop(r, c, t, m)
|
||||
}
|
||||
|
||||
def main(args: Array[String]): Unit = {
|
||||
val pairs = List(
|
||||
(10L, 13L),
|
||||
(56L, 101L),
|
||||
(1030L, 10009L),
|
||||
(1032L, 10009L),
|
||||
(44402L, 100049L),
|
||||
(665820697L, 1000000009L),
|
||||
(881398088036L, 1000000000039L)
|
||||
)
|
||||
|
||||
for ((n, p) <- pairs) {
|
||||
val sol = ts(n, p)
|
||||
println(s"n = $n")
|
||||
println(s"p = $p")
|
||||
if (sol.exists) {
|
||||
println(s"root1 = ${sol.root1}")
|
||||
println(s"root2 = ${sol.root2}")
|
||||
} else {
|
||||
println("No solution exists")
|
||||
}
|
||||
println()
|
||||
}
|
||||
|
||||
val bn = new BigInteger("41660815127637347468140745042827704103445750172002")
|
||||
val bp = TEN.pow(50).add(BigInteger.valueOf(577))
|
||||
val sol = ts(bn, bp)
|
||||
println(s"n = $bn")
|
||||
println(s"p = $bp")
|
||||
if (sol.exists) {
|
||||
println(s"root1 = ${sol.root1}")
|
||||
println(s"root2 = ${sol.root2}")
|
||||
} else {
|
||||
println("No solution exists")
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue