Path: blob/master/attacks/pseudoprimes/miller_rabin.py
2589 views
import logging1import os2import sys3from math import gcd45from sage.all import is_prime6from sage.all import kronecker7from sage.all import next_prime89path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(os.path.abspath(__file__)))))10if sys.path[1] != path:11sys.path.insert(1, path)1213from shared.crt import fast_crt141516def _generate_s(A, k):17S = []18for a in A:19# Possible non-residues mod 4a of potential primes p20Sa = set()21for p in range(1, 4 * a, 2):22if kronecker(a, p) == -1:23Sa.add(p)2425# Subsets of Sa that meet the intersection requirement26Sk = []27for ki in k:28assert gcd(ki, 4 * a) == 129Sk.append({pow(ki, -1, 4 * a) * (s + ki - 1) % (4 * a) for s in Sa})3031S.append(Sa.intersection(*Sk))3233return S343536# Brute forces a combination of residues from S by backtracking37# X already contains the remainders mod each k38# M already contains each k39def _backtrack(S, A, X, M, i):40if i == len(S):41return fast_crt(X, M)4243M.append(4 * A[i])44for za in S[i]:45X.append(za)46try:47fast_crt(X, M)48z, m = _backtrack(S, A, X, M, i + 1)49if z is not None and m is not None:50return z, m51except ValueError:52pass53X.pop()5455M.pop()56return None, None575859def generate_pseudoprime(A, k2=None, k3=None, min_bit_length=0):60"""61Generates a pseudoprime of the form p1 * p2 * p3 which passes the Miller-Rabin primality test for the provided bases.62More information: R. Albrecht M. et al., "Prime and Prejudice: Primality Testing Under Adversarial Conditions"63:param A: the bases64:param k2: the k2 value (default: next_prime(A[-1]))65:param k3: the k3 value (default: next_prime(k2))66:param min_bit_length: the minimum bit length of the generated pseudoprime (default: 0)67:return: a tuple containing the pseudoprime n, as well as its 3 prime factors68"""69A.sort()70if k2 is None:71k2 = int(next_prime(A[-1]))72if k3 is None:73k3 = int(next_prime(k2))74while True:75logging.info(f"Trying {k2 = } and {k3 = }...")76X = [pow(-k3, -1, k2), pow(-k2, -1, k3)]77M = [k2, k3]78S = _generate_s(A, M)79logging.info(f"{S = }")80z, m = _backtrack(S, A, X, M, 0)81if z and m:82logging.info(f"Found residue {z} and modulus {m}")83i = (2 ** (min_bit_length // 3)) // m84while True:85p1 = int(z + i * m)86p2 = k2 * (p1 - 1) + 187p3 = k3 * (p1 - 1) + 188if is_prime(p1) and is_prime(p2) and is_prime(p3):89return p1 * p2 * p3, p1, p2, p39091i += 192else:93k3 = int(next_prime(k3))949596