// 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..