Competitive Coding

Unit 2: Primality Testing

From naive checks to blazing-fast sieves โ€” master every primality testing algorithm, crack competitive coding problems, and understand the cryptography that secures India's digital payments.

โฑ๏ธ 6 hrs theory + 4 hrs practice  |  ๐Ÿ’ฐ Earning Potential: โ‚น5,000โ€“โ‚น25,000/month  |  ๐Ÿ“ 30 MCQs (Bloom's Mapped)

๐Ÿ’ผ Jobs this unlocks: Cryptography Engineer (โ‚น8โ€“15 LPA)  |  Security Developer (โ‚น6โ€“12 LPA)  |  Competitive Programmer

Section A

Opening Hook โ€” The Invisible Math Guarding Your Money

๐Ÿ” Every UPI Payment You Make is Secured by Prime Numbers

Open PhonePe or Google Pay right now. Send โ‚น1 to a friend. In that fraction of a second, your phone performed RSA encryption โ€” a cryptographic algorithm that relies entirely on the difficulty of factoring the product of two very large prime numbers (each 300+ digits long).

India's UPI processed 13.89 billion transactions worth โ‚น20.64 lakh crore in May 2024 alone. Every single one of those transactions was secured by primality testing. The NPCI (National Payments Corporation of India) uses TLS certificates backed by RSA-2048, which depends on 617-digit prime numbers. If someone could efficiently test and factor these primes, they could intercept every payment on PhonePe, Google Pay, Paytm, and BHIM.

What if YOU understood how this works? What if you could implement the same algorithms that protect billions of rupees? That's exactly what this chapter teaches you โ€” from the simplest O(n) check to the blazing-fast Sieve of Eratosthenes used in competitive programming.

๐Ÿ‡ฎ๐Ÿ‡ณ PhonePe๐Ÿ‡ฎ๐Ÿ‡ณ Google Pay๐Ÿ‡ฎ๐Ÿ‡ณ Razorpay๐Ÿ‡ฎ๐Ÿ‡ณ Paytm๐Ÿ‡ฎ๐Ÿ‡ณ NPCI๐Ÿ‡ฎ๐Ÿ‡ณ BHIM
RSA-2048 uses prime numbers with 617 digits each. To crack it by brute force, you'd need more time than the age of the universe โ€” even with every computer on Earth working together. The security of โ‚น20+ lakh crore in monthly UPI transactions rests on one simple mathematical fact: multiplying two primes is easy, but factoring their product is astronomically hard.
Section B

Learning Outcomes โ€” Bloom's Taxonomy Mapped

Bloom's LevelLearning Outcome
๐Ÿ”ต RememberDefine prime numbers and list their fundamental properties (infinitude, distribution, fundamental theorem of arithmetic)
๐Ÿ”ต RememberState Fermat's Little Theorem and recall the first 25 prime numbers
๐ŸŸข UnderstandExplain why checking divisibility only up to โˆšn is sufficient for primality testing, with mathematical proof
๐ŸŸข UnderstandDescribe the Sieve of Eratosthenes algorithm step-by-step and trace it for any given n
๐ŸŸก ApplyImplement the O(โˆšn) primality test in both C++ and Python with edge-case handling
๐ŸŸก ApplyCode the Sieve of Eratosthenes to generate all primes up to N = 10โท
๐ŸŸ  AnalyzeCompare time complexities of naive O(n), O(โˆšn), Fermat, and Sieve methods for different input ranges
๐ŸŸ  AnalyzeAnalyze why Carmichael numbers are problematic for the Fermat primality test and identify examples
๐Ÿ”ด EvaluateAssess when to use deterministic vs probabilistic primality tests based on problem constraints
๐Ÿ”ด EvaluateEvaluate Sieve of Eratosthenes vs Segmented Sieve trade-offs for different memory and range requirements
๐ŸŸฃ CreateDesign a comprehensive prime-testing library that combines multiple algorithms with automatic method selection
๐ŸŸฃ CreateBuild a segmented sieve for arbitrary range [L, R] queries where R can be up to 10โน
Section C

Concept Explanation โ€” Primality Testing from Scratch

1. Introduction to Primality Testing

What is a prime number? A prime number is a natural number greater than 1 that has no positive divisors other than 1 and itself. The first few primes are: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47.

Note that 2 is the only even prime. Every even number greater than 2 is divisible by 2, so it cannot be prime. Also, 1 is NOT prime by convention (it has only one divisor, not two).

๐Ÿ”ข Why Do Primes Matter?

1. Cryptography (RSA): RSA encryption relies on the product of two large primes. Multiplying them is easy (milliseconds), but factoring the result takes billions of years. This asymmetry secures all online banking, UPI payments, and HTTPS websites.

2. Hash Tables: Using prime numbers as hash table sizes reduces collisions. Languages like Java use prime-based hash functions internally.

3. Competitive Programming: Primality testing appears in 20%+ of competitive coding problems. Platforms like Codeforces, CodeChef, and LeetCode regularly feature prime-based problems.

4. Random Number Generation: Many pseudorandom number generators (PRNGs) use prime moduli for better distribution.

Naive O(n) Primality Test

The simplest approach: check if any number from 2 to n-1 divides n. If yes, n is not prime.

C++
// Naive primality test โ€” O(n) time complexity
#include <iostream>
using namespace std;

bool isPrime(int n) {
    if (n <= 1) return false;
    for (int i = 2; i < n; i++) {
        if (n % i == 0) return false;
    }
    return true;
}

int main() {
    int n;
    cout << "Enter a number: ";
    cin >> n;
    if (isPrime(n))
        cout << n << " is PRIME" << endl;
    else
        cout << n << " is NOT prime" << endl;
    return 0;
}
Python
# Naive primality test โ€” O(n) time complexity
def is_prime(n):
    if n <= 1:
        return False
    for i in range(2, n):
        if n % i == 0:
            return False
    return True

n = int(input("Enter a number: "))
if is_prime(n):
    print(f"{n} is PRIME")
else:
    print(f"{n} is NOT prime")
This O(n) approach is WAY too slow for large numbers. For n = 10โน (1 billion), this loop runs 1 billion times. At ~10โธ operations/second, that's 10 seconds โ€” far too slow for competitive coding where time limits are typically 1-2 seconds.

2. O(โˆšn) Optimized Primality Test

Key Insight: If n = a ร— b where both a and b are greater than โˆšn, then a ร— b > โˆšn ร— โˆšn = n, which is a contradiction. Therefore, if n has any factor other than 1 and itself, at least one factor must be โ‰ค โˆšn.

๐Ÿ“ Mathematical Proof: Why โˆšn is Sufficient

Theorem: If n is composite, then n has a prime factor p where p โ‰ค โˆšn.

Proof: Let n be composite. Then n = a ร— b where 1 < a โ‰ค b < n. Since a โ‰ค b, we have a ร— a โ‰ค a ร— b = n, therefore a โ‰ค โˆšn. Since a > 1 and a divides n, a has a prime factor p that also divides n, and p โ‰ค a โ‰ค โˆšn. โˆŽ

Practical impact: For n = 10โน, instead of checking 10โน divisors, we check only โˆš(10โน) โ‰ˆ 31,623 divisors. That's a 31,600ร— speedup!

C++
// O(โˆšn) primality test โ€” optimized
#include <iostream>
#include <cmath>
using namespace std;

bool isPrime(int n) {
    if (n <= 1) return false;
    if (n <= 3) return true;
    if (n % 2 == 0 || n % 3 == 0) return false;
    for (int i = 5; i * i <= n; i += 6) {
        if (n % i == 0 || n % (i + 2) == 0)
            return false;
    }
    return true;
}

int main() {
    int n;
    cout << "Enter number: ";
    cin >> n;
    cout << n << (isPrime(n) ? " is PRIME" : " is NOT prime") << endl;
    return 0;
}
Python
# O(โˆšn) primality test โ€” optimized with 6kยฑ1 trick
def is_prime(n):
    if n <= 1: return False
    if n <= 3: return True
    if n % 2 == 0 or n % 3 == 0: return False
    i = 5
    while i * i <= n:
        if n % i == 0 or n % (i + 2) == 0:
            return False
        i += 6
    return True
The 6kยฑ1 optimization: All primes greater than 3 are of the form 6kยฑ1. Why? Because any integer can be written as 6k, 6k+1, 6k+2, 6k+3, 6k+4, or 6k+5. Of these, 6k is divisible by 6, 6k+2 and 6k+4 by 2, and 6k+3 by 3. So only 6k+1 and 6k+5 (= 6(k+1)-1) can be prime. This lets us skip 2/3 of all candidates!

3. Factorization of a Number

Trial division finds all prime factors by repeatedly dividing by the smallest possible factor. The optimized approach runs in O(โˆšn) time.

C++
// Find ALL prime factors of n โ€” O(โˆšn)
#include <iostream>
#include <vector>
using namespace std;

vector<int> primeFactors(int n) {
    vector<int> factors;
    while (n % 2 == 0) {
        factors.push_back(2);
        n /= 2;
    }
    for (int i = 3; i * i <= n; i += 2) {
        while (n % i == 0) {
            factors.push_back(i);
            n /= i;
        }
    }
    if (n > 1) factors.push_back(n);
    return factors;
}

int main() {
    int n = 84;
    auto f = primeFactors(n);
    cout << "Prime factors of " << n << ": ";
    for (int x : f) cout << x << " ";
    return 0;
}
Python
# Find ALL prime factors of n โ€” O(โˆšn)
def prime_factors(n):
    factors = []
    while n % 2 == 0:
        factors.append(2)
        n //= 2
    i = 3
    while i * i <= n:
        while n % i == 0:
            factors.append(i)
            n //= i
        i += 2
    if n > 1:
        factors.append(n)
    return factors

print(prime_factors(84))  # [2, 2, 3, 7]

4. Finding Prime Factors by Taking Square Root

๐Ÿ“ Worked Example: n = 84

Step 1: 84 รท 2 = 42 โ†’ Factor found: 2

Step 2: 42 รท 2 = 21 โ†’ Factor found: 2

Step 3: 21 รท 3 = 7 โ†’ Factor found: 3

Step 4: 7 > 1 and โˆš7 โ‰ˆ 2.6 < 3 (next candidate), so 7 is prime โ†’ Factor found: 7

Result: 84 = 2ยฒ ร— 3ยน ร— 7ยน

Prime factors of 84: 2 2 3 7 84 = 2^2 ร— 3^1 ร— 7^1

5. Fermat Primality Test

๐Ÿ”ฌ Fermat's Little Theorem

Statement: If p is a prime number and a is any integer not divisible by p, then:

apโˆ’1 โ‰ก 1 (mod p)

Example: Let p = 7, a = 2. Then 2โถ = 64. And 64 mod 7 = 1. โœ“ Confirmed!

Contrapositive: If anโˆ’1 โ‰ข 1 (mod n), then n is definitely composite.

The Test: Pick random values of a. If any gives anโˆ’1 โ‰ข 1 (mod n), n is composite. If all pass, n is probably prime.

C++
// Fermat Primality Test โ€” Probabilistic
#include <iostream>
#include <cstdlib>
using namespace std;

long long power(long long base, long long exp, long long mod) {
    long long result = 1;
    base %= mod;
    while (exp > 0) {
        if (exp % 2 == 1)
            result = (result * base) % mod;
        exp /= 2;
        base = (base * base) % mod;
    }
    return result;
}

bool fermatTest(int n, int k) {
    if (n <= 1) return false;
    if (n <= 3) return true;
    for (int i = 0; i < k; i++) {
        int a = 2 + rand() % (n - 3);
        if (power(a, n - 1, n) != 1)
            return false;
    }
    return true;
}
Python
# Fermat Primality Test โ€” Probabilistic
import random

def fermat_test(n, k=10):
    if n <= 1: return False
    if n <= 3: return True
    for _ in range(k):
        a = random.randint(2, n - 2)
        if pow(a, n - 1, n) != 1:
            return False
    return True

print(fermat_test(7))    # True
print(fermat_test(561))  # True! (FALSE POSITIVE โ€” Carmichael number)
print(fermat_test(15))   # False
Beware of Carmichael numbers! These are composite numbers that pass the Fermat test for ALL coprime bases. Examples: 561 = 3ร—11ร—17, 1105 = 5ร—13ร—17, 1729 = 7ร—13ร—19 (also the Hardy-Ramanujan number!). The Fermat test will say these are "prime" โ€” but they're not. For competitive coding, prefer the deterministic O(โˆšn) test or Miller-Rabin.

6. Sieve of Eratosthenes โญ MOST IMPORTANT

The Sieve of Eratosthenes is the single most important algorithm in this entire unit. It generates ALL prime numbers up to n in O(n log log n) time. If you learn only one thing from this chapter, learn this.

Think of the Sieve like filtering wheat at a kirana (grocery) store. You start with a big pile of grains (numbers 2 to n). You pass it through a sieve โ€” the first sieve removes all chaff divisible by 2, the next removes chaff divisible by 3, then 5, and so on. What's left after all the filtering? Only the pure wheat โ€” the prime numbers!

๐Ÿ“Š Algorithm Step-by-Step

Step 1: Create a boolean array is_prime[0..n], initialized to true.

Step 2: Mark is_prime[0] and is_prime[1] as false (not prime).

Step 3: Start with p = 2 (first prime).

Step 4: Mark all multiples of p (starting from pยฒ) as false.

Step 5: Find the next unmarked number โ€” that's the next prime.

Step 6: Repeat until pยฒ > n.

Step 7: All remaining true entries are primes!

ASCII Visualization: Sieve for n = 30

StepNumbers 2โ€“30 (โœ“ = prime candidate, โœ— = crossed out)
Initialโœ“2 โœ“3 โœ“4 โœ“5 โœ“6 โœ“7 โœ“8 โœ“9 โœ“10 โœ“11 โœ“12 โœ“13 โœ“14 โœ“15 โœ“16 โœ“17 โœ“18 โœ“19 โœ“20 โœ“21 โœ“22 โœ“23 โœ“24 โœ“25 โœ“26 โœ“27 โœ“28 โœ“29 โœ“30
p=2
Cross 4,6,8โ€ฆ30
โœ“2 โœ“3 โœ—4 โœ“5 โœ—6 โœ“7 โœ—8 โœ“9 โœ—10 โœ“11 โœ—12 โœ“13 โœ—14 โœ“15 โœ—16 โœ“17 โœ—18 โœ“19 โœ—20 โœ“21 โœ—22 โœ“23 โœ—24 โœ“25 โœ—26 โœ“27 โœ—28 โœ“29 โœ—30
p=3
Cross 9,15,21,27
โœ“2 โœ“3 โœ—4 โœ“5 โœ—6 โœ“7 โœ—8 โœ—9 โœ—10 โœ“11 โœ—12 โœ“13 โœ—14 โœ—15 โœ—16 โœ“17 โœ—18 โœ“19 โœ—20 โœ—21 โœ—22 โœ“23 โœ—24 โœ“25 โœ—26 โœ—27 โœ—28 โœ“29 โœ—30
p=5
Cross 25
โœ“2 โœ“3 โœ—4 โœ“5 โœ—6 โœ“7 โœ—8 โœ—9 โœ—10 โœ“11 โœ—12 โœ“13 โœ—14 โœ—15 โœ—16 โœ“17 โœ—18 โœ“19 โœ—20 โœ—21 โœ—22 โœ“23 โœ—24 โœ—25 โœ—26 โœ—27 โœ—28 โœ“29 โœ—30
Done!
โˆš30 โ‰ˆ 5.47
Primes: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 (10 primes found)
C++
// Sieve of Eratosthenes โ€” O(n log log n)
#include <iostream>
#include <vector>
using namespace std;

vector<int> sieve(int n) {
    vector<bool> is_prime(n + 1, true);
    is_prime[0] = is_prime[1] = false;
    for (int p = 2; p * p <= n; p++) {
        if (is_prime[p]) {
            for (int j = p * p; j <= n; j += p)
                is_prime[j] = false;
        }
    }
    vector<int> primes;
    for (int i = 2; i <= n; i++)
        if (is_prime[i]) primes.push_back(i);
    return primes;
}

int main() {
    auto primes = sieve(30);
    cout << "Primes up to 30: ";
    for (int p : primes) cout << p << " ";
    return 0;
}
Python
# Sieve of Eratosthenes โ€” O(n log log n)
def sieve(n):
    is_prime = [True] * (n + 1)
    is_prime[0] = is_prime[1] = False
    p = 2
    while p * p <= n:
        if is_prime[p]:
            for j in range(p * p, n + 1, p):
                is_prime[j] = False
        p += 1
    return [i for i in range(2, n + 1) if is_prime[i]]

print(sieve(30))
# [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
Primes up to 30: 2 3 5 7 11 13 17 19 23 29

โฑ๏ธ Time Complexity: O(n log log n)

The total work done is: n/2 + n/3 + n/5 + n/7 + n/11 + ... (sum over all primes p โ‰ค n).

This equals n ร— ฮฃ(1/p) for primes p โ‰ค n. By Mertens' theorem, this sum โ‰ˆ log(log n).

So total operations โ‰ˆ O(n log log n). For n = 10โท, log log n โ‰ˆ 3, so it's essentially O(3n) โ€” nearly linear!

Space complexity: O(n) for the boolean array.

Why start marking from pยฒ instead of 2p? Because all composites smaller than pยฒ that are multiples of p have already been marked by smaller primes. For example, when p=5, the composite 10 = 2ร—5 was already marked when p=2, and 15 = 3ร—5 was already marked when p=3. The first unmarked multiple of 5 is 5ยฒ = 25.

7. Segmented Sieve

When n is very large (say 10โน), a regular sieve needs a boolean array of 10โน entries โ€” about 1 GB of RAM. Most competitive programming judges allow only 256 MB. Solution: segmented sieve.

๐Ÿ”ง How Segmented Sieve Works

Step 1: Generate all primes up to โˆšR using the regular sieve (these "small primes" fit easily in memory).

Step 2: Divide the range [L, R] into segments of size ~โˆšR.

Step 3: For each segment, use the small primes to mark composites.

Step 4: Collect unmarked numbers โ€” those are primes in the range.

Memory: O(โˆšR) instead of O(R). For R = 10โน, that's ~31,623 instead of 10โน!

C++
// Segmented Sieve โ€” find primes in range [L, R]
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

vector<long long> segmentedSieve(long long L, long long R) {
    int limit = (int)sqrt((double)R) + 1;
    vector<bool> mark(limit + 1, true);
    vector<int> small_primes;
    for (int p = 2; p <= limit; p++) {
        if (mark[p]) {
            small_primes.push_back(p);
            for (int j = p * p; j <= limit; j += p)
                mark[j] = false;
        }
    }
    vector<bool> is_prime(R - L + 1, true);
    for (int p : small_primes) {
        long long start = max((long long)p * p, ((L + p - 1) / p) * p);
        for (long long j = start; j <= R; j += p)
            is_prime[j - L] = false;
    }
    if (L == 1) is_prime[0] = false;
    vector<long long> result;
    for (long long i = 0; i <= R - L; i++)
        if (is_prime[i]) result.push_back(L + i);
    return result;
}
Python
# Segmented Sieve โ€” find primes in [L, R]
import math

def segmented_sieve(L, R):
    limit = int(math.sqrt(R)) + 1
    # Step 1: small primes via regular sieve
    mark = [True] * (limit + 1)
    small_primes = []
    for p in range(2, limit + 1):
        if mark[p]:
            small_primes.append(p)
            for j in range(p*p, limit+1, p):
                mark[j] = False
    # Step 2: sieve the range [L, R]
    is_prime = [True] * (R - L + 1)
    for p in small_primes:
        start = max(p * p, ((L + p - 1) // p) * p)
        for j in range(start, R + 1, p):
            is_prime[j - L] = False
    if L == 1: is_prime[0] = False
    return [L + i for i in range(R - L + 1) if is_prime[i]]

print(segmented_sieve(100, 150))
# [101, 103, 107, 109, 113, 127, 131, 137, 139, 149]

8. Sieve of Atkins

The Sieve of Atkins is a modern algorithm that uses quadratic forms and modular arithmetic. It has a theoretical time complexity of O(n / log log n), slightly better than Eratosthenes for very large n.

๐Ÿ”ฌ Three Quadratic Forms

The algorithm toggles entries based on solutions to three equations:

Form 1: 4xยฒ + yยฒ โ‰ก 1 (mod 4) โ€” for n โ‰ก 1 (mod 4)

Form 2: 3xยฒ + yยฒ โ‰ก 7 (mod 12) โ€” for n โ‰ก 7 (mod 12)

Form 3: 3xยฒ โˆ’ yยฒ (where x > y) โ‰ก 11 (mod 12) โ€” for n โ‰ก 11 (mod 12)

After toggling, eliminate all multiples of squares of primes.

When to use: Only for very large n (> 10โธ) where the constant factor improvement matters. For most competitive programming, Eratosthenes is preferred due to simplicity.

C++
// Sieve of Atkins โ€” Overview Implementation
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

vector<int> sieveOfAtkins(int limit) {
    vector<bool> sieve(limit + 1, false);
    if (limit > 2) sieve[2] = true;
    if (limit > 3) sieve[3] = true;
    for (int x = 1; x * x <= limit; x++) {
        for (int y = 1; y * y <= limit; y++) {
            int n = 4 * x * x + y * y;
            if (n <= limit && (n % 12 == 1 || n % 12 == 5))
                sieve[n] = !sieve[n];
            n = 3 * x * x + y * y;
            if (n <= limit && n % 12 == 7)
                sieve[n] = !sieve[n];
            n = 3 * x * x - y * y;
            if (x > y && n <= limit && n % 12 == 11)
                sieve[n] = !sieve[n];
        }
    }
    for (int r = 5; r * r <= limit; r++)
        if (sieve[r])
            for (int i = r * r; i <= limit; i += r * r)
                sieve[i] = false;
    vector<int> primes;
    for (int i = 2; i <= limit; i++)
        if (sieve[i]) primes.push_back(i);
    return primes;
}

9. Mansi and Her Series

Problem: Given N, generate first N terms of a series where: if index i is prime, term[i] = i; otherwise, term[i] = smallest prime factor of i.

C++
// Mansi's Series using Smallest Prime Factor (SPF) sieve
#include <iostream>
#include <vector>
using namespace std;

int main() {
    int N = 10;
    vector<int> spf(N + 1);
    for (int i = 0; i <= N; i++) spf[i] = i;
    for (int i = 2; i * i <= N; i++) {
        if (spf[i] == i) {
            for (int j = i * i; j <= N; j += i)
                if (spf[j] == j) spf[j] = i;
        }
    }
    cout << "Mansi's Series: ";
    for (int i = 1; i <= N; i++)
        cout << spf[i] << " ";
    return 0;
}
Mansi's Series: 1 2 3 2 5 2 7 2 3 2

10. Collections of Pens

Problem: Rohan has N pens. He wants to distribute them equally among groups. Find the total number of ways (= number of divisors of N).

C++
// Count divisors using prime factorization
#include <iostream>
using namespace std;

int countDivisors(int n) {
    int count = 1;
    for (int i = 2; i * i <= n; i++) {
        int exp = 0;
        while (n % i == 0) { exp++; n /= i; }
        count *= (exp + 1);
    }
    if (n > 1) count *= 2;
    return count;
}

int main() {
    int n = 12;
    cout << "N = " << n << ", Ways = " << countDivisors(n) << endl;
    // 12 = 2^2 ร— 3^1 โ†’ (2+1)(1+1) = 6
    return 0;
}
N = 12, Ways = 6 (Groups of: 1, 2, 3, 4, 6, or 12 pens each)

11. Next Prime Palindrome

C++
// Find next number that is both prime AND palindrome
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

bool isPrime(int n) {
    if (n <= 1) return false;
    if (n <= 3) return true;
    if (n % 2 == 0 || n % 3 == 0) return false;
    for (int i = 5; i * i <= n; i += 6)
        if (n % i == 0 || n % (i+2) == 0) return false;
    return true;
}

bool isPalindrome(int n) {
    string s = to_string(n);
    string r = s;
    reverse(r.begin(), r.end());
    return s == r;
}

int nextPrimePalindrome(int n) {
    int candidate = n + 1;
    while (true) {
        if (isPalindrome(candidate) && isPrime(candidate))
            return candidate;
        candidate++;
    }
}

int main() {
    cout << "Next prime palindrome after 100: " << nextPrimePalindrome(100) << endl;
    cout << "Next prime palindrome after 7: " << nextPrimePalindrome(7) << endl;
    return 0;
}
Next prime palindrome after 100: 101 Next prime palindrome after 7: 11
Section D

Learn by Doing โ€” 3-Tier Lab Structure

๐ŸŸข Tier 1 โ€” GUIDED: Implement O(โˆšn) Primality Test

โฑ๏ธ 45โ€“60 minutesBeginnerStep-by-step instructions

Step 1: Handle edge cases

n โ‰ค 1 โ†’ not prime. n = 2 or n = 3 โ†’ prime.

Step 2: Check divisibility by 2 and 3

If n % 2 == 0 or n % 3 == 0 โ†’ not prime.

Step 3: Check 6kยฑ1 up to โˆšn

Loop i from 5, step 6. Check n % i and n % (i+2).

Step 4: Test with these inputs

Test: 1, 2, 3, 4, 17, 25, 97, 100, 7919, 1000000007

1 โ†’ NOT prime 2 โ†’ PRIME 3 โ†’ PRIME 4 โ†’ NOT prime 17 โ†’ PRIME 25 โ†’ NOT prime 97 โ†’ PRIME 100 โ†’ NOT prime 7919 โ†’ PRIME 1000000007 โ†’ PRIME

๐ŸŸก Tier 2 โ€” SEMI-GUIDED: Sieve of Eratosthenes

โฑ๏ธ 60โ€“90 minutesIntermediateHints provided

Your Mission:

Generate all primes up to 10โถ and count them.

Hints:

  1. Create a boolean array of size 10โถ + 1, initialized to true
  2. Mark 0 and 1 as false
  3. For each p from 2 where pยฒ โ‰ค n, mark multiples from pยฒ as false
  4. Count and collect all remaining true entries
Stretch Goal: Count twin primes (pairs p, p+2 where both are prime) up to 10โถ. Expected answer: 8169 twin prime pairs.

๐Ÿ”ด Tier 3 โ€” OPEN CHALLENGE: Segmented Sieve for [L, R]

โฑ๏ธ 90โ€“120 minutesAdvancedNo instructions โ€” real contest problem

The Brief:

Given L and R (up to 10โน, R โˆ’ L โ‰ค 10โถ), find and print all primes in the range [L, R]. Your solution must use O(โˆšR) memory.

Test case: L=999999000000, R=1000000000000. How many primes are in this range?

Section E

Problem Set โ€” Practice Questions

Tracing Questions (5)

T1. Trace the Sieve of Eratosthenes for n = 20. Show the array state after each prime's multiples are crossed out.

T2. Trace the O(โˆšn) algorithm for n = 97. List each divisor checked and the final result.

T3. Trace the Fermat test for n = 561 with bases a = 2, 3, 5. Show each computation a^(n-1) mod n.

T4. Trace the prime factorization of n = 360. Show each division step.

T5. Trace the segmented sieve for the range [10, 30] using small primes {2, 3, 5}.

Programming Problems (8)

P1. Count the number of primes up to N. Input: N = 10โถ. Expected output: 78498.

P2. Find the Nth prime number. Input: N = 10001. Expected output: 104743.

P3. Check if a number is a Mersenne prime (of the form 2แต– โˆ’ 1). Test for p = 2, 3, 5, 7, 11, 13.

P4. Find all prime factors of N and print in exponential form. Input: 360 โ†’ Output: 2ยณ ร— 3ยฒ ร— 5ยน.

P5. Generate all twin primes up to N. Twin primes: (3,5), (5,7), (11,13), (17,19), ...

P6. Find the largest prime factor of N. Input: 600851475143. (This is Project Euler Problem 3!)

P7. Count prime palindromes up to N. Input: N = 1000. Expected output: 5 (2, 3, 5, 7, 11).

P8. Sum of all primes up to N using Sieve. Input: N = 2ร—10โถ. Verify your answer.

Industry Application Problems (3)

I1. RSA Key Generation: Given primes p = 61, q = 53, compute n = pร—q, ฯ†(n) = (p-1)(q-1), find e coprime to ฯ†(n), compute d = eโปยน mod ฯ†(n). Encrypt and decrypt the message m = 65.

I2. Hash Table Sizing: Write a function that, given N (desired table size), returns the smallest prime โ‰ฅ N. This is used in languages like C++ (unordered_map) and Java (HashMap) internally.

I3. Checksum Verification: Implement a prime-based rolling hash for a string. Use a prime modulus (10โน + 7) and prime base (31). Verify string integrity after transmission.

Interview Questions (3)

Q1. (Google-style): Given an array of N numbers (each โ‰ค 10โถ), count how many are prime. Optimize using sieve preprocessing.

Q2. (Amazon-style): Find the k-th prime number efficiently. Can you do better than checking each number?

Q3. (Microsoft-style): Given array A of N integers, count pairs (i, j) where i < j and A[i] + A[j] is prime. Optimize using Goldbach-related observations.

Section F

MCQ Assessment Bank โ€” 30 Questions (Bloom's Mapped)

Remember / Identify (Q1โ€“Q5)

Q1

Which of the following is a prime number?

  1. 51
  2. 67
  3. 91
  4. 87
Remember
โœ… Answer: (B) 67 โ€” 51 = 3ร—17, 91 = 7ร—13, 87 = 3ร—29. Only 67 has no factors other than 1 and itself.
Q2

What is the only even prime number?

  1. 1
  2. 2
  3. 4
  4. 0
Remember
โœ… Answer: (B) 2 โ€” It is the smallest and only even prime. All other even numbers are divisible by 2.
Q3

Fermat's Little Theorem states that if p is prime, then a^(p-1) mod p equals:

  1. 0
  2. 1
  3. p-1
  4. a
Remember
โœ… Answer: (B) 1 โ€” For any a not divisible by p, a^(p-1) โ‰ก 1 (mod p).
Q4

The time complexity of the Sieve of Eratosthenes is:

  1. O(nยฒ)
  2. O(n log n)
  3. O(n log log n)
  4. O(nโˆšn)
Remember
โœ… Answer: (C) O(n log log n) โ€” Due to the harmonic series of prime reciprocals (Mertens' theorem).
Q5

Which of these is a Carmichael number?

  1. 511
  2. 561
  3. 571
  4. 581
Remember
โœ… Answer: (B) 561 = 3 ร— 11 ร— 17 โ€” The smallest Carmichael number. It passes Fermat's test for all coprime bases despite being composite.

Understand / Explain (Q6โ€“Q10)

Q6

Why is checking divisors only up to โˆšn sufficient for primality testing?

  1. All prime factors are less than โˆšn
  2. If n has a factor greater than โˆšn, it must have a corresponding factor less than โˆšn
  3. โˆšn is always a prime number
  4. It reduces memory usage
Understand
โœ… Answer: (B) โ€” If n = a ร— b and both a, b > โˆšn, then a ร— b > n, which is a contradiction. So at least one factor must be โ‰ค โˆšn.
Q7

Why does the Sieve of Eratosthenes start marking from pยฒ instead of 2p?

  1. To save memory
  2. Because all smaller multiples of p have already been marked by smaller primes
  3. pยฒ is always composite
  4. It's an arbitrary optimization
Understand
โœ… Answer: (B) โ€” Multiples 2p, 3p, ..., (p-1)p were already marked when processing primes 2, 3, ..., p-1.
Q8

Why is the Fermat test called "probabilistic"?

  1. It uses random number generation internally
  2. It can give false positives (declare composite numbers as prime)
  3. It runs in random time
  4. It only works for random inputs
Understand
โœ… Answer: (B) โ€” Carmichael numbers pass the Fermat test but are composite, making it probabilistic. More iterations reduce (but don't eliminate) false positive probability.
Q9

What is the main advantage of a segmented sieve over a regular sieve?

  1. It is faster
  2. It uses significantly less memory
  3. It finds more primes
  4. It works with negative numbers
Understand
โœ… Answer: (B) โ€” Regular sieve needs O(n) memory. Segmented sieve needs only O(โˆšn), making it practical for n up to 10โน and beyond.
Q10

In the context of RSA encryption, why are large primes essential?

  1. Large primes make the key look impressive
  2. The security depends on the difficulty of factoring the product of two large primes
  3. Small primes cannot be multiplied
  4. Large primes are faster to compute with
Understand
โœ… Answer: (B) โ€” RSA security relies on the computational intractability of factoring n = p ร— q when p and q are very large primes (300+ digits each).

Apply (Q11โ€“Q15)

Q11

What is the output of the Sieve of Eratosthenes for n = 10?

  1. 2, 3, 5, 7, 9
  2. 2, 3, 5, 7
  3. 1, 2, 3, 5, 7
  4. 2, 4, 6, 8, 10
Apply
โœ… Answer: (B) 2, 3, 5, 7 โ€” These are the four primes โ‰ค 10. 9 = 3ร—3 is composite; 1 is not prime by definition.
Q12

The prime factorization of 360 is:

  1. 2ยณ ร— 3ยฒ ร— 5
  2. 2ยฒ ร— 3ยณ ร— 5
  3. 2ยณ ร— 3 ร— 5ยฒ
  4. 4 ร— 9 ร— 10
Apply
โœ… Answer: (A) 2ยณ ร— 3ยฒ ร— 5 โ€” 360 = 8 ร— 45 = 8 ร— 9 ร— 5 = 2ยณ ร— 3ยฒ ร— 5ยน.
Q13

How many prime numbers are between 1 and 30?

  1. 8
  2. 10
  3. 11
  4. 12
Apply
โœ… Answer: (B) 10 โ€” Primes: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29.
Q14

For Fermat test with n=7 and a=3, what is 3^6 mod 7?

  1. 0
  2. 1
  3. 3
  4. 6
Apply
โœ… Answer: (B) 1 โ€” 3โถ = 729. 729 รท 7 = 104 remainder 1. Since result is 1, the test says 7 is probably prime (and it is!).
Q15

What is the next prime palindrome after 10?

  1. 11
  2. 13
  3. 22
  4. 101
Apply
โœ… Answer: (A) 11 โ€” 11 is both prime (no factors other than 1 and 11) and a palindrome (reads same forwards and backwards).

Analyze (Q16โ€“Q20)

Q16

For checking if a single number n is prime, which method is most efficient?

  1. Sieve of Eratosthenes
  2. O(โˆšn) trial division
  3. Naive O(n) check
  4. Segmented sieve
Analyze
โœ… Answer: (B) โ€” For a single query, O(โˆšn) is optimal. Sieve is better only when you need to check multiple numbers up to n.
Q17

Why is 1729 special in number theory?

  1. It is the largest known prime
  2. It is both a Carmichael number and the Hardy-Ramanujan number
  3. It is the only number divisible by all single-digit primes
  4. It is the sum of all primes up to 100
Analyze
โœ… Answer: (B) โ€” 1729 = 7 ร— 13 ร— 19 (Carmichael number) and is also 1ยณ + 12ยณ = 9ยณ + 10ยณ (Hardy-Ramanujan: smallest number expressible as sum of two cubes in two ways).
Q18

What happens if we use the Sieve of Eratosthenes for n = 10โน?

  1. It works perfectly
  2. It runs out of memory (needs ~1 GB for boolean array)
  3. It produces wrong results
  4. It takes exactly 1 second
Analyze
โœ… Answer: (B) โ€” A boolean array of 10โน elements needs ~1 GB RAM, exceeding typical memory limits. Use segmented sieve instead.
Q19

Compare the number of operations for O(โˆšn) vs Sieve for finding all primes up to n = 10โถ:

  1. โˆšn is faster for this task
  2. Sieve is faster because it processes all numbers at once with O(n log log n)
  3. They take the same time
  4. Neither can handle 10โถ
Analyze
โœ… Answer: (B) โ€” Testing each number individually: 10โถ ร— โˆš10โถ = 10โน operations. Sieve: ~3 ร— 10โถ operations. Sieve is ~333ร— faster for this task.
Q20

Which data structure is used internally by the Sieve of Eratosthenes?

  1. Linked list
  2. Binary search tree
  3. Boolean array
  4. Hash map
Analyze
โœ… Answer: (C) โ€” A boolean array where index i represents whether i is prime. Simple, cache-friendly, and efficient.

Evaluate (Q21โ€“Q25)

Q21

For a competitive coding problem asking "Is N prime?" where N โ‰ค 10ยนโธ, which method is best?

  1. Sieve of Eratosthenes
  2. Naive O(n) check
  3. Miller-Rabin probabilistic test
  4. Segmented sieve
Evaluate
โœ… Answer: (C) โ€” For N up to 10ยนโธ, โˆšN โ‰ˆ 10โน which is too slow for trial division. Miller-Rabin runs in O(k logยฒ n) and is the standard choice for very large single-number primality tests.
Q22

When should you use Sieve of Atkins instead of Eratosthenes?

  1. Always โ€” it is strictly better
  2. Never โ€” Eratosthenes is always better
  3. Only for very large n (>10โธ) where the slight theoretical advantage matters
  4. Only for small n (<100)
Evaluate
โœ… Answer: (C) โ€” Atkins has a better asymptotic complexity O(n/log log n) vs O(n log log n), but larger constant factors. In practice, optimized Eratosthenes is often faster. Atkins is mainly of theoretical interest.
Q23

A student claims "If a number passes the Fermat test with 100 random bases, it is definitely prime." Is this correct?

  1. Yes, 100 bases is more than enough
  2. No, Carmichael numbers pass for all coprime bases, so even 100 tests cannot guarantee primality
  3. Yes, but only for odd numbers
  4. No, the Fermat test never works
Evaluate
โœ… Answer: (B) โ€” Carmichael numbers (like 561, 1105, 1729) pass the Fermat test for every coprime base. No number of Fermat tests can distinguish them from primes. Use Miller-Rabin instead.
Q24

For finding primes in range [10โน, 10โน+10โถ], the best approach is:

  1. Regular Sieve up to 10โน
  2. Check each number with O(โˆšn)
  3. Segmented Sieve
  4. Fermat test on each number
Evaluate
โœ… Answer: (C) โ€” Regular sieve can't handle 10โน (memory). Individual โˆšn tests: 10โถ ร— โˆš(10โน) โ‰ˆ 3ร—10ยนโฐ (too slow). Segmented sieve: ~10โถ operations with O(โˆš10โน) โ‰ˆ 31K memory. Perfect!
Q25

Which property makes prime numbers useful for hash table sizes?

  1. Prime numbers are always odd
  2. Using a prime modulus distributes hash values more uniformly, reducing collisions
  3. Prime numbers are faster to compute
  4. Prime numbers use less memory
Evaluate
โœ… Answer: (B) โ€” When the table size is prime, hash(key) % size distributes keys more uniformly because primes have no common factors with typical key patterns, reducing collision clustering.

Create / Design (Q26โ€“Q30)

Q26

To build a function that checks primality for multiple queries where each n โ‰ค 10โท, the best preprocessing is:

  1. No preprocessing; check each query with O(โˆšn)
  2. Precompute a sieve up to 10โท and answer each query in O(1)
  3. Store all primes in a hash set
  4. Use Fermat test for each query
Create
โœ… Answer: (B) โ€” Sieve preprocessing takes O(n log log n) once, then each query is O(1) lookup. Far better than O(โˆšn) per query when there are many queries.
Q27

To count divisors of N efficiently, the best approach combines:

  1. Checking all numbers from 1 to N
  2. Prime factorization + divisor count formula: product of (exponent+1)
  3. Using Sieve of Eratosthenes
  4. Binary search
Create
โœ… Answer: (B) โ€” Find prime factorization N = pโ‚^aโ‚ ร— pโ‚‚^aโ‚‚ ร— ... Then divisor count = (aโ‚+1)(aโ‚‚+1)... This runs in O(โˆšN).
Q28

To generate the Smallest Prime Factor (SPF) for all numbers up to N, you should modify the sieve to:

  1. Store the first prime that marks each composite number
  2. Count how many times each number is marked
  3. Use a linked list instead of an array
  4. Run the sieve backwards
Create
โœ… Answer: (A) โ€” Initialize SPF[i] = i. When marking composites of prime p, only update SPF[j] = p if SPF[j] == j (meaning j hasn't been marked by a smaller prime yet).
Q29

To design an efficient "next prime" function, the best strategy for large N (>10โถ) is:

  1. Increment N and test each with O(โˆšn) until a prime is found
  2. Use the Prime Number Theorem to jump approximately ln(N) ahead, then search
  3. Generate all primes up to 2N with a sieve
  4. Use Fermat test only
Create
โœ… Answer: (A) โ€” By the Prime Number Theorem, the gap between consecutive primes near N is approximately ln(N). For N = 10โถ, that's about 14. So O(โˆšn) testing of ~14 candidates is fast enough.
Q30

To implement a secure random prime generator for a simplified RSA system, you need:

  1. Any random odd number
  2. A random number generator + Miller-Rabin test with sufficient iterations
  3. The largest known Mersenne prime
  4. Sequential search starting from 2
Create
โœ… Answer: (B) โ€” Generate a random number of desired bit length, ensure it's odd, then run Miller-Rabin with ~40 iterations (probability of false positive < 2โปโธโฐ). This is how OpenSSL generates RSA primes.
Section G

Short Answer Questions (8)

Q1. Define primality testing and explain its importance in computer science.

Primality testing is the process of determining whether a given natural number is prime (divisible only by 1 and itself). It is fundamental to computer science for several reasons: (1) Cryptography โ€” RSA encryption, which secures all online transactions including UPI payments, relies on large primes. (2) Hash tables โ€” prime-sized tables reduce collisions. (3) Random number generation โ€” many PRNGs use prime moduli. (4) Competitive programming โ€” primality problems appear frequently on Codeforces, CodeChef, and LeetCode. (5) Error-correcting codes โ€” Reed-Solomon codes use prime field arithmetic. Understanding efficient primality testing is essential for any serious programmer or computer scientist.

Q2. Why is checking divisibility up to โˆšn sufficient? Prove it.

Proof: Suppose n is composite, meaning n = a ร— b where 1 < a, b < n. Assume for contradiction that both a > โˆšn and b > โˆšn. Then a ร— b > โˆšn ร— โˆšn = n, contradicting n = a ร— b. Therefore, at least one of a or b must be โ‰ค โˆšn. Since any composite number n has at least one factor โ‰ค โˆšn, we only need to check potential divisors from 2 to โˆšn. If none divides n, then n must be prime. Impact: For n = 10โน, this reduces checks from ~10โน to ~31,623 โ€” a speedup of over 31,000ร—.

Q3. Explain Fermat's Little Theorem with an example.

Fermat's Little Theorem: If p is a prime number and a is any integer with gcd(a, p) = 1, then a^(pโˆ’1) โ‰ก 1 (mod p). Example: Let p = 7 and a = 2. Compute 2^(7โˆ’1) = 2โถ = 64. Now 64 mod 7 = 64 โˆ’ 63 = 1. Since the result is 1, the theorem holds. โœ“ Another example: p = 11, a = 3. 3ยนโฐ = 59049. 59049 mod 11 = 59049 โˆ’ 5368ร—11 = 59049 โˆ’ 59048 = 1. โœ“ The contrapositive is used for testing: if a^(nโˆ’1) mod n โ‰  1, then n is definitely composite.

Q4. What are Carmichael numbers? Give 3 examples.

Carmichael numbers are composite numbers that satisfy Fermat's Little Theorem for ALL bases coprime to them. They are "Fermat liars" โ€” they fool the Fermat primality test into thinking they are prime. Examples: (1) 561 = 3 ร— 11 ร— 17 โ€” the smallest Carmichael number. (2) 1105 = 5 ร— 13 ร— 17. (3) 1729 = 7 ร— 13 ร— 19 โ€” also the famous Hardy-Ramanujan number. They are problematic because no matter how many random bases you test with Fermat's method, these numbers will always pass. To handle them, use the Miller-Rabin test, which can detect Carmichael numbers.

Q5. Describe the Sieve of Eratosthenes step-by-step for n = 30.

Step 1: Create boolean array [0..30], all set to true. Set arr[0] = arr[1] = false. Step 2 (p=2): Mark multiples 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30 as false. Step 3 (p=3): Mark 9, 15, 21, 27 as false (6, 12, 18, 24, 30 already marked). Step 4 (p=5): Mark 25 as false (other multiples already marked). Step 5: Since 6ยฒ = 36 > 30, we stop. Result: Numbers still marked true: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 โ€” these are all 10 primes โ‰ค 30.

Q6. Compare time complexity of naive primality test vs Sieve.

Naive test: O(n) per number or O(โˆšn) per number with optimization. To check ALL numbers up to N: N ร— O(โˆšN) = O(NโˆšN). Sieve of Eratosthenes: O(N log log N) for ALL numbers up to N simultaneously. Comparison: For N = 10โถ: Naive = 10โถ ร— 10ยณ = 10โน operations. Sieve = 10โถ ร— 3 โ‰ˆ 3ร—10โถ operations. The sieve is ~333ร— faster. When to use each: For a single query, โˆšn test is better. For multiple queries or generating all primes up to N, the sieve is vastly superior.

Q7. What is a segmented sieve and when to use it?

A segmented sieve divides the range [L, R] into smaller segments of size ~โˆšR and sieves each segment independently using pre-computed small primes (up to โˆšR). Memory: O(โˆšR) instead of O(R). When to use: When R > 10โท (regular sieve exceeds memory limits). For R = 10โน, regular sieve needs ~1 GB; segmented sieve needs only ~31 KB for small primes plus segment buffer. Use cases: Finding primes in a range [L, R], prime counting in large ranges, problems on SPOJ like PRIME1. Time complexity remains O((Rโˆ’L+1) log log R + โˆšR).

Q8. Difference between deterministic and probabilistic primality tests.

Deterministic tests (trial division, AKS) give a definitive yes/no answer. Trial division is O(โˆšn) and always correct. AKS runs in polynomial time and is always correct but has large constants. Probabilistic tests (Fermat, Miller-Rabin) are faster but can produce false positives. Fermat can be fooled by Carmichael numbers. Miller-Rabin with k iterations has error probability < 4^(โˆ’k) โ€” with k=40, the probability of error is less than 2^(โˆ’80), which is negligible. For competitive coding: Deterministic O(โˆšn) for n โ‰ค 10ยนยฒ, Miller-Rabin for n > 10ยนยฒ.

Section H

Long Answer Questions (3)

Q1. Compare all primality testing methods covered in this unit.

MethodTimeSpaceTypeBest Use
Naive O(n)O(n)O(1)DeterministicEducational only
O(โˆšn)O(โˆšn)O(1)DeterministicSingle query, n โ‰ค 10ยนยฒ
FermatO(k log n)O(1)ProbabilisticQuick check (beware Carmichael)
Miller-RabinO(k logยฒ n)O(1)ProbabilisticSingle query, n โ‰ค 10ยนโธ
SieveO(n log log n)O(n)DeterministicAll primes up to n โ‰ค 10โท
Segmented SieveO((R-L)ยทlog log R)O(โˆšR)DeterministicRange queries, R up to 10โน
Sieve of AtkinsO(n/log log n)O(n)DeterministicTheoretical; very large n

The choice depends on the problem: single query vs multiple queries, range of n, memory constraints, and whether deterministic answers are required. For most competitive programming, O(โˆšn) for single queries and Sieve of Eratosthenes for bulk generation cover 95% of problems.

Q2. Explain the Sieve of Eratosthenes in complete detail.

The Sieve of Eratosthenes, invented by the Greek mathematician Eratosthenes around 240 BC, is an algorithm to find all prime numbers up to a given limit n. It works by iteratively marking the multiples of each prime starting from 2.

Mathematical Basis: The Fundamental Theorem of Arithmetic states every integer > 1 has a unique prime factorization. The sieve exploits the fact that any composite number must have a prime factor โ‰ค โˆšn.

Optimization โ€” start from pยฒ: When processing prime p, we start marking from pยฒ (not 2p) because all smaller multiples kp where k < p have already been marked by the prime factor k. This reduces the total work significantly.

Time Complexity Analysis: The inner loop for prime p does n/p operations. Total work = ฮฃ(n/p) for all primes p โ‰ค โˆšn = n ร— ฮฃ(1/p). By Mertens' theorem, ฮฃ(1/p) for primes p โ‰ค n โ‰ˆ log log n. Therefore, total time = O(n log log n). Since log log n grows extremely slowly (log log 10โน โ‰ˆ 3), this is practically linear.

Optimizations: (1) Bitwise sieve: use bits instead of bytes, reducing memory by 8ร—. (2) Wheel factorization: skip multiples of 2, 3, 5 automatically. (3) Segment the sieve for cache efficiency.

Q3. How are prime numbers used in RSA encryption?

RSA Key Generation Process:

1. Choose two large primes p and q (each 300+ digits in practice).

2. Compute n = p ร— q. This is the modulus. n is made public; p and q are kept secret.

3. Compute Euler's totient: ฯ†(n) = (pโˆ’1)(qโˆ’1). This is kept secret.

4. Choose public exponent e such that 1 < e < ฯ†(n) and gcd(e, ฯ†(n)) = 1. Commonly e = 65537.

5. Compute private exponent d = eโปยน mod ฯ†(n) using the Extended Euclidean Algorithm.

6. Public key: (n, e). Private key: (n, d).

Encryption: c = m^e mod n. Decryption: m = c^d mod n.

Why large primes are essential: The security relies on the computational difficulty of factoring n back into p and q. For RSA-2048, n has 617 digits. The best known factoring algorithms (General Number Field Sieve) would take billions of years with current computing power.

Indian Context: India's UPI (Unified Payments Interface), managed by NPCI, processes 10+ billion transactions monthly. Every transaction uses TLS (Transport Layer Security) which relies on RSA or ECDSA for key exchange. Aadhaar authentication also uses RSA-2048 for securing biometric data transmission. The security of โ‚น20+ lakh crore in monthly digital payments rests on the difficulty of factoring large primes.

Section I

Lab Programs from Syllabus (5)

Lab 1: Finding Prime Factors by Square Root Method

โฑ๏ธ 30 minBeginner

Objective:

Find all prime factors of a number using trial division up to โˆšn.

Algorithm:

  1. While n is divisible by 2, print 2 and divide n by 2.
  2. For odd i from 3 to โˆšn: while n is divisible by i, print i and divide.
  3. If n > 1, print n (it's a remaining prime factor).
C++
#include <iostream>
#include <cmath>
using namespace std;
void primeFactors(int n) {
    while (n % 2 == 0) { cout << 2 << " "; n /= 2; }
    for (int i=3; i*i<=n; i+=2) {
        while (n%i==0) { cout<<i<<" "; n/=i; }
    }
    if (n>1) cout<<n;
    cout<<endl;
}
int main() { primeFactors(84); return 0; }
2 2 3 7

Viva Voce:

V1: What is prime factorization? โ€” Expressing a number as a product of prime powers.

V2: Why check up to โˆšn? โ€” If n has a factor > โˆšn, it must have a corresponding factor < โˆšn.

V3: Time complexity? โ€” O(โˆšn).

V4: Can this handle very large numbers? โ€” Up to ~10โน efficiently; beyond that, use Pollard's rho.

V5: State the Fundamental Theorem of Arithmetic. โ€” Every integer > 1 has a unique prime factorization.

Lab 2: Fermat Primality Test

โฑ๏ธ 30 minIntermediate

Objective:

Implement probabilistic primality test using Fermat's Little Theorem.

Python
import random
def power_mod(base, exp, mod):
    result = 1
    base %= mod
    while exp > 0:
        if exp % 2 == 1: result = (result * base) % mod
        exp //= 2
        base = (base * base) % mod
    return result

def fermat_test(n, k=10):
    if n < 2: return False
    if n < 4: return True
    for _ in range(k):
        a = random.randint(2, n-2)
        if power_mod(a, n-1, n) != 1: return False
    return True

for n in [7, 15, 561, 997]:
    print(f"{n}: {'Prime' if fermat_test(n) else 'Composite'}")
7: Prime 15: Composite 561: Prime โ† FALSE POSITIVE! (Carmichael number) 997: Prime

Viva Voce:

V1: State Fermat's Little Theorem. โ€” If p is prime and gcd(a,p)=1, then a^(p-1) โ‰ก 1 (mod p).

V2: What are Carmichael numbers? โ€” Composites that pass Fermat test for all coprime bases (e.g., 561).

V3: Why multiple iterations? โ€” Each iteration with a random base reduces false positive probability.

V4: What is modular exponentiation? โ€” Computing a^b mod m in O(log b) using repeated squaring.

V5: How does Miller-Rabin improve on Fermat? โ€” It detects Carmichael numbers using strong pseudoprime tests.

Lab 3: Sieve of Eratosthenes

โฑ๏ธ 30 minBeginner

Objective:

Generate all primes up to N using the Sieve of Eratosthenes.

C++
#include <iostream>
#include <vector>
using namespace std;
int main() {
    int n = 50;
    vector<bool> sieve(n+1, true);
    sieve[0] = sieve[1] = false;
    for (int p=2; p*p<=n; p++)
        if (sieve[p])
            for (int j=p*p; j<=n; j+=p)
                sieve[j] = false;
    cout << "Primes up to " << n << ": ";
    for (int i=2; i<=n; i++)
        if (sieve[i]) cout << i << " ";
    return 0;
}
Primes up to 50: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47

Viva Voce:

V1: Time complexity? โ€” O(n log log n).

V2: Space complexity? โ€” O(n) for the boolean array.

V3: Why start marking from pยฒ? โ€” Smaller multiples of p were already marked by smaller primes.

V4: Can we optimize memory? โ€” Yes, bitwise sieve uses bits instead of bytes (8ร— savings).

V5: What is the prime counting function ฯ€(n)? โ€” Number of primes โ‰ค n. ฯ€(10โถ) = 78498.

Lab 4: Segmented Sieve

โฑ๏ธ 45 minAdvanced

Objective:

Find all primes in a given range [L, R] using the segmented sieve approach.

Python
import math
def segmented_sieve(L, R):
    limit = int(math.sqrt(R)) + 1
    mark = [True] * (limit + 1)
    primes = []
    for p in range(2, limit + 1):
        if mark[p]:
            primes.append(p)
            for j in range(p*p, limit+1, p): mark[j] = False
    is_prime = [True] * (R - L + 1)
    for p in primes:
        start = max(p*p, ((L+p-1)//p)*p)
        for j in range(start, R+1, p): is_prime[j-L] = False
    if L <= 1: is_prime[1-L] = False
    return [L+i for i in range(R-L+1) if is_prime[i]]
print(segmented_sieve(100, 150))
[101, 103, 107, 109, 113, 127, 131, 137, 139, 149]

Viva Voce:

V1: Why not use a regular sieve for large ranges? โ€” Memory constraint: sieve of 10โน needs ~1 GB.

V2: Memory advantage? โ€” O(โˆšR) vs O(R).

V3: How to choose segment size? โ€” Typically โˆšR or cache size for optimal performance.

V4: Time complexity? โ€” O((Rโˆ’L+1) log log R + โˆšR).

V5: Applications? โ€” SPOJ PRIME1, Project Euler problems, counting primes in ranges.

Lab 5: Sieve of Atkins

โฑ๏ธ 45 minAdvanced

Objective:

Implement the Sieve of Atkins using quadratic forms.

Python
import math
def sieve_of_atkins(limit):
    sieve = [False] * (limit + 1)
    for x in range(1, int(math.sqrt(limit)) + 1):
        for y in range(1, int(math.sqrt(limit)) + 1):
            n = 4*x*x + y*y
            if n <= limit and (n%12 == 1 or n%12 == 5):
                sieve[n] = not sieve[n]
            n = 3*x*x + y*y
            if n <= limit and n%12 == 7:
                sieve[n] = not sieve[n]
            n = 3*x*x - y*y
            if x > y and n <= limit and n%12 == 11:
                sieve[n] = not sieve[n]
    for r in range(5, int(math.sqrt(limit)) + 1):
        if sieve[r]:
            for i in range(r*r, limit+1, r*r):
                sieve[i] = False
    return [2,3] + [i for i in range(5, limit+1) if sieve[i]]

print(sieve_of_atkins(100))
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

Viva Voce:

V1: How does Atkins differ from Eratosthenes? โ€” Uses quadratic forms instead of marking multiples.

V2: What are the three quadratic forms? โ€” 4xยฒ+yยฒ, 3xยฒ+yยฒ, 3xยฒ-yยฒ with specific modular conditions.

V3: Time complexity? โ€” O(n / log log n), slightly better than Eratosthenes asymptotically.

V4: When is Atkins faster? โ€” Theoretically for very large n, but optimized Eratosthenes often wins in practice.

V5: Who invented it? โ€” A.O.L. Atkin and Daniel J. Bernstein, published in 2004.

Section J

Industry Spotlight โ€” A Day in the Life

๐Ÿ‘ฉโ€๐Ÿ’ป Priya Nair, 26 โ€” Cryptography Engineer at Razorpay, Bangalore

Background: B.Tech in Computer Science from NIT Calicut. Competitive programmer โ€” Codeforces rating 1800+ (Expert), CodeChef 5-star. Interned at Razorpay in 3rd year working on payment gateway security. Converted to full-time offer. Now works on cryptographic modules for payment processing.

A Typical Day:

9:00 AM โ€” Morning standup with the security engineering team. Review overnight security alerts and vulnerability reports.

10:00 AM โ€” Code review of TLS implementation updates. Check certificate validation logic and cipher suite configurations.

11:30 AM โ€” Implement and test prime generation module for the internal key management system. Benchmark with various key sizes (1024, 2048, 4096 bits).

1:00 PM โ€” Lunch at Razorpay's Bangalore office. Participate in a Codeforces virtual contest during break.

2:00 PM โ€” Research post-quantum cryptography algorithms. Write internal documentation on lattice-based alternatives to RSA.

4:00 PM โ€” Pair programming with a junior developer on implementing RSA-OAEP padding scheme. Review their understanding of prime generation.

5:30 PM โ€” Security audit of a new payment API endpoint. Run automated vulnerability scans using OpenSSL toolkit.

DetailInfo
Tools Used DailyOpenSSL, C++, Python, Go, HSMs (Hardware Security Modules), Wireshark
Entry Salary (2024)โ‚น8โ€“12 LPA + ESOPs
Mid-Level (3โ€“5 yrs)โ‚น15โ€“25 LPA
Senior (7+ yrs)โ‚น30โ€“50 LPA
Companies HiringRazorpay, PhonePe, Visa, Mastercard, NPCI, Juspay, Pine Labs, BharatPe, PayU, Cashfree
Section K

Earn With It โ€” Freelance & Income Roadmap

๐Ÿ’ฐ Your Earning Path After This Chapter

Portfolio Pieces: Implement and showcase primality testing library on GitHub. Solve 50+ competitive programming problems involving primes.

Earning Avenues:

โ€ข Competitive programming prizes (Codeforces, CodeChef, Google Code Jam) โ€” โ‚น5,000โ€“โ‚น50,000 per contest

โ€ข Bug bounty programs (HackerOne India: Razorpay, Paytm, CRED) โ€” โ‚น5,000โ€“โ‚น5,00,000 per bug

โ€ข Freelance security auditing and crypto implementation โ€” โ‚น10,000โ€“โ‚น50,000/project

โ€ข Technical writing about algorithms and cryptography โ€” โ‚น2,000โ€“โ‚น8,000/article

โ€ข Open-source contributions to crypto libraries โ€” builds reputation for high-paying jobs

PlatformBest ForTypical Rate
Codeforces/CodeChefContest prizes, building competitive programming profileโ‚น5,000โ€“โ‚น1,00,000/contest
HackerOne IndiaBug bounty programs (Razorpay, Paytm, etc.)โ‚น5,000โ€“โ‚น5,00,000/vulnerability
Toptal/UpworkFreelance security consulting, crypto implementations$30โ€“$100/hour
GitHub SponsorsOpen-source crypto library contributions$50โ€“$500/month (sponsorship)
Medium/Dev.toTechnical articles on algorithms and cryptographyโ‚น2,000โ€“โ‚น8,000/article
Fastest path to earning: Solve 100 competitive programming problems on Codeforces (focus on number theory tag). Reach 1400+ rating. Then participate in rated contests for prize money and build a profile that attracts job offers from top companies.
Section L

Chapter Summary

๐Ÿ”‘ Key Takeaways โ€” Primality Testing

  • A prime number has exactly two distinct factors: 1 and itself. 2 is the only even prime.
  • Naive O(n) test: check all divisors from 2 to nโˆ’1. Too slow for n > 10โถ.
  • O(โˆšn) optimization: if n is composite, it has a factor โ‰ค โˆšn. Check only up to โˆšn.
  • 6kยฑ1 trick: all primes > 3 are of the form 6kยฑ1, letting us skip 2/3 of candidates.
  • Trial division factorization finds all prime factors in O(โˆšn) by dividing by smallest factors repeatedly.
  • Fermat's Little Theorem: a^(pโˆ’1) โ‰ก 1 (mod p) for prime p. Basis for probabilistic testing.
  • Carmichael numbers (561, 1105, 1729) fool the Fermat test โ€” they're composite but pass all coprime bases.
  • Sieve of Eratosthenes โญ: generates ALL primes up to n in O(n log log n). The most important algorithm in this unit.
  • Sieve optimization: start marking from pยฒ, not 2p, since smaller multiples were already marked.
  • Segmented Sieve: handles ranges where regular sieve exceeds memory. Uses O(โˆšR) memory.
  • Sieve of Atkins: uses quadratic forms. O(n/log log n) time. Mainly theoretical interest.
  • Prime factorization enables counting divisors: if N = pโ‚^aโ‚ ร— pโ‚‚^aโ‚‚ ร— ..., divisors = ฮ (aแตข+1).
  • RSA encryption relies on the difficulty of factoring the product of two large primes.
  • India's UPI/NPCI system uses RSA-2048 to secure 10+ billion monthly transactions.
  • For single queries: use O(โˆšn). For bulk generation: use Sieve. For very large n: use Miller-Rabin.
  • Every competitive programmer must know Sieve of Eratosthenes โ€” it appears in 20%+ of number theory problems.
  • Next prime palindrome: combine palindrome check with primality test. Prime gaps near n โ‰ˆ ln(n).
  • Primes are infinite (Euclid's proof, ~300 BC) and their distribution follows the Prime Number Theorem: ฯ€(n) โ‰ˆ n/ln(n).
Section M

Earning Checkpoint

SkillTool / MethodPortfolio DeliverableReady to Earn?
O(โˆšn) Primality TestC++ / PythonCompetitive programming solutions on Codeforcesโœ… Yes โ€” foundation for contest problems
Prime FactorizationTrial DivisionNumber theory problem solutionsโœ… Yes โ€” common in interviews
Fermat Primality TestModular ExponentiationCrypto-related implementationsโœ… Yes โ€” useful in security projects
Sieve of EratosthenesBoolean Array + IterationEfficient prime generator libraryโœ… Yes โ€” essential for competitive coding
Segmented SieveRange-based SievingAdvanced contest solutions (SPOJ PRIME1)โœ… Yes โ€” demonstrates advanced skills
Cryptography ConceptsRSA, Modular ArithmeticSecurity audit reports, crypto implementationsโฌœ Partially โ€” need more depth for professional work
Minimum Viable Earning Setup after this chapter: A Codeforces profile with 50+ solved number theory problems + a GitHub repository showcasing your primality testing library + an active competitive programming practice routine = you can earn โ‚น5,000โ€“โ‚น25,000/month from contest prizes, bug bounties, and freelance algorithm work.

โœ… Unit 2 complete. Ready for Unit 3!

[QR: Link to EduArtha video tutorial โ€” Primality Testing Deep Dive]