// File: /workspace/github_c_makefile_star2_O3/mjosaarinen[P]brutus/crypto_aead/paeq160/ref/encrypt.cpp
// Function: GenerateNonce(unsigned char*, unsigned char const*, unsigned long long, unsigned char const*, unsigned long long, unsigned char const*)
int GenerateNonce(unsigned char* output, const unsigned char *m,unsigned long long mlen,
       const unsigned char *ad,unsigned long long adlen,
       const unsigned char *k)
	   //Generate a nonce as a hash of the plaintext & AD by the AESQ-sponge function
{
	//Does not work for keys longer than 192 bits
	if(CRYPTO_KEYBYTES >24)
	{
		memset(output,0,CRYPTO_NPUBBYTES);
		return -1;
	}

	unsigned char State[64];
	unsigned char Buffer[CRYPTO_KEYBYTES+2+2*CRYPTO_LENGTH];
	unsigned char StateOut[64];
	memset(State,0,64);

	//Plaintext length
	for(unsigned i=0; i<CRYPTO_LENGTH; ++i)
		Buffer[i] = (i<sizeof(mlen))? (mlen>>(8*i))&0xff:0;

	//Associated data length
	for(unsigned i=0; i<CRYPTO_LENGTH; ++i)
		Buffer[i+CRYPTO_LENGTH] =  (i<sizeof(adlen))?(adlen>>(8*i))&0xff:0;

	//Key length
	Buffer[2*CRYPTO_LENGTH] = CRYPTO_KEYBYTES;

	//Nonce length
	Buffer[2*CRYPTO_LENGTH+1] = CRYPTO_NPUBBYTES;

	//Add key 
	for(unsigned i=0; i<CRYPTO_KEYBYTES; ++i)
		Buffer[i+CRYPTO_LENGTH*2+2] = k[i];

	unsigned state_index=0;
	unsigned long long message_index=0;
	unsigned long long ad_index=0;
	
	for(unsigned i=0; (i<CRYPTO_KEYBYTES+2+2*CRYPTO_LENGTH); ++i)//Feeding buffer
	{
		State[state_index] ^= Buffer[i];
		state_index++;
		if(state_index==64-2*CRYPTO_KEYBYTES)//end of state
		{
			FPerm(State,StateOut);
			state_index = 0;
			for(unsigned j=0; j<64; ++j) State[j] = StateOut[j];
		}
	}

	while(mlen>0)//Feeding plaintext
	{
		State[state_index] ^= m[message_index];
		state_index++;
		message_index++;
		mlen--;
		if(state_index==64-2*CRYPTO_KEYBYTES)//end of state
		{
			FPerm(State,StateOut);
			state_index = 0;
			for(unsigned j=0; j<64; ++j) State[j] = StateOut[j];
		}
	}
	while(adlen>0) //Filling AD
	{
		State[state_index] ^= ad[ad_index];
		state_index++;
		ad_index++;
		adlen--;
		if(state_index==64-2*CRYPTO_KEYBYTES)//end of state
		{
			FPerm(State,StateOut);
			state_index = 0;
			for(unsigned j=0; j<64; ++j) State[j] = StateOut[j];
		}
	}
	//end of data
	//Padding 10*1
	State[state_index] ^= 1;
	if(state_index==64-2*CRYPTO_KEYBYTES)//end of state
	{
		FPerm(State,StateOut);
		state_index = 0;
		for(unsigned j=0; j<64; ++j) State[j] = StateOut[j];
	}
	while(state_index <63-2*CRYPTO_KEYBYTES)
	{
		State[state_index] ^= 0;
		state_index++;
	}
	State[state_index] ^= 1;//state_index must be =63 - 2*CRYPTO_KEYBYTES
	FPerm(State,StateOut);
	for(unsigned j=0; j<CRYPTO_NPUBBYTES; ++j)
		output[j] = StateOut[j];

	return 0;

}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xc8, %rsp
movq %r8, %r14
movq %rcx, %r15
movq %rdx, %r12
movq %rsi, %r13
movq %rdi, 0x48(%rsp)
vxorps %xmm0, %xmm0, %xmm0
vmovups %ymm0, (%rsp)
vmovups %ymm0, 0x20(%rsp)
vpbroadcastq %rdx, %ymm0
vpmovsxbq 0x1dd0(%rip), %ymm1 # 0x3288
xorl %eax, %eax
vpbroadcastq 0x1d9d(%rip), %ymm2 # 0x3260
vpbroadcastq 0x1d9c(%rip), %ymm3 # 0x3268
vpbroadcastq 0x1d9b(%rip), %ymm4 # 0x3270
vpcmpltuq %ymm2, %ymm1, %k1
vpcmpltuq %ymm3, %ymm1, %k2
vpsllq $0x3, %ymm1, %ymm5
vpsrlvq %ymm5, %ymm0, %ymm5
vpmovqb %ymm5, %xmm5
vmovdqu8 %xmm5, %xmm5 {%k2} {z}
vmovdqu8 %xmm5, 0x50(%rsp,%rax) {%k1}
addq $0x4, %rax
vpaddq %ymm4, %ymm1, %ymm1
cmpq $0xc, %rax
jne 0x14d5
vpbroadcastq %r14, %ymm0
vpsrlvq 0x1c22(%rip), %ymm0, %ymm1 # 0x3140
vpmovqb %ymm1, 0x5c(%rsp)
vpsrlvq 0x1c31(%rip), %ymm0, %ymm0 # 0x3160
vpmovqb %ymm0, 0x60(%rsp)
movl $0x0, 0x64(%rsp)
movw $0x1414, 0x68(%rsp)     # imm = 0x1414
vmovups (%r9), %xmm0
vmovups %xmm0, 0x6a(%rsp)
movl 0x10(%r9), %eax
movl %eax, 0x7a(%rsp)
xorl %ebp, %ebp
leaq 0x80(%rsp), %rbx
xorl %eax, %eax
movb 0x50(%rsp,%rbp), %cl
movl %eax, %edx
xorb %cl, (%rsp,%rdx)
incl %eax
cmpl $0x18, %eax
jne 0x15a2
movq %rsp, %rdi
movq %rbx, %rsi
vzeroupper
callq 0x1080
vmovups 0x80(%rsp), %ymm0
vmovdqu 0xa0(%rsp), %ymm1
vmovdqu %ymm1, 0x20(%rsp)
vmovups %ymm0, (%rsp)
xorl %eax, %eax
incq %rbp
cmpq $0x2e, %rbp
jne 0x1565
testq %r12, %r12
je 0x1600
xorl %ebp, %ebp
leaq 0x80(%rsp), %rbx
movb (%r13,%rbp), %cl
movl %eax, %edx
xorb %cl, (%rsp,%rdx)
incl %eax
cmpl $0x18, %eax
jne 0x15f8
movq %rsp, %rdi
movq %rbx, %rsi
vzeroupper
callq 0x1080
vmovups 0x80(%rsp), %ymm0
vmovdqu 0xa0(%rsp), %ymm1
vmovdqu %ymm1, 0x20(%rsp)
vmovups %ymm0, (%rsp)
xorl %eax, %eax
incq %rbp
cmpq %rbp, %r12
jne 0x15ba
testq %r14, %r14
je 0x1658
xorl %r13d, %r13d
movq %rsp, %r12
leaq 0x80(%rsp), %rbx
movb (%r15,%r13), %cl
movl %eax, %edx
xorb %cl, (%rsp,%rdx)
incl %eax
cmpl $0x18, %eax
jne 0x1650
movq %r12, %rdi
movq %rbx, %rsi
vzeroupper
callq 0x1080
vmovups 0x80(%rsp), %ymm0
vmovdqu 0xa0(%rsp), %ymm1
vmovdqu %ymm1, 0x20(%rsp)
vmovups %ymm0, (%rsp)
xorl %eax, %eax
incq %r13
cmpq %r13, %r14
jne 0x1613
movl %eax, %ecx
xorb $0x1, (%rsp,%rcx)
cmpl $0x18, %eax
movl $0x17, %ecx
cmovael %eax, %ecx
xorb $0x1, (%rsp,%rcx)
movq %rsp, %rdi
leaq 0x80(%rsp), %rbx
movq %rbx, %rsi
vzeroupper
callq 0x1080
movl 0x10(%rbx), %eax
movq 0x48(%rsp), %rcx
movl %eax, 0x10(%rcx)
vmovaps (%rbx), %xmm0
vmovups %xmm0, (%rcx)
xorl %eax, %eax
addq $0xc8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq