// Copyright 2026 Leo Cheng
// SPDX-License-Identifier: Apache-2.0

///|
/// Rotate a 32-bit word left by `n` bits.
fn rotl32(x : UInt, n : Int) -> UInt {
  (x << n) | (x >> (32 - n))
}

///|
/// The byte at bit-position `shift` of a 32-bit word (big-endian extraction).
fn u32_byte(x : UInt, shift : Int) -> Byte {
  ((x >> shift) & 0xFF).reinterpret_as_int().to_byte()
}

///|
/// SHA-1 (FIPS 180-4) over `msg`, returning the 20-byte digest.
///
/// MoonBit's core ships no SHA-1, but mysql_native_password's challenge-response
/// is built entirely on it (`SHA1(password) XOR SHA1(salt + SHA1(SHA1(password)))`),
/// so the driver carries its own. Pure and allocation-simple; verified against
/// the FIPS/NIST test vectors in the suite.
pub fn sha1(msg : Bytes) -> Bytes {
  let ml = msg.length()
  // Padded length = message ++ 0x80 ++ zero-fill to 56 mod 64 ++ 8-byte bit count.
  let base = ml + 1 + 8
  let rem = base % 64
  let total = if rem == 0 { base } else { base + (64 - rem) }
  let buf = FixedArray::make(total, b'\x00')
  for i in 0..> (i * 8)) & 0xFFL).to_byte()
  }
  let mut h0 = (0x67452301 : UInt)
  let mut h1 = (0xEFCDAB89 : UInt)
  let mut h2 = (0x98BADCFE : UInt)
  let mut h3 = (0x10325476 : UInt)
  let mut h4 = (0xC3D2E1F0 : UInt)
  let w = FixedArray::make(80, 0U)
  let chunks = total / 64
  let all_ones = 0xFFFFFFFFU
  for c in 0..