prime numbers
algorithms
number theory
computational mathematics
cryptography

Generate large prime number with specified last digits

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Generating a large prime with specified last digits is a constrained prime-search problem. The key observation is that if you fix the final decimal suffix, you are no longer searching all large integers. You are searching numbers of the form k * 10^m + suffix, where m is the number of forced trailing digits. Once you express the problem that way, the rest is primality testing and basic modular filtering.

First Check Whether the Suffix Even Allows Primes

Not every suffix can end a prime greater than 5.

If the suffix makes every candidate divisible by 2 or 5, then no large prime exists with that suffix.

Examples of impossible endings for primes greater than 5:

  • anything ending in 0
  • anything ending in 2
  • anything ending in 4
  • anything ending in 5
  • anything ending in 6
  • anything ending in 8

So before writing a search loop, reject impossible suffixes quickly.

You can also filter by divisibility rules for 3, 9, or other small primes when appropriate.

Build Candidates in the Right Shape

If the desired suffix is 37, then every candidate prime must look like:

text
candidate = prefix * 100 + 37

If the suffix has m digits, the multiplier is 10^m.

In Python:

python
def make_candidate(prefix: int, suffix: int, digits_in_suffix: int) -> int:
    return prefix * (10 ** digits_in_suffix) + suffix

Now the job becomes: choose prefixes, build candidates, and test primality.

Use Probabilistic Primality Testing

For large integers, you do not want trial division. A probabilistic test such as Miller–Rabin is the usual practical choice.

Here is a simple implementation:

python
1import random
2
3
4def is_probable_prime(n: int, rounds: int = 10) -> bool:
5    if n < 2:
6        return False
7    for p in (2, 3, 5, 7, 11, 13, 17, 19, 23, 29):
8        if n == p:
9            return True
10        if n % p == 0:
11            return False
12
13    d = n - 1
14    s = 0
15    while d % 2 == 0:
16        d //= 2
17        s += 1
18
19    for _ in range(rounds):
20        a = random.randrange(2, n - 1)
21        x = pow(a, d, n)
22        if x == 1 or x == n - 1:
23            continue
24        for _ in range(s - 1):
25            x = pow(x, 2, n)
26            if x == n - 1:
27                break
28        else:
29            return False
30    return True

For many engineering tasks, this is a practical answer. For cryptographic production use, you would typically rely on a vetted library rather than handwritten primality code.

Search Strategy

A simple search loop is:

python
1import secrets
2
3
4def generate_prime_with_suffix(total_digits: int, suffix: int) -> int:
5    suffix_str = str(suffix)
6    m = len(suffix_str)
7
8    if total_digits <= m:
9        raise ValueError("total_digits must exceed suffix length")
10    if suffix % 2 == 0 or suffix % 5 == 0:
11        raise ValueError("suffix cannot end an odd prime greater than 5")
12
13    prefix_digits = total_digits - m
14    lower = 10 ** (prefix_digits - 1)
15    upper = 10 ** prefix_digits - 1
16
17    while True:
18        prefix = secrets.randbelow(upper - lower + 1) + lower
19        candidate = prefix * (10 ** m) + suffix
20        if is_probable_prime(candidate):
21            return candidate
22
23
24prime = generate_prime_with_suffix(20, 37)
25print(prime)
26print(str(prime).endswith("37"))

This works because the suffix is fixed and the prefix is random.

Add Small-Prime Filtering for Speed

Before Miller–Rabin, you can quickly reject many candidates using small-prime modular tests.

For example, if a candidate is divisible by 3, 7, 11, or 13, there is no point running the heavier test.

That can speed up the search noticeably, especially when generating many primes.

The pattern is:

  • construct candidate
  • test divisibility by a small prime list
  • only then run Miller–Rabin

Cryptographic Caution

If the prime is for cryptographic use, fixing the last digits reduces randomness. That may or may not be acceptable depending on the protocol and the reason for the suffix requirement.

So ask why the suffix constraint exists.

  • if it is for a puzzle or math exercise, fine
  • if it is for cryptographic key generation, be very careful

Security-sensitive prime generation should usually use well-reviewed libraries and protocol-specific requirements.

Common Pitfalls

The biggest pitfall is asking for a suffix that makes primality impossible, such as one ending in an even digit or 5.

Another issue is using slow deterministic trial division on very large candidates.

Developers also sometimes forget that fixing a suffix means candidates must be generated as prefix * 10^m + suffix, not by random search with later string filtering.

Finally, for cryptographic primes, handwritten primality code is usually the wrong production choice.

Summary

  • Generate candidates as prefix * 10^m + suffix.
  • Reject impossible suffixes before searching.
  • Use small-prime filtering and then a fast primality test such as Miller–Rabin.
  • For large numbers, probabilistic testing is the practical approach.
  • If the prime is security-sensitive, use vetted libraries and reconsider whether the suffix constraint is acceptable.

Course illustration
Course illustration

All Rights Reserved.