// File: /workspace/github_c_makefile_star2_O2/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
vxorps %xmm0, %xmm0, %xmm0
vmovups %ymm0, 0x10(%rsp)
movq %r8, %r14
movq %rcx, %r15
movq %rdx, %r12
movq %rsi, %r13
movq %rdi, 0x8(%rsp)
vmovups %ymm0, 0x30(%rsp)
xorl %eax, %eax
xorl %ecx, %ecx
xorl %edx, %edx
cmpq $0xc, %rdx
je 0x1511
cmpq $0x8, %rdx
shrxq %rcx, %r12, %rsi
cmovael %eax, %esi
movb %sil, 0x90(%rsp,%rdx)
incq %rdx
addq $0x8, %rcx
jmp 0x14ee
xorl %eax, %eax
xorl %ecx, %ecx
xorl %edx, %edx
cmpq $0xc, %rdx
je 0x153a
cmpq $0x8, %rdx
shrxq %rcx, %r14, %rsi
cmovael %eax, %esi
movb %sil, 0x9c(%rsp,%rdx)
incq %rdx
addq $0x8, %rcx
jmp 0x1517
movw $0x1414, 0xa8(%rsp)     # imm = 0x1414
xorl %eax, %eax
cmpq $0x14, %rax
je 0x155c
movb (%r9,%rax), %cl
movb %cl, 0xaa(%rsp,%rax)
incq %rax
jmp 0x1546
xorl %ebp, %ebp
leaq 0x50(%rsp), %rbx
xorl %eax, %eax
cmpq $0x2e, %rbp
je 0x15ab
movb 0x90(%rsp,%rbp), %cl
movl %eax, %edx
xorb %cl, 0x10(%rsp,%rdx)
incl %eax
cmpl $0x18, %eax
jne 0x15a6
leaq 0x10(%rsp), %rdi
movq %rbx, %rsi
vzeroupper
callq 0x1080
xorl %eax, %eax
cmpq $0x40, %rax
je 0x15a4
movb 0x50(%rsp,%rax), %cl
movb %cl, 0x10(%rsp,%rax)
incq %rax
jmp 0x1591
xorl %eax, %eax
incq %rbp
jmp 0x1565
xorl %ebx, %ebx
leaq 0x50(%rsp), %rbp
testq %r12, %r12
je 0x15f8
movb (%r13,%rbx), %cl
movl %eax, %edx
xorb %cl, 0x10(%rsp,%rdx)
incl %eax
incq %rbx
decq %r12
cmpl $0x18, %eax
jne 0x15b2
leaq 0x10(%rsp), %rdi
movq %rbp, %rsi
vzeroupper
callq 0x1080
xorl %eax, %eax
cmpq $0x40, %rax
je 0x15f4
movb 0x50(%rsp,%rax), %cl
movb %cl, 0x10(%rsp,%rax)
incq %rax
jmp 0x15e1
xorl %eax, %eax
jmp 0x15b2
xorl %ebx, %ebx
leaq 0x10(%rsp), %r12
leaq 0x50(%rsp), %r13
movl %eax, %ecx
testq %r14, %r14
je 0x1647
movb (%r15,%rbx), %dl
xorb %dl, 0x10(%rsp,%rcx)
incl %eax
incq %rbx
decq %r14
cmpl $0x18, %eax
jne 0x1604
movq %r12, %rdi
movq %r13, %rsi
vzeroupper
callq 0x1080
xorl %eax, %eax
cmpq $0x40, %rax
je 0x1643
movb 0x50(%rsp,%rax), %cl
movb %cl, 0x10(%rsp,%rax)
incq %rax
jmp 0x1630
xorl %eax, %eax
jmp 0x1604
xorb $0x1, 0x10(%rsp,%rcx)
cmpl $0x18, %eax
pushq $0x17
popq %rcx
cmovael %eax, %ecx
xorb $0x1, 0x10(%rsp,%rcx)
leaq 0x10(%rsp), %rdi
leaq 0x50(%rsp), %rsi
vzeroupper
callq 0x1080
xorl %eax, %eax
movq 0x8(%rsp), %rdx
cmpq $0x14, %rax
je 0x1685
movb 0x50(%rsp,%rax), %cl
movb %cl, (%rdx,%rax)
incq %rax
jmp 0x1673
xorl %eax, %eax
addq $0xc8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq