ExamplesBy LevelBy TopicLearning Paths
831 Fundamental

Miller-Rabin Primality Test

Functional Programming

Tutorial Video

Text description (accessibility)

This video demonstrates the "Miller-Rabin Primality Test" functional Rust example. Difficulty level: Fundamental. Key concepts covered: Functional Programming. Deterministic primality testing via trial division is O(sqrt(n)), impractical for 64-bit numbers (up to 4 billion operations). Key difference from OCaml: | Aspect | Rust | OCaml |

Tutorial

The Problem

Deterministic primality testing via trial division is O(sqrt(n)), impractical for 64-bit numbers (up to 4 billion operations). Cryptographic applications need to test numbers with hundreds of digits for primality during key generation. Miller-Rabin is a probabilistic primality test that runs in O(k log^2 n) where k is the number of witness rounds — each round reduces error probability to 1/4. With k=25 rounds, the probability of a false positive is negligible. For 64-bit integers, a specific set of deterministic witnesses {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37} makes Miller-Rabin deterministic — no false positives for any n < 3.3 * 10^24.

🎯 Learning Outcomes

  • • Decompose n-1 as 2^r * d where d is odd, used in the Miller-Rabin witness test
  • • Implement the witness test: a^d ≠ 1 (mod n) AND a^(2^j * d) ≠ -1 (mod n) for all j means composite
  • • Understand strong pseudoprimes and why multiple witnesses reduce false positive rate
  • • Use the deterministic witness set for 64-bit integers to get an exact answer
  • • Compare with Fermat test: Miller-Rabin has no Carmichael number problem
  • Code Example

    #![allow(clippy::all)]
    //! Placeholder

    Key Differences

    AspectRustOCaml
    64-bit modular mulas u128 intermediateInt64 or Zarith
    Witness iterationfor &a in &[...]List.for_all
    Overflow safetyu128 prevents overflowZarith arbitrary precision
    Deterministic rangen < 3.3 * 10^24Same witnesses, same range
    False positivesNone with chosen witnessesNone
    Probabilistic modeAdd random witnessesRandom.int64 witnesses

    OCaml Approach

    OCaml's Miller-Rabin decomposes n-1 using a recursive/iterative bit-strip. The witness list is a let witnesses = [2; 3; 5; 7; 11; 13; 17; 19; 23; 29; 31; 37]. The test uses List.for_all (fun a -> not (is_composite n a d r)) witnesses. OCaml's Int64 or Zarith handles modular multiplication for large n. The 63-bit native int suffices for n < 2^62; for full 64-bit range, Int64 or Zarith.mpz is needed.

    Full Source

    #![allow(clippy::all)]
    //! Placeholder

    Deep Comparison

    OCaml vs Rust: Miller Rabin Primality

    Overview

    See the example.rs and example.ml files for detailed implementations.

    Key Differences

    AspectOCamlRust
    Type systemHindley-MilnerOwnership + traits
    MemoryGCZero-cost abstractions
    MutabilityExplicit refmut keyword
    Error handlingOption/ResultResult<T, E>

    See README.md for detailed comparison.

    Exercises

  • Implement the probabilistic version with k random witnesses and estimate false positive rate empirically.
  • Use Miller-Rabin to generate large primes: generate random odd n until Miller-Rabin returns true.
  • Compare Miller-Rabin with the Fermat primality test on Carmichael numbers (which fool Fermat but not Miller-Rabin).
  • Implement Baillie-PSW primality test (Miller-Rabin base 2 + strong Lucas) which has no known pseudoprimes.
  • Benchmark Miller-Rabin vs. trial division for n up to 10^12 and measure crossover point.
  • Open Source Repos