ExamplesBy LevelBy TopicLearning Paths
833 Fundamental

Discrete Logarithm — Baby-Step Giant-Step

Functional Programming

Tutorial Video

Text description (accessibility)

This video demonstrates the "Discrete Logarithm — Baby-Step Giant-Step" functional Rust example. Difficulty level: Fundamental. Key concepts covered: Functional Programming. Given g, h, and prime p, the discrete logarithm problem asks: find x such that `g^x ≡ h (mod p)`. Key difference from OCaml: | Aspect | Rust | OCaml |

Tutorial

The Problem

Given g, h, and prime p, the discrete logarithm problem asks: find x such that g^x ≡ h (mod p). This is computationally hard for large p (the Discrete Log Problem, DLP), which is the security foundation of Diffie-Hellman key exchange, ElGamal encryption, DSA signatures, and elliptic curve cryptography. Baby-step Giant-step (BSGS) solves the DLP in O(sqrt(p)) time and O(sqrt(p)) space — much faster than brute force O(p) but still infeasible for cryptographic p (256+ bit). Understanding BSGS is essential for cryptanalysis, CTF competitions, and understanding why large primes are necessary.

🎯 Learning Outcomes

  • • Understand the meet-in-the-middle decomposition: write x = i*m - j where m = ceil(sqrt(p))
  • • Baby steps: precompute h * g^j mod p for j = 0..m into a hash map
  • • Giant steps: for i = 1..m, compute g^(i*m) mod p and look up in the baby-step table
  • • Recognize the time-space tradeoff: O(sqrt(p)) in both time and memory
  • • Understand why BSGS only works for small p and why index calculus is needed for large p
  • Code Example

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

    Key Differences

    AspectRustOCaml
    Baby step tableHashMap<u64, u64>Hashtbl (int, int)
    m computation(p as f64).sqrt().ceil()float_of_int |> sqrt |> ceil
    Giant step iterationMultiply by precomputed gmSame approach
    No solutionReturns NoneReturns None
    Large p supportLimited to u64Zarith for large p
    ComplexityO(sqrt(p)) time+spaceSame

    OCaml Approach

    OCaml implements BSGS with Hashtbl.t for baby steps: Hashtbl.add table val j. The giant step loop uses for i = 1 to m do ... done. OCaml's float_of_int |> sqrt |> ceil |> int_of_float computes m. The Hashtbl.find_opt table giant returns int option. OCaml's Zarith handles large moduli beyond 63-bit integers. The baby-step table uses Hashtbl.replace to handle collisions where multiple j values give the same baby step (take the smallest j).

    Full Source

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

    Deep Comparison

    OCaml vs Rust: Discrete Log Bsgs

    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 BSGS for a general group order n (not just prime p) using n instead of p-1 in the result.
  • Optimize memory by using a sorted array + binary search instead of a HashMap for baby steps.
  • Implement Pohlig-Hellman which reduces DLP over Z/pZ to smaller DLPs over prime-order subgroups.
  • Test BSGS on small primes p < 10^6 and verify by computing g^result mod p == h.
  • Measure the practical limit: what is the largest p for which BSGS completes in under 1 second on your machine?
  • Open Source Repos