// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// This module is browser compatible.

import { assert } from "jsr:/@std/assert@^0.224.0/assert";

/**
 * When checking the values of cryptographic hashes are equal, default
 * comparisons can be susceptible to timing based attacks, where attacker is
 * able to find out information about the host system by repeatedly checking
 * response times to equality comparisons of values.
 *
 * It is likely some form of timing safe equality will make its way to the
 * WebCrypto standard (see:
 * {@link https://github.com/w3c/webcrypto/issues/270 | w3c/webcrypto#270}), but until
 * that time, `timingSafeEqual()` is provided:
 *
 * ```ts
 * import { timingSafeEqual } from "@std/crypto/timing-safe-equal";
 * import { assert } from "@std/assert/assert";
 *
 * const a = await crypto.subtle.digest(
 *   "SHA-384",
 *   new TextEncoder().encode("hello world"),
 * );
 * const b = await crypto.subtle.digest(
 *   "SHA-384",
 *   new TextEncoder().encode("hello world"),
 * );
 *
 * assert(timingSafeEqual(a, b));
 * ```
 */
export function timingSafeEqual(
  a: ArrayBufferView | ArrayBufferLike | DataView,
  b: ArrayBufferView | ArrayBufferLike | DataView,
): boolean {
  if (a.byteLength !== b.byteLength) {
    return false;
  }
  if (!(a instanceof DataView)) {
    a = ArrayBuffer.isView(a)
      ? new DataView(a.buffer, a.byteOffset, a.byteLength)
      : new DataView(a);
  }
  if (!(b instanceof DataView)) {
    b = ArrayBuffer.isView(b)
      ? new DataView(b.buffer, b.byteOffset, b.byteLength)
      : new DataView(b);
  }
  assert(a instanceof DataView);
  assert(b instanceof DataView);
  const length = a.byteLength;
  let out = 0;
  let i = -1;
  while (++i < length) {
    out |= a.getUint8(i) ^ b.getUint8(i);
  }
  return out === 0;
}

// denoCacheMetadata={"headers":{"x-jsr-backend":"modules","content-type":"text/typescript","cf-cache-status":"HIT","nel":"{\"report_to\":\"cf-nel\",\"success_fraction\":0.0,\"max_age\":604800}","cache-control":"public, max-age=31536000, immutable","age":"1322354","etag":"\"cdac6632c5c27a2fc21bcf32ac3ebec7\"","cf-ray":"a223e6564f517db6-LAX","x-robots-tag":"noindex","x-content-type-options":"nosniff","access-control-expose-headers":"*","content-length":"1825","content-security-policy":"default-src 'none'; script-src 'none'; style-src 'none'; img-src 'none'; font-src 'none'; connect-src 'none'; frame-src 'none'; object-src 'none'; frame-ancestors 'none'; sandbox; form-action 'none';","accept-ranges":"bytes","vary":"Origin","set-cookie":"__cf_bm=klxBdPO3X.tzUuE96IP2mePvrj7ojf71E3YqwsZiEhI-1785241874.9693732-1.0.1.1-ZP6L6A5EHes.ioGgqjPd56ddMf1VPy9QbvraQo_Nv9yM4fvsViavG9QnBaSC5Y1gTMZU3slC1l.KiKTkrvw0JUGyeZUBLXTiWcIQ4OyNxVBNCZtL5cyFQs_mxEh3LYSI; HttpOnly; SameSite=None; Secure; Path=/; Domain=jsr.io; Expires=Tue, 28 Jul 2026 13:01:14 GMT","alt-svc":"h3=\":443\"; ma=86400","access-control-allow-origin":"*","report-to":"{\"group\":\"cf-nel\",\"max_age\":604800,\"endpoints\":[{\"url\":\"https://a.nel.cloudflare.com/report/v4?s=HQDMKYTvUqRrhsrcxV0WFRUBumXd33p9NJmlmJi%2FRBZUR5ANgYx2frWHSvlGkbbG6mfZXghPzdwIi2WV3Y2vRiRl4j2qXMzOMqtz5M1GaRnJaPj%2Fp7pKeGk%3D\"}]}","server":"cloudflare","date":"Tue, 28 Jul 2026 12:31:14 GMT","cross-origin-resource-policy":"cross-origin"},"url":"https://jsr.io/@std/crypto/0.224.0/timing_safe_equal.ts","time":1785241874}