user: Translate the below assembly code into C programming language:

```asm
<castle_norm_key_bounds_check>:
  endbr64
  push   %rbp
  mov    %rsp,%rbp
  sub    $0x90,%rsp
  mov    %rdi,-0x78(%rbp)
  mov    %rsi,-0x80(%rbp)
  mov    %rdx,-0x88(%rbp)
  mov    %rcx,-0x90(%rbp)
  mov    %fs:0x28,%rax
  mov    %rax,-0x8(%rbp)
  xor    %eax,%eax
  lea    -0x68(%rbp),%rdx
  mov    -0x78(%rbp),%rax
  mov    %rdx,%rsi
  mov    %rax,%rdi
  call   <castle_norm_key_end@plt>
  mov    %rax,-0x50(%rbp)
  lea    -0x60(%rbp),%rdx
  mov    -0x80(%rbp),%rax
  mov    %rdx,%rsi
  mov    %rax,%rdi
  call   <castle_norm_key_end@plt>
  mov    %rax,-0x48(%rbp)
  lea    -0x58(%rbp),%rdx
  mov    -0x88(%rbp),%rax
  mov    %rdx,%rsi
  mov    %rax,%rdi
  call   <castle_norm_key_end@plt>
  mov    %rax,-0x40(%rbp)
  lea    -0x68(%rbp),%rax
  mov    %rax,%rdi
  call   <castle_norm_key_dim_get@plt>
  mov    %rax,-0x38(%rbp)
  lea    -0x60(%rbp),%rax
  mov    %rax,%rdi
  call   <castle_norm_key_dim_get@plt>
  mov    %rax,-0x30(%rbp)
  lea    -0x58(%rbp),%rax
  mov    %rax,%rdi
  call   <castle_norm_key_dim_get@plt>
  mov    %rax,-0x28(%rbp)
  mov    -0x38(%rbp),%rax
  cmp    -0x30(%rbp),%rax
  jne    L4
  mov    -0x38(%rbp),%rax
  cmp    -0x28(%rbp),%rax
  jne    L4
  mov    $0x1,%eax
  jmp    L11
L4:
  mov    $0x0,%eax
L11:
  mov    %eax,%edi
  call   <assert@plt>
  movl   $0x0,-0x6c(%rbp)
  jmp    L114
L64:
  mov    -0x68(%rbp),%rax
  mov    %rax,%rdi
  call   <castle_norm_key_dim_next@plt>
  mov    %rax,-0x20(%rbp)
  mov    -0x60(%rbp),%rax
  mov    %rax,%rdi
  call   <castle_norm_key_dim_next@plt>
  mov    %rax,-0x18(%rbp)
  mov    -0x58(%rbp),%rax
  mov    %rax,%rdi
  call   <castle_norm_key_dim_next@plt>
  mov    %rax,-0x10(%rbp)
  mov    -0x60(%rbp),%rdx
  mov    -0x18(%rbp),%rax
  sub    %rdx,%rax
  mov    %eax,%ecx
  mov    -0x60(%rbp),%rdx
  mov    -0x68(%rbp),%rsi
  mov    -0x20(%rbp),%rax
  sub    %rsi,%rax
  mov    %eax,%esi
  mov    -0x68(%rbp),%rax
  mov    %rax,%rdi
  call   <castle_norm_key_data_compare@plt>
  test   %rax,%rax
  jns    L53
  cmpq   $0x0,-0x90(%rbp)
  je     L128
  mov    -0x90(%rbp),%rax
  mov    -0x6c(%rbp),%edx
  mov    %edx,(%rax)
L128:
  mov    $0xffffffff,%eax
  jmp    L90
L53:
  mov    -0x58(%rbp),%rdx
  mov    -0x10(%rbp),%rax
  sub    %rdx,%rax
  mov    %eax,%ecx
  mov    -0x58(%rbp),%rdx
  mov    -0x68(%rbp),%rsi
  mov    -0x20(%rbp),%rax
  sub    %rsi,%rax
  mov    %eax,%esi
  mov    -0x68(%rbp),%rax
  mov    %rax,%rdi
  call   <castle_norm_key_data_compare@plt>
  test   %rax,%rax
  jle    L15
  cmpq   $0x0,-0x90(%rbp)
  je     L103
  mov    -0x90(%rbp),%rax
  mov    -0x6c(%rbp),%edx
  mov    %edx,(%rax)
L103:
  mov    $0x1,%eax
  jmp    L90
L15:
  mov    -0x20(%rbp),%rax
  mov    %rax,-0x68(%rbp)
  mov    -0x18(%rbp),%rax
  mov    %rax,-0x60(%rbp)
  mov    -0x10(%rbp),%rax
  mov    %rax,-0x58(%rbp)
  addl   $0x1,-0x6c(%rbp)
L114:
  mov    -0x6c(%rbp),%eax
  cmp    %rax,-0x38(%rbp)
  ja     L64
  mov    -0x68(%rbp),%rax
  cmp    %rax,-0x50(%rbp)
  jne    L42
  mov    -0x60(%rbp),%rax
  cmp    %rax,-0x48(%rbp)
  jne    L42
  mov    -0x58(%rbp),%rax
  cmp    %rax,-0x40(%rbp)
  jne    L42
  mov    $0x1,%eax
  jmp    L74
L42:
  mov    $0x0,%eax
L74:
  mov    %eax,%edi
  call   <assert@plt>
  mov    $0x0,%eax
L90:
  mov    -0x8(%rbp),%rdx
  sub    %fs:0x28,%rdx
  je     L148
  call   <__stack_chk_fail@plt>
L148:
  leave
  ret
```

assistant: ```c
int castle_norm_key_bounds_check(const struct castle_norm_key *key, const struct castle_norm_key *lower, const struct castle_norm_key *upper, unsigned int *offending_dim) {
  const unsigned char *key_curr, *key_end = castle_norm_key_end(key, &key_curr);
  const unsigned char *lower_curr, *lower_end = castle_norm_key_end(lower, &lower_curr);
  const unsigned char *upper_curr, *upper_end = castle_norm_key_end(upper, &upper_curr);
  unsigned int dim;
  size_t key_dim = castle_norm_key_dim_get(&key_curr);
  size_t lower_dim = castle_norm_key_dim_get(&lower_curr);
  size_t upper_dim = castle_norm_key_dim_get(&upper_curr);
  assert(!(key_dim != lower_dim || key_dim != upper_dim));
  for (dim = 0; dim < key_dim; ++dim) {
    const unsigned char *key_next = castle_norm_key_dim_next(key_curr);
    const unsigned char *lower_next = castle_norm_key_dim_next(lower_curr);
    const unsigned char *upper_next = castle_norm_key_dim_next(upper_curr);
    if (castle_norm_key_data_compare(key_curr, key_next - key_curr, lower_curr, lower_next - lower_curr) < 0) {
      if (offending_dim)
        *offending_dim = dim;
      return -1;
    }
    if (castle_norm_key_data_compare(key_curr, key_next - key_curr, upper_curr, upper_next - upper_curr) > 0) {
      if (offending_dim)
        *offending_dim = dim;
      return 1;
    }
    key_curr = key_next;
    lower_curr = lower_next;
    upper_curr = upper_next;
  }
  assert(!(key_curr != key_end || lower_curr != lower_end || upper_curr != upper_end));
  return 0;
}
```