///|
/// RFC5155 SHA1 iteration with policy checked before any hashing.
pub fn nsec3_hash(
  name : Name,
  salt : Bytes,
  iterations : Int32,
  limits : Limits,
) -> Result[Bytes, DnsError] {
  match limits.validate() {
    Ok(_) => ()
    Err(e) => return Err(e)
  }
  if salt.length() > 255 {
    return Err(Malformed("NSEC3 salt length"))
  }
  if iterations < 0 || iterations > limits.max_nsec3_iterations {
    return Err(ResourceLimit("NSEC3 iterations exceed policy"))
  }
  let initial : Array[Byte] = []
  append_bytes(initial, name.wire())
  append_bytes(initial, salt)
  let mut hash = @sha1.hash(Bytes::from_array(initial)[:])
  for i = 0; i < iterations; i = i + 1 {
    let next : Array[Byte] = []
    append_bytes(next, hash)
    append_bytes(next, salt)
    hash = @sha1.hash(Bytes::from_array(next)[:])
  }
  Ok(hash)
}

///|
pub fn nsec3_label(hash : Bytes) -> Result[String, DnsError] {
  if hash.length() != 20 {
    return Err(Malformed("NSEC3 SHA1 hash length"))
  }
  let alphabet = "0123456789abcdefghijklmnopqrstuv"
  let out = StringBuilder()
  let mut acc = 0
  let mut bits = 0
  for b in hash {
    acc = (acc << 8) | b.to_int()
    bits += 8
    while bits >= 5 {
      bits -= 5
      let n = (acc >> bits) & 31
      out.write_char(alphabet[n].to_int().unsafe_to_char())
    }
    acc = acc & ((1 << bits) - 1)
  }
  Ok(out.to_string())
}

///|
pub fn decode_nsec3_label(label : Bytes) -> Result[Bytes, DnsError] {
  if label.length() != 32 {
    return Err(Malformed("NSEC3 owner hash label must have 32 characters"))
  }
  let out : Array[Byte] = []
  let mut acc = 0
  let mut bits = 0
  for b in label {
    let c = b.to_int()
    let n = if c >= 48 && c <= 57 {
      c - 48
    } else if c >= 97 && c <= 118 {
      c - 97 + 10
    } else {
      return Err(Malformed("NSEC3 owner is not base32hex"))
    }
    acc = (acc << 5) | n
    bits += 5
    if bits >= 8 {
      bits -= 8
      out.push(((acc >> bits) & 255).to_byte())
      acc = acc & ((1 << bits) - 1)
    }
  }
  Ok(Bytes::from_array(out))
}