#define NULL ((void *)0)
typedef unsigned long size_t; // Customize by platform.
typedef long intptr_t;
typedef unsigned long uintptr_t;
typedef long scalar_t__; // Either arithmetic or pointer type.
/* By default, we understand bool (as a convenience). */
typedef int bool;
#define false 0
#define true 1

/* Forward declarations */

/* Type definitions */
typedef int const uint8_t;
typedef int uint64_t;

/* Variables and functions */
int /*<<< orphan*/ memcpy(int const *, int *, int);
int /*<<< orphan*/ morus_stateupdate(int *, int **);
int morus_tag_verification(uint64_t msglen, uint64_t adlen, const uint8_t *c,
                           uint64_t state[][4]) {
  int i, j;
  uint8_t t[32];
  int check = 0;
  memcpy(t, state[3], 32);
  ((uint64_t *)t)[0] ^= (adlen << 3);
  ((uint64_t *)t)[1] ^= (msglen << 3);
  state[4][0] ^= state[0][0];
  state[4][1] ^= state[0][1];
  state[4][2] ^= state[0][2];
  state[4][3] ^= state[0][3];
  for (i = 0; i < 8; i++)
    morus_stateupdate((uint64_t *)t, state);
  for (i = 2; i < 5; i++) {
    for (j = 0; j < 4; j++) {
      state[1][j] ^= state[i][j];
    }
  }
  for (i = 0; i < 16; i++)
    check |= (c[msglen + i] ^ ((uint8_t *)state[1])[i]);
  if (0 == check)
    return 0;
  else
    return -1;
}


x86 assembly (clang, -O0):
<morus_tag_verification>:
push   %rbp
mov    %rsp,%rbp
sub    $0xc0,%rsp
mov    %edi,-0x8(%rbp)
mov    %esi,-0xc(%rbp)
mov    %rdx,-0x18(%rbp)
mov    %rcx,-0x20(%rbp)
movl   $0x0,-0xb4(%rbp)
lea    -0xb0(%rbp),%rdi
mov    -0x20(%rbp),%rsi
add    $0x30,%rsi
mov    $0x20,%edx
call   1030 <memcpy@plt>
mov    -0xc(%rbp),%eax
shl    $0x3,%eax
xor    -0xb0(%rbp),%eax
mov    %eax,-0xb0(%rbp)
mov    -0x8(%rbp),%eax
shl    $0x3,%eax
xor    -0xac(%rbp),%eax
mov    %eax,-0xac(%rbp)
mov    -0x20(%rbp),%rax
mov    (%rax),%ecx
mov    -0x20(%rbp),%rax
xor    0x40(%rax),%ecx
mov    %ecx,0x40(%rax)
mov    -0x20(%rbp),%rax
mov    0x4(%rax),%ecx
mov    -0x20(%rbp),%rax
xor    0x44(%rax),%ecx
mov    %ecx,0x44(%rax)
mov    -0x20(%rbp),%rax
mov    0x8(%rax),%ecx
mov    -0x20(%rbp),%rax
xor    0x48(%rax),%ecx
mov    %ecx,0x48(%rax)
mov    -0x20(%rbp),%rax
mov    0xc(%rax),%ecx
mov    -0x20(%rbp),%rax
xor    0x4c(%rax),%ecx
mov    %ecx,0x4c(%rax)
movl   $0x0,-0x24(%rbp)
cmpl   $0x8,-0x24(%rbp)
jge    11f2 <morus_tag_verification+0xd2>
lea    -0xb0(%rbp),%rdi
mov    -0x20(%rbp),%rsi
call   1040 <morus_stateupdate@plt>
mov    -0x24(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x24(%rbp)
jmp    11ca <morus_tag_verification+0xaa>
movl   $0x2,-0x24(%rbp)
cmpl   $0x5,-0x24(%rbp)
jge    125b <morus_tag_verification+0x13b>
movl   $0x0,-0x28(%rbp)
cmpl   $0x4,-0x28(%rbp)
jge    1248 <morus_tag_verification+0x128>
mov    -0x20(%rbp),%rax
movslq -0x24(%rbp),%rcx
shl    $0x4,%rcx
add    %rcx,%rax
movslq -0x28(%rbp),%rcx
mov    (%rax,%rcx,4),%edx
mov    -0x20(%rbp),%rax
movslq -0x28(%rbp),%rcx
xor    0x10(%rax,%rcx,4),%edx
mov    %edx,0x10(%rax,%rcx,4)
mov    -0x28(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x28(%rbp)
jmp    120a <morus_tag_verification+0xea>
jmp    124d <morus_tag_verification+0x12d>
mov    -0x24(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x24(%rbp)
jmp    11f9 <morus_tag_verification+0xd9>
movl   $0x0,-0x24(%rbp)
cmpl   $0x10,-0x24(%rbp)
jge    12a2 <morus_tag_verification+0x182>
mov    -0x18(%rbp),%rax
mov    -0x8(%rbp),%ecx
add    -0x24(%rbp),%ecx
movslq %ecx,%rcx
mov    (%rax,%rcx,4),%eax
mov    -0x20(%rbp),%rcx
movslq -0x24(%rbp),%rdx
xor    0x10(%rcx,%rdx,4),%eax
or     -0xb4(%rbp),%eax
mov    %eax,-0xb4(%rbp)
mov    -0x24(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x24(%rbp)
jmp    1262 <morus_tag_verification+0x142>
xor    %eax,%eax
cmp    -0xb4(%rbp),%eax
jne    12bc <morus_tag_verification+0x19c>
movl   $0x0,-0x4(%rbp)
jmp    12c3 <morus_tag_verification+0x1a3>
movl   $0xffffffff,-0x4(%rbp)
mov    -0x4(%rbp),%eax
add    $0xc0,%rsp
pop    %rbp
ret

x86 assembly (clang, -O2):
<morus_tag_verification>:
push   %rbp
push   %r15
push   %r14
push   %r12
push   %rbx
sub    $0x80,%rsp
mov    %rcx,%rbx
mov    %rdx,%r14
mov    %esi,%ebp
mov    %edi,%r15d
lea    0x30(%rcx),%rsi
mov    %rsp,%r12
mov    %r12,%rdi
mov    $0x20,%edx
call   1030 <memcpy@plt>
shl    $0x3,%ebp
xor    %ebp,(%rsp)
lea    0x0(,%r15,8),%eax
xor    %eax,0x4(%rsp)
movups (%rbx),%xmm0
movups 0x40(%rbx),%xmm1
xorps  %xmm0,%xmm1
movups %xmm1,0x40(%rbx)
mov    %r12,%rdi
mov    %rbx,%rsi
call   1040 <morus_stateupdate@plt>
mov    %r12,%rdi
mov    %rbx,%rsi
call   1040 <morus_stateupdate@plt>
mov    %r12,%rdi
mov    %rbx,%rsi
call   1040 <morus_stateupdate@plt>
mov    %r12,%rdi
mov    %rbx,%rsi
call   1040 <morus_stateupdate@plt>
mov    %r12,%rdi
mov    %rbx,%rsi
call   1040 <morus_stateupdate@plt>
mov    %r12,%rdi
mov    %rbx,%rsi
call   1040 <morus_stateupdate@plt>
mov    %r12,%rdi
mov    %rbx,%rsi
call   1040 <morus_stateupdate@plt>
mov    %r12,%rdi
mov    %rbx,%rsi
call   1040 <morus_stateupdate@plt>
movdqu 0x10(%rbx),%xmm0
movdqu 0x20(%rbx),%xmm1
movdqu 0x30(%rbx),%xmm2
movdqu 0x40(%rbx),%xmm3
pxor   %xmm1,%xmm0
movdqa %xmm2,%xmm4
pxor   %xmm3,%xmm4
pxor   %xmm0,%xmm4
movdqu %xmm4,0x10(%rbx)
movslq %r15d,%rax
movdqu (%r14,%rax,4),%xmm0
movdqu 0x10(%r14,%rax,4),%xmm5
movdqu 0x20(%r14,%rax,4),%xmm6
movdqu 0x30(%r14,%rax,4),%xmm7
pxor   %xmm4,%xmm0
pxor   %xmm2,%xmm6
por    %xmm0,%xmm6
pxor   %xmm3,%xmm7
pxor   %xmm1,%xmm5
por    %xmm7,%xmm5
por    %xmm6,%xmm5
pxor   %xmm0,%xmm0
pcmpeqb %xmm5,%xmm0
pmovmskb %xmm0,%ecx
xor    %eax,%eax
cmp    $0xffff,%ecx
setne  %al
neg    %eax
add    $0x80,%rsp
pop    %rbx
pop    %r12
pop    %r14
pop    %r15
pop    %rbp
ret

LLVM IR (-O0):
define i32 @morus_tag_verification(i32 %0, i32 %1, i32* %2, [4 x i32]* %3) {
%5 = alloca i32
%6 = alloca i32
%7 = alloca i32
%8 = alloca i32*
%9 = alloca [4 x i32]*
%10 = alloca i32
%11 = alloca i32
%12 = alloca [32 x i32]
%13 = alloca i32
store i32 %0, i32* %6
store i32 %1, i32* %7
store i32* %2, i32** %8
store [4 x i32]* %3, [4 x i32]** %9
store i32 0, i32* %13
%14 = getelementptr inbounds [32 x i32], [32 x i32]* %12, i64 0, i64 0
%15 = load [4 x i32]*, [4 x i32]** %9
%16 = getelementptr inbounds [4 x i32], [4 x i32]* %15, i64 3
%17 = getelementptr inbounds [4 x i32], [4 x i32]* %16, i64 0, i64 0
%18 = call i32 @memcpy(i32* %14, i32* %17, i32 32)
%19 = load i32, i32* %7
%20 = shl i32 %19, 3
%21 = getelementptr inbounds [32 x i32], [32 x i32]* %12, i64 0, i64 0
%22 = getelementptr inbounds i32, i32* %21, i64 0
%23 = load i32, i32* %22
%24 = xor i32 %23, %20
store i32 %24, i32* %22
%25 = load i32, i32* %6
%26 = shl i32 %25, 3
%27 = getelementptr inbounds [32 x i32], [32 x i32]* %12, i64 0, i64 0
%28 = getelementptr inbounds i32, i32* %27, i64 1
%29 = load i32, i32* %28
%30 = xor i32 %29, %26
store i32 %30, i32* %28
%31 = load [4 x i32]*, [4 x i32]** %9
%32 = getelementptr inbounds [4 x i32], [4 x i32]* %31, i64 0
%33 = getelementptr inbounds [4 x i32], [4 x i32]* %32, i64 0, i64 0
%34 = load i32, i32* %33
%35 = load [4 x i32]*, [4 x i32]** %9
%36 = getelementptr inbounds [4 x i32], [4 x i32]* %35, i64 4
%37 = getelementptr inbounds [4 x i32], [4 x i32]* %36, i64 0, i64 0
%38 = load i32, i32* %37
%39 = xor i32 %38, %34
store i32 %39, i32* %37
%40 = load [4 x i32]*, [4 x i32]** %9
%41 = getelementptr inbounds [4 x i32], [4 x i32]* %40, i64 0
%42 = getelementptr inbounds [4 x i32], [4 x i32]* %41, i64 0, i64 1
%43 = load i32, i32* %42
%44 = load [4 x i32]*, [4 x i32]** %9
%45 = getelementptr inbounds [4 x i32], [4 x i32]* %44, i64 4
%46 = getelementptr inbounds [4 x i32], [4 x i32]* %45, i64 0, i64 1
%47 = load i32, i32* %46
%48 = xor i32 %47, %43
store i32 %48, i32* %46
%49 = load [4 x i32]*, [4 x i32]** %9
%50 = getelementptr inbounds [4 x i32], [4 x i32]* %49, i64 0
%51 = getelementptr inbounds [4 x i32], [4 x i32]* %50, i64 0, i64 2
%52 = load i32, i32* %51
%53 = load [4 x i32]*, [4 x i32]** %9
%54 = getelementptr inbounds [4 x i32], [4 x i32]* %53, i64 4
%55 = getelementptr inbounds [4 x i32], [4 x i32]* %54, i64 0, i64 2
%56 = load i32, i32* %55
%57 = xor i32 %56, %52
store i32 %57, i32* %55
%58 = load [4 x i32]*, [4 x i32]** %9
%59 = getelementptr inbounds [4 x i32], [4 x i32]* %58, i64 0
%60 = getelementptr inbounds [4 x i32], [4 x i32]* %59, i64 0, i64 3
%61 = load i32, i32* %60
%62 = load [4 x i32]*, [4 x i32]** %9
%63 = getelementptr inbounds [4 x i32], [4 x i32]* %62, i64 4
%64 = getelementptr inbounds [4 x i32], [4 x i32]* %63, i64 0, i64 3
%65 = load i32, i32* %64
%66 = xor i32 %65, %61
store i32 %66, i32* %64
store i32 0, i32* %10
br label %67
67: ; preds = %75, %4
%68 = load i32, i32* %10
%69 = icmp slt i32 %68, 8
br i1 %69, label %70, label %78
70: ; preds = %67
%71 = getelementptr inbounds [32 x i32], [32 x i32]* %12, i64 0, i64 0
%72 = load [4 x i32]*, [4 x i32]** %9
%73 = bitcast [4 x i32]* %72 to i32**
%74 = call i32 @morus_stateupdate(i32* %71, i32** %73)
br label %75
75: ; preds = %70
%76 = load i32, i32* %10
%77 = add nsw i32 %76, 1
store i32 %77, i32* %10
br label %67
78: ; preds = %67
store i32 2, i32* %10
br label %79
79: ; preds = %106, %78
%80 = load i32, i32* %10
%81 = icmp slt i32 %80, 5
br i1 %81, label %82, label %109
82: ; preds = %79
store i32 0, i32* %11
br label %83
83: ; preds = %102, %82
%84 = load i32, i32* %11
%85 = icmp slt i32 %84, 4
br i1 %85, label %86, label %105
86: ; preds = %83
%87 = load [4 x i32]*, [4 x i32]** %9
%88 = load i32, i32* %10
%89 = sext i32 %88 to i64
%90 = getelementptr inbounds [4 x i32], [4 x i32]* %87, i64 %89
%91 = load i32, i32* %11
%92 = sext i32 %91 to i64
%93 = getelementptr inbounds [4 x i32], [4 x i32]* %90, i64 0, i64 %92
%94 = load i32, i32* %93
%95 = load [4 x i32]*, [4 x i32]** %9
%96 = getelementptr inbounds [4 x i32], [4 x i32]* %95, i64 1
%97 = load i32, i32* %11
%98 = sext i32 %97 to i64
%99 = getelementptr inbounds [4 x i32], [4 x i32]* %96, i64 0, i64 %98
%100 = load i32, i32* %99
%101 = xor i32 %100, %94
store i32 %101, i32* %99
br label %102
102: ; preds = %86
%103 = load i32, i32* %11
%104 = add nsw i32 %103, 1
store i32 %104, i32* %11
br label %83
105: ; preds = %83
br label %106
106: ; preds = %105
%107 = load i32, i32* %10
%108 = add nsw i32 %107, 1
store i32 %108, i32* %10
br label %79
109: ; preds = %79
store i32 0, i32* %10
br label %110
110: ; preds = %131, %109
%111 = load i32, i32* %10
%112 = icmp slt i32 %111, 16
br i1 %112, label %113, label %134
113: ; preds = %110
%114 = load i32*, i32** %8
%115 = load i32, i32* %6
%116 = load i32, i32* %10
%117 = add nsw i32 %115, %116
%118 = sext i32 %117 to i64
%119 = getelementptr inbounds i32, i32* %114, i64 %118
%120 = load i32, i32* %119
%121 = load [4 x i32]*, [4 x i32]** %9
%122 = getelementptr inbounds [4 x i32], [4 x i32]* %121, i64 1
%123 = getelementptr inbounds [4 x i32], [4 x i32]* %122, i64 0, i64 0
%124 = load i32, i32* %10
%125 = sext i32 %124 to i64
%126 = getelementptr inbounds i32, i32* %123, i64 %125
%127 = load i32, i32* %126
%128 = xor i32 %120, %127
%129 = load i32, i32* %13
%130 = or i32 %129, %128
store i32 %130, i32* %13
br label %131
131: ; preds = %113
%132 = load i32, i32* %10
%133 = add nsw i32 %132, 1
store i32 %133, i32* %10
br label %110
134: ; preds = %110
%135 = load i32, i32* %13
%136 = icmp eq i32 0, %135
br i1 %136, label %137, label %138
137: ; preds = %134
store i32 0, i32* %5
br label %139
138: ; preds = %134
store i32 -1, i32* %5
br label %139
139: ; preds = %138, %137
%140 = load i32, i32* %5
ret i32 %140
}

LLVM IR (-O2):
define i32 @morus_tag_verification(i32 %0, i32 %1, i32* nocapture %2, [4 x i32]* %3) {
%5 = alloca [32 x i32]
%6 = bitcast [32 x i32]* %5 to i8*
%7 = getelementptr inbounds [32 x i32], [32 x i32]* %5, i64 0, i64 0
%8 = getelementptr inbounds [4 x i32], [4 x i32]* %3, i64 3, i64 0
%9 = call i32 @memcpy(i32* %7, i32* %8, i32 32)
%10 = shl i32 %1, 3
%11 = load i32, i32* %7
%12 = xor i32 %11, %10
store i32 %12, i32* %7
%13 = shl i32 %0, 3
%14 = getelementptr inbounds [32 x i32], [32 x i32]* %5, i64 0, i64 1
%15 = load i32, i32* %14
%16 = xor i32 %15, %13
store i32 %16, i32* %14
%17 = getelementptr inbounds [4 x i32], [4 x i32]* %3, i64 4, i64 0
%18 = bitcast [4 x i32]* %3 to <4 x i32>*
%19 = load <4 x i32>, <4 x i32>* %18
%20 = bitcast i32* %17 to <4 x i32>*
%21 = load <4 x i32>, <4 x i32>* %20
%22 = xor <4 x i32> %21, %19
%23 = bitcast i32* %17 to <4 x i32>*
store <4 x i32> %22, <4 x i32>* %23
%24 = bitcast [4 x i32]* %3 to i32**
%25 = call i32 @morus_stateupdate(i32* %7, i32** %24)
%26 = call i32 @morus_stateupdate(i32* %7, i32** %24)
%27 = call i32 @morus_stateupdate(i32* %7, i32** %24)
%28 = call i32 @morus_stateupdate(i32* %7, i32** %24)
%29 = call i32 @morus_stateupdate(i32* %7, i32** %24)
%30 = call i32 @morus_stateupdate(i32* %7, i32** %24)
%31 = call i32 @morus_stateupdate(i32* %7, i32** %24)
%32 = call i32 @morus_stateupdate(i32* %7, i32** %24)
%33 = getelementptr inbounds [4 x i32], [4 x i32]* %3, i64 2, i64 0
%34 = getelementptr inbounds [4 x i32], [4 x i32]* %3, i64 1, i64 0
%35 = getelementptr inbounds [4 x i32], [4 x i32]* %3, i64 1, i64 1
%36 = getelementptr inbounds [4 x i32], [4 x i32]* %3, i64 1, i64 2
%37 = bitcast i32* %33 to <4 x i32>*
%38 = load <4 x i32>, <4 x i32>* %37
%39 = getelementptr inbounds [4 x i32], [4 x i32]* %3, i64 1, i64 3
%40 = bitcast i32* %34 to <4 x i32>*
%41 = load <4 x i32>, <4 x i32>* %40
%42 = xor <4 x i32> %41, %38
%43 = bitcast i32* %8 to <8 x i32>*
%44 = load <8 x i32>, <8 x i32>* %43
%45 = shufflevector <8 x i32> %44, <8 x i32> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
%46 = xor <4 x i32> %42, %45
%47 = shufflevector <8 x i32> %44, <8 x i32> undef, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
%48 = xor <4 x i32> %46, %47
%49 = extractelement <4 x i32> %48, i64 0
store i32 %49, i32* %34
%50 = extractelement <4 x i32> %48, i64 1
store i32 %50, i32* %35
%51 = extractelement <4 x i32> %48, i64 2
store i32 %51, i32* %36
%52 = extractelement <4 x i32> %48, i64 3
store i32 %52, i32* %39
%53 = sext i32 %0 to i64
%54 = getelementptr inbounds i32, i32* %2, i64 %53
%55 = bitcast i32* %54 to <16 x i32>*
%56 = load <16 x i32>, <16 x i32>* %55
%57 = shufflevector <4 x i32> %48, <4 x i32> %38, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
%58 = shufflevector <8 x i32> %44, <8 x i32> poison, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
%59 = shufflevector <16 x i32> %57, <16 x i32> %58, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 16, i32 17, i32 18, i32 19, i32 20, i32 21, i32 22, i32 23>
%60 = xor <16 x i32> %59, %56
%61 = call i32 @llvm.vector.reduce.or.v16i32(<16 x i32> %60)
%62 = icmp ne i32 %61, 0
%63 = sext i1 %62 to i32
ret i32 %63
}