/** Byte / base64 helpers (dependency-free; Node Buffer under the hood). */

export function bytesToBase64(bytes: Uint8Array): string {
  return Buffer.from(bytes).toString('base64')
}

export function base64ToBytes(b64: string): Uint8Array {
  // Buffer.from is lenient; assert round-trip to reject clearly-invalid input.
  const buf = Buffer.from(b64, 'base64')
  if (buf.toString('base64').replace(/=+$/, '') !== b64.replace(/=+$/, '')) {
    throw new Error('invalid base64')
  }
  return new Uint8Array(buf)
}

export function bytesToHex(bytes: Uint8Array): string {
  return Buffer.from(bytes).toString('hex')
}

/** Constant-time equality of two byte arrays (length-independent short-circuit avoided). */
export function timingSafeEqualBytes(a: Uint8Array, b: Uint8Array): boolean {
  if (a.length !== b.length) return false
  let diff = 0
  for (let i = 0; i < a.length; i++) {
    // Non-null via loop bounds; noUncheckedIndexedAccess guarded below.
    diff |= (a[i] as number) ^ (b[i] as number)
  }
  return diff === 0
}
