// File: FFY00[P]uicc/include/milenage.h
// Function: milenage_f2345(unsigned char const*, unsigned char const*, unsigned char const*, unsigned char*, unsigned char*, unsigned char*, unsigned char*, unsigned char*)
bool milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand,
                    u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar) {
  u8 tmp1[16], tmp2[16], tmp3[16];
  int i;

  /* tmp2 = 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, tmp2);

  /* OUT2 = E_K(rot(TEMP XOR OP_C, r2) XOR c2) XOR OP_C */
  /* OUT3 = E_K(rot(TEMP XOR OP_C, r3) XOR c3) XOR OP_C */
  /* OUT4 = E_K(rot(TEMP XOR OP_C, r4) XOR c4) XOR OP_C */
  /* OUT5 = E_K(rot(TEMP XOR OP_C, r5) XOR c5) XOR OP_C */

  /* f2 and f5 */
  /* rotate by r2 (= 0, i.e., NOP) */
  for (i = 0; i < 16; i++)
    tmp1[i] = tmp2[i] ^ opc[i];

  tmp1[15] ^= 1; /* XOR c2 (= ..01) */
  /* f5 || f2 = E_K(tmp1) XOR OP_c */
  aes_128_encrypt_block(k, tmp1, tmp3);

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

  if (res)
    memcpy(res, tmp3 + 8, 8); /* f2 */

  if (ak)
    memcpy(ak, tmp3, 6); /* f5 */

  /* f3 */
  if (ck) {
    /* rotate by r3 = 0x20 = 4 bytes */
    for (i = 0; i < 16; i++)
      tmp1[(i + 12) % 16] = tmp2[i] ^ opc[i];

    tmp1[15] ^= 2; /* XOR c3 (= ..02) */
    aes_128_encrypt_block(k, tmp1, ck);

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

  /* f4 */
  if (ik) {
    /* rotate by r4 = 0x40 = 8 bytes */
    for (i = 0; i < 16; i++)
      tmp1[(i + 8) % 16] = tmp2[i] ^ opc[i];

    tmp1[15] ^= 4; /* XOR c4 (= ..04) */
    aes_128_encrypt_block(k, tmp1, ik);

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

  /* f5* */
  if (akstar) {
    /* rotate by r5 = 0x60 = 12 bytes */
    for (i = 0; i < 16; i++)
      tmp1[(i + 4) % 16] = tmp2[i] ^ opc[i];

    tmp1[15] ^= 8; /* XOR c5 (= ..08) */
    aes_128_encrypt_block(k, tmp1, tmp1);

    for (i = 0; i < 6; i++)
      akstar[i] = tmp1[i] ^ opc[i];
  }

  return true;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x70, %rsp
movq 0x18(%rbp), %rax
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 0x38a4
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 0x386f
movq -0x10(%rbp), %rdi
leaq -0x40(%rbp), %rsi
leaq -0x50(%rbp), %rdx
callq 0x37f0
movl $0x0, -0x64(%rbp)
cmpl $0x10, -0x64(%rbp)
jge 0x38ee
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
movslq -0x64(%rbp), %rax
movb %cl, -0x40(%rbp,%rax)
movl -0x64(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x64(%rbp)
jmp 0x38bc
movzbl -0x31(%rbp), %eax
xorl $0x1, %eax
movb %al, -0x31(%rbp)
movq -0x10(%rbp), %rdi
leaq -0x40(%rbp), %rsi
leaq -0x60(%rbp), %rdx
callq 0x37f0
movl $0x0, -0x64(%rbp)
cmpl $0x10, -0x64(%rbp)
jge 0x393c
movq -0x8(%rbp), %rax
movslq -0x64(%rbp), %rcx
movzbl (%rax,%rcx), %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 0x3910
cmpq $0x0, -0x20(%rbp)
je 0x394e
movq -0x20(%rbp), %rax
movq -0x58(%rbp), %rcx
movq %rcx, (%rax)
cmpq $0x0, 0x10(%rbp)
je 0x3966
movq 0x10(%rbp), %rax
movl -0x60(%rbp), %ecx
movl %ecx, (%rax)
movw -0x5c(%rbp), %cx
movw %cx, 0x4(%rax)
cmpq $0x0, -0x28(%rbp)
je 0x3a09
movl $0x0, -0x64(%rbp)
cmpl $0x10, -0x64(%rbp)
jge 0x39b7
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 $0xc, %eax
movl $0x10, %esi
cltd
idivl %esi
movslq %edx, %rax
movb %cl, -0x40(%rbp,%rax)
movl -0x64(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x64(%rbp)
jmp 0x3978
movzbl -0x31(%rbp), %eax
xorl $0x2, %eax
movb %al, -0x31(%rbp)
movq -0x10(%rbp), %rdi
leaq -0x40(%rbp), %rsi
movq -0x28(%rbp), %rdx
callq 0x37f0
movl $0x0, -0x64(%rbp)
cmpl $0x10, -0x64(%rbp)
jge 0x3a07
movq -0x8(%rbp), %rax
movslq -0x64(%rbp), %rcx
movzbl (%rax,%rcx), %esi
movq -0x28(%rbp), %rax
movslq -0x64(%rbp), %rcx
movzbl (%rax,%rcx), %edx
xorl %esi, %edx
movb %dl, (%rax,%rcx)
movl -0x64(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x64(%rbp)
jmp 0x39d9
jmp 0x3a09
cmpq $0x0, -0x30(%rbp)
je 0x3aac
movl $0x0, -0x64(%rbp)
cmpl $0x10, -0x64(%rbp)
jge 0x3a5a
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, -0x40(%rbp,%rax)
movl -0x64(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x64(%rbp)
jmp 0x3a1b
movzbl -0x31(%rbp), %eax
xorl $0x4, %eax
movb %al, -0x31(%rbp)
movq -0x10(%rbp), %rdi
leaq -0x40(%rbp), %rsi
movq -0x30(%rbp), %rdx
callq 0x37f0
movl $0x0, -0x64(%rbp)
cmpl $0x10, -0x64(%rbp)
jge 0x3aaa
movq -0x8(%rbp), %rax
movslq -0x64(%rbp), %rcx
movzbl (%rax,%rcx), %esi
movq -0x30(%rbp), %rax
movslq -0x64(%rbp), %rcx
movzbl (%rax,%rcx), %edx
xorl %esi, %edx
movb %dl, (%rax,%rcx)
movl -0x64(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x64(%rbp)
jmp 0x3a7c
jmp 0x3aac
cmpq $0x0, 0x18(%rbp)
je 0x3b56
movl $0x0, -0x64(%rbp)
cmpl $0x10, -0x64(%rbp)
jge 0x3afd
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 $0x4, %eax
movl $0x10, %esi
cltd
idivl %esi
movslq %edx, %rax
movb %cl, -0x40(%rbp,%rax)
movl -0x64(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x64(%rbp)
jmp 0x3abe
movzbl -0x31(%rbp), %eax
xorl $0x8, %eax
movb %al, -0x31(%rbp)
movq -0x10(%rbp), %rdi
leaq -0x40(%rbp), %rsi
leaq -0x40(%rbp), %rdx
callq 0x37f0
movl $0x0, -0x64(%rbp)
cmpl $0x6, -0x64(%rbp)
jge 0x3b54
movslq -0x64(%rbp), %rax
movzbl -0x40(%rbp,%rax), %eax
movq -0x8(%rbp), %rcx
movslq -0x64(%rbp), %rdx
movzbl (%rcx,%rdx), %ecx
xorl %ecx, %eax
movb %al, %dl
movq 0x18(%rbp), %rax
movslq -0x64(%rbp), %rcx
movb %dl, (%rax,%rcx)
movl -0x64(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x64(%rbp)
jmp 0x3b1f
jmp 0x3b56
movb $0x1, %al
andb $0x1, %al
addq $0x70, %rsp
popq %rbp
retq