Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
duyuefeng0708
GitHub Repository: duyuefeng0708/Cryptography-From-First-Principle
Path: blob/main/foundations/01-modular-arithmetic-groups/python/connect-dh-parameter-selection.ipynb
483 views
unlisted
Kernel: Python 3
# This notebook has two versions: # Python (this file) -- runs in browser via JupyterLite, no install needed # SageMath (../sage/) -- richer algebra system, needs local install or Codespaces # # Both versions cover the same material. Choose whichever works for you. import sys, os sys.path.insert(0, os.path.join('..', '..', '..', 'shared')) from cryptolab import Mod, divisors, factor, is_prime, power_mod, primitive_root

Connect: Diffie-Hellman Parameter Selection

Module 01 | Real-World Connections

Generators, orders, and safe primes --- Module 01's concepts determine whether Diffie-Hellman is secure.

Introduction

Diffie-Hellman key exchange lives in (Z/pZ)(\mathbb{Z}/p\mathbb{Z})^*, the multiplicative group of integers mod a prime pp. The security depends on choosing the right pp and gg --- and Module 01 taught you exactly what "right" means.

In this notebook, we'll trace how generators, element orders, safe primes, and Lagrange's theorem directly determine whether a Diffie-Hellman instantiation is secure or broken.

Generator = DH Base

In Diffie-Hellman, both parties compute powers of a shared base gg modulo a prime pp. For security, gg must be a generator of (Z/pZ)(\mathbb{Z}/p\mathbb{Z})^* --- meaning gg has order p1p-1 and its powers produce every element of the group.

If gg is not a generator, then the powers g1,g2,g^1, g^2, \ldots only cover a subgroup, which shrinks the space an attacker must search.

# Pick a safe prime and a generator p = 2267 # safe prime: 2267 = 2 * 1133 + 1, 1133 is prime q = (p - 1) // 2 print(f'Safe prime p = {p}') print(f'q = (p-1)/2 = {q}, is_prime(q) = {is_prime(q)}') # Find a generator g = primitive_root(p) print(f'Generator g = {g}') print(f'Order of g = {Mod(g, p).multiplicative_order()} (should be {p-1})')

The Key Exchange

Diffie-Hellman lets two parties (Alice and Bob) establish a shared secret over a public channel:

  1. Alice picks a secret aa, sends A=gamodpA = g^a \bmod p.

  2. Bob picks a secret bb, sends B=gbmodpB = g^b \bmod p.

  3. Both compute the shared secret: s=gabmodps = g^{ab} \bmod p.

An eavesdropper sees gg, pp, AA, and BB, but computing ss requires solving the discrete logarithm problem (DLP).

# Alice picks secret a, computes A = g^a mod p a = 1234 # Alice's secret A = power_mod(g, a, p) # Bob picks secret b, computes B = g^b mod p b = 5678 # Bob's secret B = power_mod(g, b, p) # Shared secret s_alice = power_mod(B, a, p) # Alice computes B^a s_bob = power_mod(A, b, p) # Bob computes A^b print(f'Alice sends: A = g^a = {A}') print(f'Bob sends: B = g^b = {B}') print(f'Alice computes: B^a = {s_alice}') print(f'Bob computes: A^b = {s_bob}') print(f'Shared secret matches: {s_alice == s_bob}')

Why Parameters Matter: The Danger of Bad Choices

Not all primes and generators are created equal. If the parameters are poorly chosen, Diffie-Hellman can be broken even without solving the general DLP.

Two key dangers (explored in the break notebooks):

  1. Smooth-order groups: If p1p - 1 has only small prime factors, the Pohlig-Hellman algorithm can solve DLP efficiently by working in each small subgroup separately.

  2. Weak generators: If gg generates a small subgroup of (Z/pZ)(\mathbb{Z}/p\mathbb{Z})^*, the shared secret lives in that subgroup, drastically reducing the search space.

This is why we need safe primes and full generators.

Safe Primes: Lagrange's Theorem in Action

A safe prime is a prime pp where q=(p1)/2q = (p-1)/2 is also prime.

Why does this help? By Lagrange's theorem, every subgroup order must divide the group order G=p1=2q|G| = p - 1 = 2q. If qq is prime, the only divisors of p1p - 1 are:

1,2,q,2q1, \quad 2, \quad q, \quad 2q

So the only subgroups have order 11 (trivial), 22 (just {1,1}\{1, -1\}), qq (half the group), or 2q=p12q = p-1 (the full group). There are no small subgroups to exploit.

# Compare subgroup structure: safe prime vs non-safe prime p_safe = 2267 p_unsafe = 2269 # 2269 is prime, but (2269-1) = 2268 = 2^2 * 3^3 * 7 * 3 print(f'Safe prime p = {p_safe}') print(f' p-1 = {p_safe - 1} = {factor(p_safe - 1)}') print(f' Possible subgroup orders (divisors of p-1): {divisors(p_safe - 1)}') print() print(f'Non-safe prime p = {p_unsafe}') print(f' p-1 = {p_unsafe - 1} = {factor(p_unsafe - 1)}') print(f' Possible subgroup orders (divisors of p-1): {divisors(p_unsafe - 1)}') print(f' Many small subgroups to exploit!')

Parameter Validation

Before using DH parameters, you should validate them. Here's a checklist derived directly from Module 01 concepts:

def validate_dh_params(p, g): """Check DH parameters are secure""" checks = [] checks.append(('p is prime', is_prime(p))) q = (p - 1) // 2 checks.append(('p is safe prime (q=(p-1)/2 is prime)', is_prime(q))) checks.append(('g is a generator', Mod(g, p).multiplicative_order() == p - 1)) checks.append(('g != 1', g != 1)) checks.append(('g != p-1', g != p - 1)) for desc, ok in checks: status = 'PASS' if ok else 'FAIL' print(f' [{status}] {desc}') return all(ok for _, ok in checks) print('=== Validating our parameters ===') print(f'p = {p}, g = {g}') result = validate_dh_params(p, g) print(f'Overall: {"SECURE" if result else "INSECURE"}')
# Test with deliberately bad parameters print('=== Validating BAD parameters ===') print(f'p = {p}, g = 1') validate_dh_params(p, 1) print() print(f'p = {p}, g = {p-1}') validate_dh_params(p, p - 1)

Real-World Parameters: RFC 3526

In practice, DH parameters are not generated on the fly. Standardized groups from RFC 3526 are used --- these specify huge safe primes (1536-bit to 8192-bit) that have been carefully vetted.

For example, the 1536-bit MODP group uses a prime of the form:

p=21536214721+264(21406π+741804)p = 2^{1536} - 2^{1472} - 1 + 2^{64} \cdot (\lfloor 2^{1406} \pi \rfloor + 741804)

The generator is simply g=2g = 2. This works because for these carefully chosen primes, 22 is a generator of the full group (Z/pZ)(\mathbb{Z}/p\mathbb{Z})^*.

The takeaway: the concepts from Module 01 (generators, orders, safe primes) are exactly what standards bodies check when selecting parameters for worldwide use.

Concept Map: Module 01 \to Diffie-Hellman

Module 01 ConceptDH Application
GeneratorsDH base gg must generate (Z/pZ)(\mathbb{Z}/p\mathbb{Z})^*
Element ordergg must have order p1p-1 (full group order)
Safe primesp=2q+1p = 2q+1 prevents small-subgroup attacks
Lagrange's theoremConstrains subgroup sizes, limits attack surface
Modular exponentiationAll DH computations (gag^a, gbg^b, gabg^{ab})
Discrete logarithmSecurity assumption: given gag^a, finding aa is hard

What's Next

Module 05 implements full Diffie-Hellman key exchange and the attacks against it --- including Pohlig-Hellman (exploiting smooth orders) and small-subgroup confinement (exploiting weak generators). You'll see firsthand why every parameter choice matters.

Summary

ConceptKey idea
DH group(Z/pZ)(\mathbb{Z}/p\mathbb{Z})^*, the cyclic group we studied all module
Base ggMust be a generator (order p1p-1), ensuring the shared secret can be any group element
Safe primesp=2q+1p = 2q + 1 with qq prime prevents small-subgroup attacks, a direct consequence of Lagrange's theorem
Parameter validationChecks exactly the properties we learned: primality, generator status, order
Real-world standardsRFC 3526 encodes these same mathematical requirements for worldwide use

The abstract algebra from Module 01 is not background theory. It is the security engineering.