// File: /workspace/github_c_makefile_star2_O1/mjosaarinen[P]brutus/crypto_aead/aescopav2/ref/encrypt.c
// Function: crypto_aead_decrypt
int crypto_aead_decrypt(
   unsigned char *m,unsigned long long *mlen,
   unsigned char *nsec,
   const unsigned char *c,unsigned long long clen,
   const unsigned char *ad,unsigned long long adlen,
   const unsigned char *npub,
   const unsigned char *k
   )
{
	unsigned char* macdata;
	const unsigned char* in = c;
	unsigned char* out = m;
	unsigned long long remaining;
	int partial;

	block_t V;
	block_t lastblock, newlastblock;
	block_t checksum = { 0 };
	block_t tag;
	block_t block, Lup, Ldown;
	block_t LL = { 0 };

	AES_ENCRYPT(LL, LL, k); /* LL = AES(LL) */

	/* verify that we have 16*x+1 bytes */
	if (clen % 16 != 1) {
		return -1;
	}

	/* Verify bit P */
	if (c[clen-1] > 1) {
		return -1;
	} else {
		partial = c[clen-1];
	}

	*mlen = clen - 16 - 1; /* provisional, will be adjusted later for incomplete last block */

	/* mac AD + nonce */
	macdata = malloc(adlen + 16);
	memcpy(macdata, ad, adlen);
	memcpy(macdata+adlen, npub, 16);
	mac(V, macdata, adlen+16, LL, k);
	free(macdata);

	xor_block(lastblock, LL, V); /* lastblock = LL ^ V; */

	gf128_mul3(Lup, LL); /* Lup = 3*LL */
	gf128_mul2(Ldown, LL); /* Ldown = 2*LL */

	remaining = *mlen;
	while (remaining > 16) {
		xor_block(block, in, Ldown);
		AES_DECRYPT(newlastblock, block, k);

		xor_block(block, newlastblock, lastblock);
		copy_block(lastblock, newlastblock);

		AES_DECRYPT(block, block, k);
		xor_block(out, block, Lup);
		xor_block(checksum, checksum, out);

		gf128_mul2(Lup, Lup);
		gf128_mul2(Ldown, Ldown);

		in += 16;
		out += 16;
		remaining -= 16;
	}

	/* verify correct length */
	if ((!partial && remaining != 16) || (partial && remaining == 0)) {
		return -1;
	}

	if (!partial) { /* full last block, normal processing */
		xor_block(block, in, Ldown);
		AES_DECRYPT(newlastblock, block, k);

		xor_block(block, newlastblock, lastblock);
		copy_block(lastblock, newlastblock);

		AES_DECRYPT(block, block, k);
		xor_block(out, block, Lup);
		xor_block(checksum, checksum, out);

		in += 16;
		out += 16;
		remaining -= 16;
	} else { /* last partial block remaining */
		int i, j;

		xor_block(block, in, Ldown);
		AES_DECRYPT(newlastblock, block, k);

		xor_block(block, newlastblock, lastblock);
		copy_block(lastblock, newlastblock);

		AES_DECRYPT(block, block, k);
		gf128_mul7(Lup, Lup);
		xor_block(newlastblock, block, Lup);
		xor_block(checksum, checksum, newlastblock);

		i = 15;
		while (i > 0 && newlastblock[i] == 0)
			--i;
		if ((newlastblock[i] != 0x80)) {
			return -1;
		}
		for (j = 0; j < i; j++) {
			out[j] = newlastblock[j];
		}

		/* adjust mlen */
		*mlen -= 16-i;

		in += remaining;
		out += i;
		remaining -= remaining;
	}

	/* compute tag */
	gf128_mul3(LL, Lup);
	xor_block(checksum, checksum, LL);
	AES_ENCRYPT(checksum, checksum, k);

	xor_block(checksum, checksum, lastblock);

	AES_ENCRYPT(checksum, checksum, k);
	gf128_mul7(LL, Ldown);
	xor_block(tag, checksum, LL);

	if (memcmp(tag, in, 16) == 0) {
		return 0;
	} else {
		return -1;
	}
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x178, %rsp            # imm = 0x178
movq %r9, 0x30(%rsp)
movq %r8, %r12
movq %rcx, %rbx
movq %rsi, 0x78(%rsp)
movq %rdi, %r15
movq 0x1c0(%rsp), %rdi
vxorps %xmm0, %xmm0, %xmm0
vmovaps %xmm0, 0x90(%rsp)
leaq 0xa0(%rsp), %r13
vmovaps %xmm0, (%r13)
leaq 0xc0(%rsp), %rbp
movq %rbp, %rsi
callq 0x10c0
leaq 0x50(%rsp), %r14
movq %r13, %rdi
movq %r14, %rsi
movq %rbp, %rdx
callq 0x10b0
vmovdqa (%r14), %xmm0
vmovdqa %xmm0, (%r13)
movl %r12d, %ecx
andl $0xf, %ecx
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
cmpl $0x1, %ecx
jne 0x26d1
movb -0x1(%rbx,%r12), %cl
cmpb $0x1, %cl
ja 0x26d1
movb %cl, 0xd(%rsp)
movq 0x1b8(%rsp), %rbp
movq 0x1b0(%rsp), %r14
addq $-0x11, %r12
movq 0x78(%rsp), %rax
movq %r12, (%rax)
leaq 0x10(%r14), %r12
movq %r12, %rdi
callq 0x1050
movq %rax, %r13
movq %rax, %rdi
movq 0x30(%rsp), %rsi
movq %r14, %rdx
callq 0x10e0
vmovups (%rbp), %xmm0
vmovups %xmm0, (%r13,%r14)
leaq 0xb0(%rsp), %rbp
leaq 0xa0(%rsp), %r14
movq %rbp, %rdi
movq %r13, %rsi
movq %r12, %rdx
movq %r14, %rcx
movq 0x1c0(%rsp), %r8
callq 0x10d0
movq %r13, %rdi
callq 0x1070
vmovaps (%r14), %xmm0
vmovaps %xmm0, 0x80(%rsp)
vxorps (%rbp), %xmm0, %xmm0
vmovaps %xmm0, 0x30(%rsp)
leaq 0x20(%rsp), %rdi
movq %r14, %rsi
callq 0x1d8f
movw $0x7fff, %ax            # imm = 0x7FFF
kmovd %eax, %k1
vmovdqu8 0x1(%r14), %xmm0 {%k1} {z}
vpsrlw $0x7, %xmm0, %xmm0
vmovdqa 0x80(%rsp), %xmm1
vpaddw %xmm1, %xmm1, %xmm1
vpternlogd $0xe4, 0x132b(%rip){1to4}, %xmm0, %xmm1 # 0x3830
movb (%r14), %cl
vmovdqu8 %xmm1, 0x10(%rsp) {%k1}
movb 0xf(%r14), %dl
addb %dl, %dl
movzbl %dl, %esi
xorb $-0x79, %dl
testb %cl, %cl
movzbl %dl, %ecx
cmovnsl %esi, %ecx
movb %cl, 0x1f(%rsp)
movq 0x78(%rsp), %rcx
movq (%rcx), %rbp
cmpq $0x11, %rbp
jb 0x26a3
leaq 0xc0(%rsp), %r13
leaq 0x40(%rsp), %r12
kmovd %eax, %k1
kmovw %k1, 0xe(%rsp)
movq 0x1c0(%rsp), %r14
vmovaps 0x10(%rsp), %xmm0
vxorps (%rbx), %xmm0, %xmm0
vmovaps %xmm0, 0x40(%rsp)
movq %r14, %rdi
movq %r13, %rsi
callq 0x10c0
movq %r12, %rdi
leaq 0x60(%rsp), %rsi
movq %r13, %rdx
callq 0x1040
vmovaps 0x60(%rsp), %xmm0
vmovaps %xmm0, 0x80(%rsp)
vxorps 0x30(%rsp), %xmm0, %xmm0
vmovaps %xmm0, 0x40(%rsp)
movq %r14, %rdi
movq %r13, %rsi
callq 0x10c0
movq %r12, %rdi
leaq 0x50(%rsp), %rsi
movq %r13, %rdx
callq 0x1040
vmovaps 0x50(%rsp), %xmm0
vmovaps %xmm0, 0x40(%rsp)
vxorps 0x20(%rsp), %xmm0, %xmm0
vmovups %xmm0, (%r15)
vxorps 0x90(%rsp), %xmm0, %xmm0
vmovaps %xmm0, 0x90(%rsp)
vmovdqa 0x20(%rsp), %xmm0
leaq 0x21(%rsp), %rax
kmovw 0xe(%rsp), %k1
vmovdqu8 (%rax), %xmm1 {%k1} {z}
vpsrlw $0x7, %xmm1, %xmm1
vpaddw %xmm0, %xmm0, %xmm0
vpbroadcastd 0x1224(%rip), %xmm2 # 0x3830
vpternlogd $0xe2, %xmm1, %xmm2, %xmm0
movb 0x20(%rsp), %al
vmovdqu8 %xmm0, 0x20(%rsp) {%k1}
movb 0x2f(%rsp), %cl
addb %cl, %cl
movzbl %cl, %edx
xorb $-0x79, %cl
testb %al, %al
movzbl %cl, %eax
cmovnsl %edx, %eax
movb %al, 0x2f(%rsp)
vmovdqa 0x10(%rsp), %xmm0
leaq 0x11(%rsp), %rax
vmovdqu8 (%rax), %xmm1 {%k1} {z}
vpsrlw $0x7, %xmm1, %xmm1
vpaddw %xmm0, %xmm0, %xmm0
vpternlogd $0xe2, %xmm1, %xmm2, %xmm0
movb 0x10(%rsp), %al
vmovdqu8 %xmm0, 0x10(%rsp) {%k1}
vmovdqa 0x80(%rsp), %xmm0
movb 0x1f(%rsp), %cl
addb %cl, %cl
movzbl %cl, %edx
xorb $-0x79, %cl
testb %al, %al
movzbl %cl, %eax
cmovnsl %edx, %eax
movb %al, 0x1f(%rsp)
addq $0x10, %rbx
addq $0x10, %r15
addq $-0x10, %rbp
vmovdqa %xmm0, 0x30(%rsp)
cmpq $0x10, %rbp
ja 0x2559
jmp 0x26a9
vmovdqa 0x30(%rsp), %xmm0
movb 0xd(%rsp), %dl
testb %dl, %dl
sete %al
cmpq $0x10, %rbp
setne %cl
testb %cl, %al
jne 0x26cc
testb %dl, %dl
setne %al
testq %rbp, %rbp
sete %cl
testb %cl, %al
je 0x26e3
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
addq $0x178, %rsp            # imm = 0x178
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
testb %dl, %dl
vmovdqa %xmm0, 0x80(%rsp)
je 0x282f
xorl %eax, %eax
movb 0x10(%rsp,%rax), %cl
xorb (%rbx,%rax), %cl
movb %cl, 0x40(%rsp,%rax)
incq %rax
cmpq $0x10, %rax
jne 0x26f6
leaq 0xc0(%rsp), %r12
movq 0x1c0(%rsp), %rdi
movq %r12, %rsi
callq 0x10c0
leaq 0x40(%rsp), %r14
leaq 0x50(%rsp), %r13
movq %r14, %rdi
movq %r13, %rsi
movq %r12, %rdx
callq 0x1040
vmovaps (%r13), %xmm0
vmovaps %xmm0, 0x60(%rsp)
vmovaps %xmm0, 0x30(%rsp)
vxorps 0x80(%rsp), %xmm0, %xmm0
vmovaps %xmm0, (%r14)
leaq 0xc0(%rsp), %r12
movq 0x1c0(%rsp), %rdi
movq %r12, %rsi
callq 0x10c0
leaq 0x50(%rsp), %r13
movq %r14, %rdi
movq %r13, %rsi
movq %r12, %rdx
callq 0x1040
vmovaps (%r13), %xmm0
vmovaps %xmm0, (%r14)
leaq 0x20(%rsp), %r12
movq %r12, %rdi
movq %r12, %rsi
callq 0x22de
vmovdqa (%r12), %xmm0
vpxor (%r14), %xmm0, %xmm0
vmovdqa %xmm0, 0x60(%rsp)
vpxor 0x90(%rsp), %xmm0, %xmm0
vmovdqa %xmm0, 0x90(%rsp)
movl $0x10, %ecx
leal -0x1(%rcx), %eax
cmpb $0x0, 0x60(%rsp,%rax)
jne 0x27db
decl %ecx
cmpl $0x1, %ecx
ja 0x27c8
xorl %eax, %eax
movslq %eax, %rcx
movb 0x60(%rsp,%rcx), %cl
cmpb $-0x80, %cl
jne 0x2815
testl %eax, %eax
jle 0x2800
movl %eax, %edx
xorl %esi, %esi
movb 0x60(%rsp,%rsi), %dil
movb %dil, (%r15,%rsi)
incq %rsi
cmpq %rsi, %rdx
jne 0x27ef
movl $0x10, %edx
subl %eax, %edx
movslq %edx, %rax
movq 0x78(%rsp), %rdx
subq %rax, (%rdx)
addq %rbp, %rbx
negb %cl
movq 0x1c0(%rsp), %rbp
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
jno 0x26d1
jmp 0x28fc
xorl %eax, %eax
movb 0x10(%rsp,%rax), %cl
xorb (%rbx,%rax), %cl
movb %cl, 0x40(%rsp,%rax)
incq %rax
cmpq $0x10, %rax
jne 0x2831
leaq 0xc0(%rsp), %r14
movq 0x1c0(%rsp), %rbp
movq %rbp, %rdi
movq %r14, %rsi
callq 0x10c0
leaq 0x40(%rsp), %r12
leaq 0x50(%rsp), %r13
movq %r12, %rdi
movq %r13, %rsi
movq %r14, %rdx
callq 0x1040
vmovaps (%r13), %xmm0
vmovaps %xmm0, 0x60(%rsp)
vmovaps %xmm0, 0x30(%rsp)
vxorps 0x80(%rsp), %xmm0, %xmm0
vmovaps %xmm0, (%r12)
leaq 0xc0(%rsp), %r14
movq %rbp, %rdi
movq %r14, %rsi
callq 0x10c0
leaq 0x50(%rsp), %r13
movq %r12, %rdi
movq %r13, %rsi
movq %r14, %rdx
callq 0x1040
vmovdqa (%r13), %xmm0
vmovdqa %xmm0, (%r12)
xorl %eax, %eax
movb 0x20(%rsp,%rax), %cl
xorb 0x40(%rsp,%rax), %cl
movb %cl, (%r15,%rax)
incq %rax
cmpq $0x10, %rax
jne 0x28cd
xorl %eax, %eax
movb (%r15,%rax), %cl
xorb %cl, 0x90(%rsp,%rax)
incq %rax
cmpq $0x10, %rax
jne 0x28e4
addq $0x10, %rbx
leaq 0xa0(%rsp), %r14
leaq 0x20(%rsp), %rsi
movq %r14, %rdi
callq 0x1d8f
vmovaps (%r14), %xmm0
leaq 0x90(%rsp), %r15
vxorps (%r15), %xmm0, %xmm0
vmovaps %xmm0, (%r15)
leaq 0xc0(%rsp), %r12
movq %rbp, %rdi
movq %r12, %rsi
callq 0x10c0
leaq 0x50(%rsp), %r13
movq %r15, %rdi
movq %r13, %rsi
movq %r12, %rdx
callq 0x10b0
vmovaps (%r13), %xmm0
vmovaps %xmm0, (%r15)
vxorps 0x30(%rsp), %xmm0, %xmm0
vmovaps %xmm0, (%r15)
leaq 0xc0(%rsp), %r12
movq %rbp, %rdi
movq %r12, %rsi
callq 0x10c0
leaq 0x50(%rsp), %r13
movq %r15, %rdi
movq %r13, %rsi
movq %r12, %rdx
callq 0x10b0
vmovaps (%r13), %xmm0
vmovaps %xmm0, (%r15)
leaq 0x10(%rsp), %rsi
movq %r14, %rdi
callq 0x22de
vmovdqa (%r14), %xmm0
vpxor (%r15), %xmm0, %xmm0
vmovdqa %xmm0, (%r12)
vpxor (%rbx), %xmm0, %xmm0
xorl %eax, %eax
vptest %xmm0, %xmm0
setne %al
negl %eax
jmp 0x26d1
nop