cybersecurity · advanced · ~15 min

Constant-Time Memory Comparator

Prevent timing side-channel attacks by implementing constant-time memory comparison.

Challenge

Standard library memcmp and strcmp terminate on the first mismatched byte, creating timing side channels that allow attackers to deduce cryptographic secrets and HMAC tokens byte by byte. Constant-time comparison accumulates differences across all bytes.

Your Task

Implement:

int constant_time_compare(const uint8_t *a, const uint8_t *b, size_t len);

Rules

  1. If a == NULL or b == NULL, return -1.
  2. If len == 0, return 0.
  3. Maintain an accumulator uint8_t diff = 0.
  4. In a single loop over len bytes, compute diff |= (a[i] ^ b[i]) for every index.
  5. Do not use early return or break on mismatch — always process all len bytes.
  6. Return 0 if diff == 0 (memory blocks are identical), or 1 if diff != 0 (memory blocks differ).

Example

uint8_t hmac1[4] = {0xAA, 0xBB, 0xCC, 0xDD};
uint8_t hmac2[4] = {0xAA, 0xBB, 0xCC, 0xDD};
constant_time_compare(hmac1, hmac2, 4); // returns 0 (identical)
uint8_t hmac3[4] = {0xAA, 0x00, 0xCC, 0xDD};
constant_time_compare(hmac1, hmac3, 4); // returns 1 (mismatched)

Input format

a, b: pointers to byte arrays; len: byte count.

Output format

Returns 0 if identical, 1 if mismatched, -1 on NULL pointer.

Constraints

Zero early returns in comparison loop. Bitwise OR accumulator.

Starter code

#include <stddef.h>
#include <stdint.h>

int constant_time_compare(const uint8_t *a, const uint8_t *b, size_t len) {
    (void)a; (void)b; (void)len;
    return -1;
}

Common mistakes

Breaking early when a difference is found; arithmetic subtraction instead of XOR.

Edge cases to handle

len == 0 returns 0; mismatch at byte 0 takes same execution path as mismatch at byte len-1.

Background lessons

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.