The Mastery of Computer Programming: Primary Algorithms  Sykalo Eugene 2023
Elementary concepts of number theory
The Mathematical Background
Basic Number Theory Concepts
Number theory is the study of the properties of numbers, particularly integers. It is a branch of mathematics that has applications in computer science, cryptography, and other areas of science and engineering. In this section, we will introduce some of the basic concepts of number theory that are relevant to computer programming.
Prime Numbers
A prime number is a positive integer greater than 1 that has no positive integer divisors other than 1 and itself. For example, 2, 3, 5, 7, 11, and 13 are all prime numbers. Prime numbers have many interesting properties and are used extensively in number theory and cryptography.
Divisibility Rules
Divisibility rules are used to determine whether a number is divisible by another number without performing division. For example, a number is divisible by 2 if its last digit is even, and a number is divisible by 3 if the sum of its digits is divisible by 3. Divisibility rules can be used to quickly determine whether a number is prime or composite.
Modular Arithmetic
Modular arithmetic is a system of arithmetic for integers that considers only remainders. In modular arithmetic, two integers are considered equivalent if they have the same remainder when divided by a fixed integer called the modulus. Modular arithmetic is used extensively in cryptography and computer science.
Greatest Common Divisor
The greatest common divisor (GCD) of two integers is the largest positive integer that divides both integers without leaving a remainder. The Euclidean algorithm is a fast and efficient algorithm for finding the GCD of two integers.
Least Common Multiple
The least common multiple (LCM) of two integers is the smallest positive integer that is a multiple of both integers. The LCM can be found using the GCD and the fact that LCM(a,b) = (a*b)/GCD(a,b).
Congruences
Congruences are equations that relate two integers modulo a fixed integer. For example, a ≡ b (mod n) means that a and b have the same remainder when divided by n. Congruences are used extensively in number theory and cryptography.
Chinese Remainder Theorem
The Chinese Remainder Theorem is a theorem in number theory that states that if we know the remainders of an unknown integer x when divided by several integers, then we can determine x uniquely up to a certain modulus. The Chinese Remainder Theorem is used extensively in cryptography and computer science.
Euclidean Algorithm
The Euclidean algorithm is a fast and efficient algorithm for finding the greatest common divisor (GCD) of two integers. The basic idea behind the algorithm is to repeatedly replace one of the two integers with the difference of the two integers until the two integers are equal. The GCD of the original two integers is then equal to the final value of the two integers.
More formally, let a and b be two positive integers. We can perform the following steps to find their GCD:
 If a=b, then the GCD of a and b is a (or b).
 If a>b, replace a with ab and go to step 1.
 If b>a, replace b with ba and go to step 1.
The Euclidean algorithm is guaranteed to terminate after a finite number of steps because each step reduces the sum of the two integers by at least one. The algorithm is also very efficient, with a worstcase time complexity of O(log(min(a,b))).
The Euclidean algorithm has many applications in computer programming, particularly in cryptography and computer security. For example, it can be used to compute the GCD of two large integers, which is an important component of many cryptographic algorithms.
Example
Let's use the Euclidean algorithm to find the GCD of 84 and 18:
84  18 = 66
66  18 = 48
48  18 = 30
30  18 = 12
12  18 = 6
12  (6) = 18
Since the two integers are now equal, the GCD of 84 and 18 is 18.
Sieve of Eratosthenes
The Sieve of Eratosthenes is an algorithm used to find all prime numbers up to a certain limit. It works by iteratively marking as composite (i.e., not prime) the multiples of each prime, starting with the multiples of 2. The algorithm terminates when the square of the next prime exceeds the given limit.
The algorithm can be implemented as follows:
 Create a list of consecutive integers from 2 through n: (2, 3, 4, ..., n).
 Initially, let p equal 2, the smallest prime number.
 Enumerate the multiples of p by counting in increments of p from p\*p to n, and mark them in the list (these will be 2p, 3p, 4p, ..., ; the p itself should not be marked).
 Find the smallest prime number greater than p that is not marked. If there was no such number, stop. Otherwise, let p now equal this new number (which is the next prime), and repeat from step 3.
At the end of the algorithm, all the numbers in the list that are not marked are prime.
The Sieve of Eratosthenes is a very efficient algorithm for finding primes, with a time complexity of O(n log log n) for finding all primes up to n. It is particularly useful for finding primes in a small range of values, and has many applications in computer science and cryptography.
Fast Modular Exponentiation
Fast modular exponentiation is an algorithm used to compute large powers of numbers modulo another number. It is a crucial algorithm in cryptography and is widely used in computer programming applications. The basic idea behind the algorithm is to break the exponent down into its binary representation and use that to compute the result.
More formally, let a, b, and m be three positive integers. We want to compute a^b (mod m). We can perform the following steps to compute this value:
 Write b in binary form: b = b<sub>k</sub>b<sub>k1</sub>...b<sub>1</sub>b<sub>0</sub>, where b<sub>k</sub> is the most significant bit and b<sub>0</sub> is the least significant bit.
 Set c = a and result = 1.
 For i from k down to 0:
 Square result: result = result * result (mod m).
 If b<sub>i</sub> = 1, then multiply result by c: result = result * c (mod m).
 Return result.
The algorithm works by computing a series of powers of c, starting with c<sup>1</sup>, c<sup>2</sup>, c<sup>4</sup>, c<sup>8</sup>, and so on, up to c<sup>2<sup>k</sup></sup>, where k is the number of bits in the binary representation of b. The result is then computed by multiplying together the powers of c that correspond to the 1 bits in the binary representation of b.
The fast modular exponentiation algorithm is very efficient, with a worstcase time complexity of O(log b). This makes it ideal for computing large powers of numbers modulo another number, which is a common operation in cryptographic algorithms.
Example
Let's use the fast modular exponentiation algorithm to compute 2^13 (mod 7):
 Write 13 in binary form: 13 = 1101<sub>2</sub>.
 Set c = 2 and result = 1.
 For i from 3 down to 0:
 Square result: result = 1 * 1 (mod 7) = 1.
 If b<sub>i</sub> = 1, then multiply result by c: result = 1 * 2 (mod 7) = 2.
 Square c: c = 2 * 2 (mod 7) = 4.
 Return result: 2^13 (mod 7) = 2.
Therefore, 2^13 is equivalent to 2 modulo 7.
Applications
Fast modular exponentiation has many applications in computer programming, particularly in cryptography and computer security. For example, it is used in the RSA cryptosystem to encrypt and decrypt messages, and in the DiffieHellman key exchange protocol to securely exchange cryptographic keys between two parties. It is also used in digital signature algorithms, hash functions, and other cryptographic applications.
RSA Cryptosystem
The RSA cryptosystem is a widely used publickey encryption algorithm. It was developed in 1977 by Ron Rivest, Adi Shamir, and Leonard Adleman and is named after their last names. The RSA cryptosystem is based on the fact that it is easy to multiply two large prime numbers together, but it is very difficult to factor the product of two large prime numbers back into the original primes.
The RSA cryptosystem works as follows:
 Key Generation: A user generates a pair of public and private keys. The public key consists of two numbers: a modulus n that is the product of two large prime numbers, and an integer e that is relatively prime to (n1). The private key consists of the modulus n and an integer d such that e*d ≡ 1 (mod n1).
 Encryption: To encrypt a message, the sender converts the message into a number m that is smaller than n, and then raises it to the power of e modulo n. The resulting ciphertext c is sent to the receiver.
 Decryption: To decrypt the ciphertext, the receiver raises it to the power of d modulo n. The resulting plaintext m is the original message.
The security of the RSA cryptosystem is based on the fact that it is very difficult to factor the product of two large prime numbers. An attacker who knows the public key (n,e) cannot easily determine the private key d without factoring n, which is believed to be a computationally difficult problem for large values of n.
The RSA cryptosystem has many applications in computer security and cryptography. It is used in secure communication protocols such as HTTPS, SSL, and TLS, as well as in digital signature algorithms, hash functions, and other cryptographic applications.
Example
Let's walk through an example of the RSA cryptosystem using small values for the keys and message:

Key Generation:
 Choose two prime numbers: p=7 and q=11.
 Compute the modulus: n = pq = 711 = 77.
 Compute the totient of n: φ(n) = (p1)(q1) = 610 = 60.
 Choose an integer e such that 1 < e < φ(n) and e is relatively prime to φ(n): e=13.
 Compute d such that e*d ≡ 1 (mod φ(n)): d = 37.
The public key is (n,e) = (77,13) and the private key is d=37.

Encryption:
 Convert the message "HELLO" to a number m: m = 827273441 = 3,053,464.
 Compute the ciphertext c: c ≡ m^e (mod n) = 3,053,464^13 (mod 77) = 62.
The ciphertext is 62.

Decryption:
 Compute the plaintext m: m ≡ c^d (mod n) = 62^37 (mod 77) = 3,053,464.
The plaintext is 3,053,464, which corresponds to the original message "HELLO".
Security
The security of the RSA cryptosystem is based on the fact that it is very difficult to factor the product of two large prime numbers. However, it is possible to break RSA using a variety of attacks, particularly if the keys are not generated properly or if the implementation is flawed.
Some of the attacks on RSA include:
 Brute force attack: Trying every possible private key until the correct one is found.
 Factoring attack: Factoring the modulus n to determine the private key d.
 Sidechannel attacks: Exploiting weaknesses in the implementation of RSA, such as timing or power consumption measurements.
To protect against these attacks, it is important to generate strong keys using a secure random number generator, to use appropriate key sizes, and to implement RSA correctly and securely.