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

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

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

	/* last byte is bit P. 
	   P=1 for partial last block, 
	   P=0 otherwise. */
	*clen = (mlen == 0 ? 16 : ((mlen+15)/16)*16) + 16 + 1; 
	partial = (*clen > mlen + 16 + 1);

	/* store bit P */
	c[*clen-1] = partial;

	/* 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 */

	while (remaining >= 16) { 
		xor_block(checksum, checksum, in);
		xor_block(block, in, Lup);
		AES_ENCRYPT(block, block, k);

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

		AES_ENCRYPT(block, block, k);
		xor_block(out, block, Ldown);

		if (remaining != 16) { /* don't double after full last block */
			gf128_mul2(Lup, Lup);
			gf128_mul2(Ldown, Ldown);
		}

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

	/* if last block is partial */
	if (partial) {
		/* padding */
		block_t padmsg = { 0 };
		unsigned long long i;

		for (i = 0; i < remaining; i++) {
			padmsg[i] = in[i];
		}
		padmsg[i] = 0x80; /* padding */

		gf128_mul7(Lup, Lup);

		xor_block(checksum, checksum, padmsg);
		xor_block(block, padmsg, Lup);
		AES_ENCRYPT(block, block, k);

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

		AES_ENCRYPT(block, block, k);
		xor_block(out, block, Ldown);

		out += 16;
	}

	/* 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(T, checksum, LL);

	copy_block(out, T);

	return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xa8, %rsp
movq %r9, %r14
movq %r8, 0x58(%rsp)
movq %rcx, %r15
movq %rdx, %r12
movq %rsi, %r13
movq %rdi, %rbx
movq 0xf0(%rsp), %rdx
vxorps %xmm0, %xmm0, %xmm0
leaq 0x30(%rsp), %rax
vmovaps %xmm0, (%rax)
leaq 0x70(%rsp), %rdi
vmovaps %xmm0, (%rdi)
movq %rdi, %rsi
callq 0x1140
leaq 0xf(%r15), %rax
andq $-0x10, %rax
addq $0x10, %rax
testq %r15, %r15
pushq $0x20
popq %rcx
cmovneq %rax, %rcx
leaq 0x1(%rcx), %rax
movq %rax, (%r13)
leaq 0x11(%r15), %rax
movq %rax, 0x60(%rsp)
cmpq %rax, %rcx
movq %rcx, 0x68(%rsp)
setae (%rbx,%rcx)
leaq 0x10(%r14), %r13
movq %r13, %rdi
callq 0x1070
movq %rax, %rbp
movq %rax, %rdi
movq 0x58(%rsp), %rsi
movq %r14, %rdx
callq 0x1120
movq 0xe8(%rsp), %rax
vmovups (%rax), %xmm0
vmovups %xmm0, (%rbp,%r14)
leaq 0x90(%rsp), %r14
movq %r14, %rdi
movq %rbp, %rsi
movq %r13, %rdx
leaq 0x70(%rsp), %r13
movq %r13, %rcx
movq 0xf0(%rsp), %r8
callq 0x1110
movq %rbp, %rdi
callq 0x1090
leaq 0x40(%rsp), %rdi
movq %r13, %rsi
movq %r14, %rdx
callq 0x1c11
leaq 0x20(%rsp), %rdi
movq %r13, %rsi
callq 0x1bdf
leaq 0x10(%rsp), %rdi
movq %r13, %rsi
callq 0x1c28
leaq 0x80(%rsp), %rbp
cmpq $0x10, %r15
jb 0x1e1f
leaq 0x30(%rsp), %rdi
movq %rdi, %rsi
movq %r12, %rdx
callq 0x1c11
movq %rbp, %rdi
movq %r12, %rsi
leaq 0x20(%rsp), %rdx
callq 0x1c11
movq %rbp, %rdi
movq %rbp, %rsi
movq 0xf0(%rsp), %r14
movq %r14, %rdx
callq 0x1140
movq %rbp, %rdi
movq %rbp, %rsi
leaq 0x40(%rsp), %r13
movq %r13, %rdx
callq 0x1c11
movq %r13, %rdi
movq %rbp, %rsi
callq 0x1a57
movq %rbp, %rdi
movq %rbp, %rsi
movq %r14, %rdx
callq 0x1140
movq %rbx, %rdi
movq %rbp, %rsi
leaq 0x10(%rsp), %rdx
callq 0x1c11
cmpq $0x10, %r15
je 0x1e0e
leaq 0x20(%rsp), %rdi
movq %rdi, %rsi
callq 0x1c28
leaq 0x10(%rsp), %rdi
movq %rdi, %rsi
callq 0x1c28
addq $0x10, %r12
addq $0x10, %rbx
addq $-0x10, %r15
jmp 0x1d72
movq 0x60(%rsp), %rax
cmpq %rax, 0x68(%rsp)
jb 0x1e47
vxorps %xmm0, %xmm0, %xmm0
vmovaps %xmm0, (%rsp)
xorl %eax, %eax
cmpq %r15, %rax
jae 0x1e54
movb (%r12,%rax), %cl
movb %cl, (%rsp,%rax)
incq %rax
jmp 0x1e36
movq 0xf0(%rsp), %r12
jmp 0x1ee7
movb $-0x80, (%rsp,%rax)
leaq 0x20(%rsp), %r15
movq %r15, %rdi
movq %r15, %rsi
callq 0x1f75
leaq 0x30(%rsp), %rdi
movq %rsp, %r12
movq %rdi, %rsi
movq %r12, %rdx
callq 0x1c11
leaq 0x80(%rsp), %r14
movq %r14, %rdi
movq %r12, %rsi
movq %r15, %rdx
callq 0x1c11
movq %r14, %rdi
movq %r14, %rsi
movq 0xf0(%rsp), %r12
movq %r12, %rdx
callq 0x1140
leaq 0x40(%rsp), %r15
movq %r14, %rdi
movq %r14, %rsi
movq %r15, %rdx
callq 0x1c11
movq %r15, %rdi
movq %r14, %rsi
callq 0x1a57
movq %r14, %rdi
movq %r14, %rsi
movq %r12, %rdx
callq 0x1140
leaq 0x10(%rsp), %rdx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x1c11
addq $0x10, %rbx
leaq 0x70(%rsp), %r14
leaq 0x20(%rsp), %rsi
movq %r14, %rdi
callq 0x1bdf
leaq 0x30(%rsp), %r15
movq %r15, %rdi
movq %r15, %rsi
movq %r14, %rdx
callq 0x1c11
movq %r15, %rdi
movq %r15, %rsi
movq %r12, %rdx
callq 0x1140
leaq 0x40(%rsp), %rdx
movq %r15, %rdi
movq %r15, %rsi
callq 0x1c11
movq %r15, %rdi
movq %r15, %rsi
movq %r12, %rdx
callq 0x1140
leaq 0x10(%rsp), %rsi
movq %r14, %rdi
callq 0x1f75
movq %rsp, %r12
movq %r12, %rdi
movq %r15, %rsi
movq %r14, %rdx
callq 0x1c11
movq %rbx, %rdi
movq %r12, %rsi
callq 0x1a57
xorl %eax, %eax
addq $0xa8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq