crypto/subtle provides cryptographic operations designed to reduce timing side channels. Its ConstantTimeCompare function compares byte slices without stopping at the first mismatched byte, making runtime depend on slice length rather than contents. section 10.4.1
ConstantTimeCompare works by:
- Returning 0 immediately when the slice lengths differ. section 10.4.1
- XORing corresponding bytes and accumulating every difference instead of short-circuiting. section 10.4.1
- Using ConstantTimeByteEq to determine whether the accumulated difference is zero. section 10.4.1
Why ordinary comparison leaks information
A memcmp-style loop exits at the first mismatch, so matching a longer prefix takes longer. An attacker can use these timing differences to infer where a comparison failed; ConstantTimeCompare processes every position instead. section 10.4.1
Listing 10.2 Constant-time comparisons in the crypto/subtle Go package
func ConstantTimeCompare(x, y []byte) int {
if len(x) != len(y) {
return 0
}
var v byte
for i := 0; i < len(x); i++ {
v |= x[i] ^ y[i]
}
return ConstantTimeByteEq(v, 0)
}
// ...
func ConstantTimeByteEq(x, y uint8) int {
return int((uint32(x^y) - 1) >> 31)
}
Inspect the Go implementation, including its XOR accumulator and ConstantTimeByteEq helper. section 10.4.1
