This repository for essential number theory laws and methods
- x % n = r
- 0 <= r <= n-1
- x = q * n + r
- ((a - b) % c + c) % c → This is genral formula for C++
- (a + b) % c = (a % c + b % c) % c
- (a * b) % c = (a % c * b % c) % c
- (a - b) % c = (a % c - b % c + c) % c
- (a / b) % c = (a % b * b-1 % c) % c
def power(x,n):
ans = 1
for i in range(n):
ans *= x
return ans
def fast_power(x,n):
ans = 1
while n:
if n % 2:
ans *= x
x *= x
n //= 2
return ans
Fermat’s little theorem : if P is prime number and a is any positive integer not divisible by P then:
for all values of a between 1 and P-1
import random
def fermat(n: int,k:int = 128) -> bool:
for _ in range(k):
x = random.randint(1,n-1)
if pow(x,n-1,n) != 1:
return False
return True
Factorization means to find all factors (divisors) of a number
def factorization(n):
factors = []
for i in range(1,n+1):
if n % i == 0:
factors.append(i)
return factors
def factorization(n):
factors = []
i = 1
while i * i <= n:
if n % i == 0:
if n // i == i:
factors.append(i)
else:
factors.append(i)
factors.append(n // i)
i += 1
return factors
def prime_factorization(n):
prime_factors = []
i = 2
end = n
while i*i <= end:
while n % i == 0:
prime_factors.append(i)
n //= i
i += 1
if n != 1:
prime_factors.append(n)
return prime_factors
Note:
- gcd → Greatest Common Divisor
- co-primes → have no common divisors
Assume that gcd(r0,r1) → g and r0 > r1
Ex: gcd(20,15)
r0 = g * x
r1 = g * y
where x > y, and x and y are co-primes
by subtracting r1 from r0
r0 - r1 = (g * x) - (g * y) = g * (x - y)
it's ovious that (x - y) and y are also co-primes
and by comparing the two equations:
- x = q * n + r → r = x - q * n
- r0 - r1 = (g * x) - (g * y)
we found that r in the first equation is exactly r0 - r0 in the secod on
we can refer to r0 - r1 with r2
then we can say that gcd(r0,r1) → gcd(r1,r0 - r1) → gcd(r1,r2) → gcd(g * y , g * (x - y))
As we can repeat this procces as much as we want
we repeat it until it becomes gcd(rn,0)
and as you can observe that we get the result of gcd(r0,r1) → rn.
And as you observe, we can replace the subtraction with modulus (%).
def GCD(n: int, m: int) -> int:
if m == 0:
return n
return GCD(m, n % m)
Note: When GCD(n,m) = 1 → called Co-Prime
def LCD(n: int, m: int) -> int:
return (n*m) // GCD(n,m)
gcd(r0,r1) = s * r0 + t * r1
our goal now is to find the gcd(r0,r1) and the values of s and t.
As we know earlier
i | gcd(ri-2,ri-1) | ri-2 = ri-1 * qi-1 + ri | ri = [si] * r0 + [ti] * r1 |
---|---|---|---|
2 | gcd(973,301) | 973 = 3 * 301 + 70 | 70 = [1] * 973 + [-3] * 301 70 = [1] * r0 + [-3] * r1 |
3 | gcd(301,70) | 301 = 4 * 70 + 21 | 21 = 301 + (-4) * 70 21 = 301 + (-4) * (973 + (-3) * 301) 21 = [-4] * 973 + [13] * 301 21 = [-4] * r0 + [13] * r1 |
4 | gcd(70,21) | 70 = 3 * 21 + 7 | 7 = 70 + (-3) * 21 7 = r2 + (-3) * r3 7 = ( [1] * r0 + [-3] * r1 ) + (-3) * ( [-4] * r0 + [13] * r1 ) 7 = [13] * r0 + [-42] * r1 |
_ | gcd(21,7) | 21 = 3 * 7 + 0 | _ |
As you observe that we go through this process untill the ri becomes 0.
The final formula for ri , si and ti is :
- ri = ri-2 + (-qi-1) * ri-1
- si = si-2 + (-qi-1) * si-1
- ti = ti-2 + (-qi-1) * ti-1
After all of these equations we know that :
- s0 = 1 , s1 = 0
- t0 = 0 , t1 = 1
def EEA(r0,r1):
s0 , s1 = 1 , 0
t0 , t1 = 0 , 1
# swap the two numbers if the second one is greater than the first one.
if r1 > r0:
r0 , r1 = r1 , r0
while r1:
q = (r0 // r1) # compute the quotient
# put r1 in r0 and compute the next r and put it in r1
r0 , r1 = r1 , r0 - q * r1
# put s1 in s0 and compute the next s and put it in s1
s0 , s1 = s1 , s0 - q * s1
# put t1 in t0 and compute the next t and put it in t1
t0 , t1 = t1 , t0 - q * t1
# r0 -> GCD
# s0 -> s
# t0 -> t
return r0 , s0 , t0 # return t0 % the initial r0 to get positive value (for Modular Multiplication Inverse).
The problem is a-1 = ? (mod n)
a * a-1 = 1 (mod n)
First before computing the a-1 we should know that to have a modular multiplicative inverse of number a :
- gcd(n,a) = 1 → co-primes.
- a-1 will be withen range of (0,n-1).
as we do in Extend Euclidean Algorithm.
gcd(n,a) = n * s + a * t
1 = n * s + a * t (mod n)
1 = 0 + (a * t) mod n
then there is a modular multiplicative inverse of a.
def modular_multiplicative_inverse(a,n):
a %= n
for i in range(1,n):
if (a * i) % n == 1:
return i
return None
Apply the Extend Euclidean Algorithm and get the value of [t] this will be the modular multiplicative inverse.
def modular_multiplicative_inverse(a,n):
return EEA(n,a)[2]