// File: FFY00[P]uicc/include/milenage.h
// Function: milenage_f1(unsigned char const*, unsigned char const*, unsigned char const*, unsigned char const*, unsigned char const*, unsigned char*, unsigned char*)
bool milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand,
                 const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s) {
  u8 tmp1[16], tmp2[16], tmp3[16];
  int i;

  /* tmp1 = TEMP = E_K(RAND XOR OP_C) */
  for (i = 0; i < 16; i++)
    tmp1[i] = _rand[i] ^ opc[i];

  aes_128_encrypt_block(k, tmp1, tmp1);
  /* tmp2 = IN1 = SQN || AMF || SQN || AMF */
  memcpy(tmp2, sqn, 6);
  memcpy(tmp2 + 6, amf, 2);
  memcpy(tmp2 + 8, tmp2, 8);

  /* OUT1 = E_K(TEMP XOR rot(IN1 XOR OP_C, r1) XOR c1) XOR OP_C */

  /* rotate (tmp2 XOR OP_C) by r1 (= 0x40 = 8 bytes) */
  for (i = 0; i < 16; i++)
    tmp3[(i + 8) % 16] = tmp2[i] ^ opc[i];

  /* XOR with TEMP = E_K(RAND XOR OP_C) */
  for (i = 0; i < 16; i++)
    tmp3[i] ^= tmp1[i];

  /* XOR with c1 (= ..00, i.e., NOP) */
  /* f1 || f1* = E_K(tmp3) XOR OP_c */
  aes_128_encrypt_block(k, tmp3, tmp1);

  for (i = 0; i < 16; i++)
    tmp1[i] ^= opc[i];

  if (mac_a)
    memcpy(mac_a, tmp1, 8); /* f1 */

  if (mac_s)
    memcpy(mac_s, tmp1 + 8, 8); /* f1* */

  return true;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x70, %rsp
movq 0x10(%rbp), %rax
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movq %r8, -0x28(%rbp)
movq %r9, -0x30(%rbp)
movl $0x0, -0x64(%rbp)
cmpl $0x10, -0x64(%rbp)
jge 0x36d0
movq -0x18(%rbp), %rax
movslq -0x64(%rbp), %rcx
movzbl (%rax,%rcx), %eax
movq -0x8(%rbp), %rcx
movslq -0x64(%rbp), %rdx
movzbl (%rcx,%rdx), %ecx
xorl %ecx, %eax
movb %al, %cl
movslq -0x64(%rbp), %rax
movb %cl, -0x40(%rbp,%rax)
movl -0x64(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x64(%rbp)
jmp 0x369b
movq -0x10(%rbp), %rdi
leaq -0x40(%rbp), %rsi
leaq -0x40(%rbp), %rdx
callq 0x37f0
movq -0x20(%rbp), %rax
movl (%rax), %ecx
movl %ecx, -0x50(%rbp)
movw 0x4(%rax), %ax
movw %ax, -0x4c(%rbp)
movq -0x28(%rbp), %rax
movw (%rax), %ax
movw %ax, -0x4a(%rbp)
movq -0x50(%rbp), %rax
movq %rax, -0x48(%rbp)
movl $0x0, -0x64(%rbp)
cmpl $0x10, -0x64(%rbp)
jge 0x374b
movslq -0x64(%rbp), %rax
movzbl -0x50(%rbp,%rax), %eax
movq -0x8(%rbp), %rcx
movslq -0x64(%rbp), %rdx
movzbl (%rcx,%rdx), %ecx
xorl %ecx, %eax
movb %al, %cl
movl -0x64(%rbp), %eax
addl $0x8, %eax
movl $0x10, %esi
cltd
idivl %esi
movslq %edx, %rax
movb %cl, -0x60(%rbp,%rax)
movl -0x64(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x64(%rbp)
jmp 0x370c
movl $0x0, -0x64(%rbp)
cmpl $0x10, -0x64(%rbp)
jge 0x377b
movslq -0x64(%rbp), %rax
movzbl -0x40(%rbp,%rax), %edx
movslq -0x64(%rbp), %rax
movzbl -0x60(%rbp,%rax), %ecx
xorl %edx, %ecx
movb %cl, -0x60(%rbp,%rax)
movl -0x64(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x64(%rbp)
jmp 0x3752
movq -0x10(%rbp), %rdi
leaq -0x60(%rbp), %rsi
leaq -0x40(%rbp), %rdx
callq 0x37f0
movl $0x0, -0x64(%rbp)
cmpl $0x10, -0x64(%rbp)
jge 0x37bf
movq -0x8(%rbp), %rax
movslq -0x64(%rbp), %rcx
movzbl (%rax,%rcx), %edx
movslq -0x64(%rbp), %rax
movzbl -0x40(%rbp,%rax), %ecx
xorl %edx, %ecx
movb %cl, -0x40(%rbp,%rax)
movl -0x64(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x64(%rbp)
jmp 0x3793
cmpq $0x0, -0x30(%rbp)
je 0x37d1
movq -0x30(%rbp), %rax
movq -0x40(%rbp), %rcx
movq %rcx, (%rax)
cmpq $0x0, 0x10(%rbp)
je 0x37e3
movq 0x10(%rbp), %rax
movq -0x38(%rbp), %rcx
movq %rcx, (%rax)
movb $0x1, %al
andb $0x1, %al
addq $0x70, %rsp
popq %rbp
retq
nopl (%rax)