skip to content

How does BigInteger.isProbablePrime(certainty) work, and what does the certainty parameter actually guarantee?

level: seniorimportance: should knowfreq 35%

answer

  1. true = probably prime, false = definitely composite
  2. Error is one-sided: only 'true' can be (tinily) wrong
  3. False-prime probability ≤ 1/2^certainty
  4. Miller-Rabin + Lucas; certainty=100 is the standard
  5. probablePrime(bits, SecureRandom) factory for key gen

basics

~10 s

isProbablePrime(certainty) is a fast test that says a number is probably prime or definitely not prime. Higher certainty lowers the chance of a wrong 'prime' answer; it never wrongly says a prime is composite.

solid answer

~50 s

isProbablePrime(int certainty) returns true if the number is probably prime and false if it is definitely composite. It uses probabilistic tests (Miller-Rabin, plus a Lucas-Lehmer step for larger inputs) rather than full factoring, because deterministic primality testing of huge numbers is too slow. The certainty parameter bounds the error: the probability that it returns true for a composite number is at most 1/2^certainty. So certainty=100 means a false-prime chance below 1 in 2^100 — astronomically small, the practical standard. Crucially the error is one-sided: a 'false' result is always correct (it really is composite), only 'true' carries the tiny risk. It is the workhorse for generating large primes — e.g. RSA key generation loops picking random odd candidates until isProbablePrime passes. There is also a public probablePrime(bitLength, random) factory that returns a prime of a given size. Higher certainty costs more rounds, hence more time.

go deeper

for a junior

Knows it tests whether a big number is prime and that bigger certainty means more confidence.

for a middle

Explains it's probabilistic, that false means definitely composite, and that it's used to generate primes.

for a senior

States the one-sided ≤1/2^certainty error bound, names Miller-Rabin, and uses probablePrime with SecureRandom for keys.

for a principal

Discusses the speed/confidence trade-off, why probabilistic testing is required (factoring infeasibility), Baillie-PSW strengthening, and RNG quality as a security boundary distinct from the test.

## The problem: is this huge number prime? A **prime** number is divisible only by 1 and itself. Checking primality of small numbers is easy (trial division), but the numbers used in cryptography are hundreds of digits long. **Trial division** or full **factoring** of such numbers is computationally infeasible — that infeasibility is literally what RSA's security rests on. So we need a test that decides primality *without* factoring. ## Probabilistic primality testing `BigInteger.isProbablePrime(int certainty)` returns: - `true` — the number is **probably prime**, with a controllable, tiny error probability. - `false` — the number is **definitely composite** (not prime), with no error. The asymmetry is the key insight: the test can be *wrong only in one direction*. It will never call a real prime "composite." It might, with vanishingly small probability, call a composite "prime." Under the hood the JDK runs the **Miller-Rabin** test: it picks random "witness" bases and checks an algebraic identity that all primes satisfy. A single composite number fails this identity for at least 3/4 of possible witnesses, so each random witness that *passes* makes it 4x less likely the number is secretly composite. For larger inputs the JDK also adds a **Baillie-PSW / Lucas-Lehmer** style check, which strengthens confidence further. ## What `certainty` guarantees The contract: if `isProbablePrime(certainty)` returns `true`, the probability the number is actually composite is **at most `1 / 2^certainty`**. The implementation translates `certainty` into a number of Miller-Rabin rounds sufficient to meet that bound (each round roughly doubles confidence). - `certainty = 10` → false-prime chance ≤ 1/1024 (too weak for crypto). - `certainty = 100` → ≤ 1/2^100, about 1 in 10^30 — the de facto standard for serious use; far less likely than a hardware cosmic-ray bit flip. - `certainty <= 0` → the method returns `true` unconditionally (it does no work). Never pass 0. Higher certainty means more rounds, so more CPU time — a direct speed/confidence trade-off. ## How it's used in practice **Generating a large prime** (e.g. for an RSA key) is a loop: ```java BigInteger p; do { p = new BigInteger(1024, random); // random 1024-bit candidate } while (!p.isProbablePrime(100)); ``` Primes are dense enough (≈ 1 in ln(N) numbers near N) that this terminates quickly. The JDK packages this as the factory `BigInteger.probablePrime(int bitLength, Random rnd)`, which returns a probable prime of the requested size. For cryptographic key generation, pass a `SecureRandom`, not a plain `Random`. ## Edge cases and pitfalls - A `false` answer is **certain** — useful for cheaply ruling out composites. - Don't confuse `isProbablePrime` with proof: it's a probabilistic guarantee, not a deterministic certificate (though at certainty 100 the practical difference is nil). - The error bound is one-sided; people sometimes wrongly fear false-negative ("it called my prime composite") — that cannot happen. - Using a non-cryptographic `Random` for key material is a security bug even if the primality test is solid.

  • Can isProbablePrime ever return false for a number that is actually prime?
    No. The error is one-sided: 'false' always means truly composite. Only a 'true' result carries the bounded (≤ 1/2^certainty) chance of being wrong.
  • What does passing certainty <= 0 do?
    It returns true unconditionally without running any test, so it is never safe to use 0 — pass something like 100 for real use.

saying these in an interview costs you the question

  • Thinking it can wrongly call a prime composite (false negatives)
  • Using low certainty (or 0, which returns true with no test) for crypto
  • Believing it factors or fully proves primality
  • Generating crypto primes with java.util.Random instead of SecureRandom

context