module ActiveSupport::SecurityUtils

def fixed_length_secure_compare(a, b)

that have already been processed by HMAC. Raises in case of length mismatch.
The values compared should be of fixed length, such as strings

Constant time string comparison, for fixed length strings.
def fixed_length_secure_compare(a, b)
  raise ArgumentError, "string length mismatch." unless a.bytesize == b.bytesize
  l = a.unpack "C#{a.bytesize}"
  res = 0
  b.each_byte { |byte| res |= byte ^ l.shift }
  res == 0
end

def secure_compare(a, b)

via timing attacks.
The values are first processed by SHA256, so that we don't leak length info

Constant time string comparison, for variable length strings.
def secure_compare(a, b)
  fixed_length_secure_compare(::Digest::SHA256.digest(a), ::Digest::SHA256.digest(b)) && a == b
end