Hands-on hmac.compare_digest vs bytes == verify lab: real ops/s plus HMAC-SHA256 construct costs, measured on Linux localhost in this eng lab for SREs.
4 min read
Verifying an auth digest: hmac.compare_digest vs naive ==, plus HMAC-SHA256 construct throughput. This lab reports ops/s on Linux localhost.
It is not a hashlib algorithm bake-off (md5 vs blake2b) and not CSPRNG minting (secrets vs urandom). This is not a timing-attack proof — we measure throughput and recommend compare_digest for tokens/MACs anyway.
Related links:
Lab honesty (1 Oct 2026 IST): Python 3.13.5. Affiliates: 0. No Docker. Equal and unequal 32-byte digests.
Verdict up front: == on equal digests ~29.68 Mops/s vs compare_digest ~15.63 Mops/s (~1.9×). HMAC-SHA256 construct B: ~623.4 kops/s (raw hashlib.sha256 is faster and not a MAC).
| Arm | Role |
|---|---|
hmac.compare_digest(a,b) | recommended verify |
a == b | naive equality |
| equal / unequal digests | both paths |
hmac.new(...).digest() | MAC construct |
hashlib.sha256 | honesty non-MAC contrast |
Script: lab-evidence/96-hmac-compare-digest/results/run_lab.py.
| Arm | Mops/s |
|---|---|
bytes == equal | 29.68 |
| compare_digest equal | 15.63 |
bytes == unequal | 42.08 |
| compare_digest unequal | 20.75 |
| Payload | hmac.new kops/s | hmac.update kops/s | sha256 (not MAC) kops/s |
|---|---|---|---|
| 64 B | 623.4 | 598.5 | 2335.0 |
| 8 KiB | 146.0 | 143.5 | 176.0 |
== is faster on this microbench — that is not a reason to use it for secrets.compare_digest is the stdlib API intended for secret comparisons; use it for tokens, password hashes, cookies, HMAC tags.| Need | Use |
|---|---|
| Compare two digests/tokens | hmac.compare_digest |
| Compute keyed MAC | hmac.new(key, msg, sha256) |
| Fast content hash (non-auth) | hashlib (see lab 77) |
| Random secret bytes | secrets (see lab 88) |
Auth compares are rarely the hot path next to network or DB. Paying ~1.9× on a 32-byte compare is cheap insurance versus shipping a short-circuiting == into a token check. Optimize MAC generation or I/O before shaving compare_digest.
Unequal digests made both == and compare_digest faster here (early exit vs still scanning). Production verifiers should assume attackers control one side — that is exactly why short-circuiting equality is the wrong default for secrets even when it wins a microbench.
HMAC construction (~hundreds of kops/s at 64 B) dwarfs compare cost (~tens of Mops/s). If verify is hot, you are usually recomputing the MAC or hitting I/O — not losing to compare_digest. Profile before replacing stdlib safety calls.
== on password hashes / API tokens because a blog showed Mops/s.compare_digest (it also length-checks safely).Evidence: summary.json, summary.txt.
One Linux box. Throughput only. Not hardware timing analysis. SHA-256 only.
== ~29.68 Mops/s beat compare_digest ~15.63 Mops/s here — still use hmac.compare_digest for auth verifies. Build MACs with hmac, not bare hashlib, and keep CSPRNG/secrets for key material.
Lab evidence
Lab 1 Oct 2026 IST. Python 3.13.5. compare equal: == 29.68 Mops/s vs compare_digest 15.63 (~1.9x). HMAC@64B 623.4 kops/s. Not timing-attack proof; not labs 77/88. Affiliates: 0. Evidence: lab-evidence/96-hmac-compare-digest/.
Hands-on platform.platform vs os.uname host inventory lab: real ops/s plus cache notes, measured on Linux localhost today in this hands-on lab for SREs.
Summary1 Oct 20264 min read
Hands-on uuid.uuid4 vs uuid.uuid1 ID generation lab: real ops/s plus version/node checks, measured on Linux localhost today in this hands-on lab for SREs.
Summary1 Oct 20263 min read
Hands-on cmath vs math.hypot magnitude ops lab: real ops/s for abs, polar, and phase, measured on Linux localhost today in this hands-on lab for SREs.
Summary1 Oct 20263 min read