// File: /workspace/github_c_makefile_star2_O2/mjosaarinen[P]brutus/crypto_aead/primatesv1ape80/ref/encrypt.cpp
// 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
)
{
	/*
    ... generating a plaintext m[0],m[1],...,m[*mlen-1]
    ... and secret message number nsec[0],nsec[1],...
    ... from a ciphertext c[0],c[1],...,c[clen-1]
    ... and associated data ad[0],ad[1],...,ad[adlen-1]
    ... and public message number npub[0],npub[1],...
    ... and secret key k[0],k[1],...
    ...
	*/
	unsigned char V[StateSize]; //the state represented in Elements
	//Temp variables represented as elements
	unsigned char key[KeySizeElements];
	unsigned char nonce[NonceSizeElements];
	unsigned char tag[TagSizeElements];
	unsigned char data[RateSizeElements];
	unsigned char cipher[RateSizeElements];
	unsigned char IV[StateSize]; //temp state represented in Elements
	
	if((clen<(TagSizeBytes+RateSizeBytes))&&(clen!=TagSizeBytes)) return -1; //invalid ciphertext
   
	//a temporary array for message
	unsigned char *mT = (unsigned char*) malloc(clen-TagSizeBytes);
    if (mT == NULL) return -2; // memory allocation failure
	
	Bytes2Element(key,k,0,KeySizeElements); //representing k as elements
	Bytes2Element(nonce,npub,0,NonceSizeElements); //representing npub as elements

	// IV <-- O||K
	InitializeState(IV,key);
	// Treating the nonce as the first part of the associated data
	for(int i=0; i<(NonceSizeElements/RateSizeElements); i++)
	{
		// IV <-- p_1 (N[i]^IV_r || IV_c)
		for(int j=0; j<RateSizeElements; j++)
			IV[j]^=nonce[RateSizeElements*i+j];
		p_1(IV);
	}
	if(adlen!=0)
	{ 
		// for i=1 to u-1 (except the last block which needs padding)
		if(adlen>RateSizeBytes)
		{ 
			for(unsigned long long i=0; i<adlen-RateSizeBytes; i=i+RateSizeBytes)
			{
				Bytes2Element(data,ad,i,RateSizeElements); // representing a block of ad as elements
				// IV <-- p_1 (A[i]^IV_r || IV_c)
				for(int j=0; j<RateSizeElements; j++)
					IV[j]^=data[j];
				p_1(IV);
			}
		}
		// IV <-- A[u]^IV_r || IV_c
		int l = adlen%RateSizeBytes;
		if(l==0){ //do padding with spill over			
			Bytes2Element(data,ad,adlen-RateSizeBytes,RateSizeElements); // representing last block of ad as elements
			for(int i=0; i<RateSizeElements; i++)
				IV[i]^=data[i];
			IV[RateSizeElements]^=16; //padding spills over to capacity
		}
		else{ //do standard padding
			unsigned char dataP[RateSizeBytes];
			for(int i=0; i< l; i++)
				dataP[i]=ad[adlen-l+i];
			dataP[l]=128; //padding over bytes
			for(int i=l+1; i<RateSizeBytes; i++)
				dataP[i]=0;
			Bytes2Element(data,dataP,0,RateSizeElements); // representing last padded block of ad as elements
			for(int i=0; i<RateSizeElements; i++)
				IV[i]^=data[i];
		}
		// IV <-- p_1(IV)
		p_1(IV);	
	}
	// IV <-- IV ^ (0..01)
	IV[StateSize-1]^=1;
	unsigned char tagT[TagSizeBytes];
	if(clen==TagSizeBytes){ //ciphertext length and hence the message length is 0
		*mlen=0;
		//do standard padding
		unsigned char dataP[RateSizeBytes];
		dataP[0]=128; //padding over bytes
		for(int i=1; i<RateSizeBytes; i++)
			dataP[i]=0;
		Bytes2Element(data,dataP,0,RateSizeElements);  // representing last block of m as elements
		// V <-- p_1 (M[1]^V_r || V_c)
		for(int i=0; i<RateSizeElements; i++)
			IV[i]^=data[i];
		p_1(IV);
		// T <-- (V_c)_c/2 ^ K 
		for(int i=0; i<TagSizeElements; i++)
			tag[i]=IV[RateSizeElements+i]^key[i]; 
		Element2Bytes(tagT,tag,0,TagSizeBytes) ;

		unsigned char cor=0;
		for(int i=0; i<TagSizeBytes; i++) //check if tags match
			cor = cor || (tagT[i]^c[i]);
		free(mT);
		if(cor==0) return 0;
		else return -1;
	}
	else{
		// V <-- p_1_inv(C[w] || K^T)
		Bytes2Element(cipher,c,clen-(TagSizeBytes+RateSizeBytes),RateSizeElements);
		Bytes2Element(tag,c,clen-(TagSizeBytes),TagSizeElements);
		for(int i=0; i<RateSizeElements; i++)
			V[i]=cipher[i];
		for(int i=0; i<CapacitySize; i++)
			V[RateSizeElements+i]=key[i]^tag[i];
		p_1_inv(V);
		
		if(clen==(TagSizeBytes+RateSizeBytes)){ //ciphertext is one block only hence plaintext length is less then or equal to RateSize
			// V <-- V ^ IV
			for(int i=0; i<StateSize; i++)
				V[i] ^= IV[i]; 
			unsigned char cor=0;
			for(int i=RateSizeElements+1; i<StateSize; i++) //check if IV_c matches with V_c
				cor = cor || V[i];
			cor = cor || (!((V[RateSizeElements]==0) || (V[RateSizeElements]==16)));
			if (cor==0)
			{
				for(int i=0; i<RateSizeElements; i++)
					data[i]=V[i];
				Element2Bytes(mT,data,0,RateSizeBytes); //representing m as bytes
				if(V[RateSizeElements]==16) *mlen=(unsigned long long) RateSizeBytes;
				else{ 
					unsigned char match=0;
					for(int i=0; i<RateSizeBytes; i++) {
						match |= (mT[i]==128);
					}
					if(match==0) { free(mT); return -1; }
					for(int i=RateSizeBytes-1; i>=0; i--)
						if(mT[i]==128) { *mlen=(unsigned long long) i; break;}
				}
				for(unsigned long long i=0; i<*mlen; i++)
					m[i]=mT[i];
				free(mT);
				return 0;
			}
			else { free(mT); return -1; }
		}
		else{
			*mlen=clen-TagSizeBytes;
			//for i=w (tha last block)
			int l = clen%RateSizeBytes;
			if (l==0){
				//M[w] <-- |V_r|_l^C[w-1]
				Bytes2Element(cipher,c,clen-(TagSizeBytes+2*RateSizeBytes),RateSizeElements);
				for(int i=0; i<RateSizeElements; i++)
					data[i]=V[i]^cipher[i];
				Element2Bytes(mT,data,clen-(TagSizeBytes+RateSizeBytes),RateSizeBytes); //representing last block m as bytes
				//V <-- V^M[w]10*
				for(int i=0; i<(RateSizeElements); i++)
					V[i]^=data[i];
				V[RateSizeElements]^=16;
			}
			else{
				//M[w] <-- |V_r|_l^C[w-1]
				unsigned char cipherP[RateSizeBytes];
				unsigned char mtmp[RateSizeBytes];
				Element2Bytes(cipherP,V,0,RateSizeBytes); //representing last block m as bytes
				for(int i=0; i<l; i++){
					mT[(clen-TagSizeBytes)-l+i]=cipherP[i]^c[clen-(TagSizeBytes+RateSizeBytes+l)+i];
					mtmp[i]=mT[(clen-TagSizeBytes)-l+i];
				}
				mtmp[l]=128;
				for(int i=l+1; i<RateSizeBytes; i++)
					mtmp[i]=0;
				Bytes2Element(data,mtmp,0,RateSizeElements);
				//V <-- V^M[w]10*
				for(int i=0; i<RateSizeElements; i++)
					V[i]^=data[i];	
			}
			l = (l==0) ? RateSizeBytes : l;
			//for i=w-1 to 2
			for(unsigned long long i=((clen-TagSizeBytes)-l); i>RateSizeBytes; i=i-5){
				// V <-- p_1_inv(V)
				p_1_inv(V);
				// M[i] <-- C[i-1]^V_r
				unsigned char mtmp[RateSizeElements];
				Bytes2Element(data,c,i-2*RateSizeBytes,RateSizeElements);
				for(int j=0; j<RateSizeElements; j++)
					mtmp[j]=data[j]^V[j];
				Element2Bytes(mT,mtmp,i-RateSizeBytes,RateSizeBytes); //representing last block m as bytes
				
				// V <-- C[i-1] || V_c
				for(int j=0; j<RateSizeElements; j++)
					V[j]=data[j];
			}
			//for i=1
			// V <-- p_1_inv(V)
			p_1_inv(V);
			// M[i] <-- C[i-1]^V_r
			for(int i=0; i<RateSizeElements; i++)
				data[i]=IV[i]^V[i];
			Element2Bytes(mT,data,0,RateSizeBytes); //representing last block m as bytes
			 //check if IV_c matches with V_c
			for(int j=0; j<RateSizeElements; j++)
				V[j]^=data[j];
			unsigned char cor=0;
			for(int i=RateSizeElements; i<StateSize; i++) 
				cor = cor || (V[i]^IV[i]);
			if(cor==0) {
				for(unsigned long long i=0; i<*mlen; i++)
					m[i]=mT[i];
			}
			free(mT);
			if (cor == 0) return 0;
			else return -1;
		}
	}
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xf8, %rsp
movq %rcx, 0x10(%rsp)
cmpq $0x19, %r8
setb %al
cmpq $0x14, %r8
setne %cl
testb %cl, %al
je 0x2691
pushq $-0x1
jmp 0x27ee
movq %r9, %r15
movq %r8, %r14
movq %rsi, %rbx
movq %rdi, 0x90(%rsp)
leaq -0x14(%r8), %rdi
movq %rdi, 0x18(%rsp)
callq 0x2090
testq %rax, %rax
je 0x27ec
movq %rax, %r13
movq %r14, 0x50(%rsp)
movq %rbx, 0x98(%rsp)
movq 0x140(%rsp), %rsi
movq 0x138(%rsp), %r12
xorl %r14d, %r14d
leaq 0xc0(%rsp), %rbp
pushq $0x20
popq %rcx
movq %rbp, %rdi
xorl %edx, %edx
callq 0x2190
leaq 0xe0(%rsp), %rbx
pushq $0x10
popq %rcx
movq %rbx, %rdi
movq %r12, %rsi
xorl %edx, %edx
callq 0x2190
leaq 0x60(%rsp), %r12
movq %r12, %rdi
movq %rbp, %rsi
callq 0x20a0
cmpq $0x2, %r14
je 0x2744
xorl %eax, %eax
cmpq $0x8, %rax
je 0x2733
movb (%rbx,%rax), %cl
xorb %cl, 0x60(%rsp,%rax)
incq %rax
jmp 0x2721
movq %r12, %rdi
callq 0x2060
incq %r14
addq $0x8, %rbx
jmp 0x2719
pushq $0x5
popq %r12
movq 0x130(%rsp), %rax
testq %rax, %rax
movq 0x50(%rsp), %rbp
je 0x288f
movq %r13, 0x88(%rsp)
cmpq $0x6, %rax
jb 0x27b6
leaq -0x5(%rax), %r13
xorl %ebx, %ebx
movq %rsp, %r12
pushq $0x8
popq %r14
leaq 0x60(%rsp), %rbp
cmpq %r13, %rbx
jae 0x27b6
movq %r12, %rdi
movq %r15, %rsi
movq %rbx, %rdx
movl %r14d, %ecx
callq 0x2190
xorl %eax, %eax
cmpq $0x8, %rax
je 0x27a8
movb (%rsp,%rax), %cl
xorb %cl, 0x60(%rsp,%rax)
incq %rax
jmp 0x2796
movq %rbp, %rdi
callq 0x2060
addq $0x5, %rbx
jmp 0x277e
movq 0x130(%rsp), %r8
movq %r8, %rax
xorl %edx, %edx
pushq $0x5
popq %r12
divq %r12
testq %rdx, %rdx
je 0x284a
movq %r8, %rax
subq %rdx, %rax
addq %rax, %r15
xorl %eax, %eax
cmpq %rax, %rdx
je 0x27f4
movb (%r15,%rax), %cl
movb %cl, 0x20(%rsp,%rax)
incq %rax
jmp 0x27da
pushq $-0x2
popq %rax
jmp 0x2c76
movq %r8, %rax
xorl %edx, %edx
divq %r12
leaq (%rax,%rax,4), %rax
notq %rax
addq %r8, %rax
movb $-0x80, %cl
movb %cl, 0x21(%rsp,%rax)
incq %rax
xorl %ecx, %ecx
cmpq $0x4, %rax
jb 0x2808
xorl %ebx, %ebx
movq %rsp, %rdi
leaq 0x20(%rsp), %rsi
pushq $0x8
popq %rcx
xorl %edx, %edx
callq 0x2190
movq 0x88(%rsp), %r13
movq 0x50(%rsp), %rbp
cmpq $0x8, %rbx
je 0x2885
movb (%rsp,%rbx), %al
xorb %al, 0x60(%rsp,%rbx)
incq %rbx
jmp 0x2838
addq $-0x5, %r8
movq %rsp, %rdi
pushq $0x8
popq %rcx
movq %r15, %rsi
movq %r8, %rdx
callq 0x2190
xorl %eax, %eax
movq 0x88(%rsp), %r13
movq 0x50(%rsp), %rbp
cmpq $0x8, %rax
je 0x2880
movb (%rsp,%rax), %cl
xorb %cl, 0x60(%rsp,%rax)
incq %rax
jmp 0x286e
xorb $0x10, 0x68(%rsp)
leaq 0x60(%rsp), %rdi
callq 0x2060
xorb $0x1, 0x87(%rsp)
cmpq $0x14, %rbp
movq 0x98(%rsp), %rbx
jne 0x28c1
andq $0x0, (%rbx)
movb $-0x80, 0x8(%rsp)
pushq $0x1
popq %rax
cmpq $0x5, %rax
je 0x290a
movb $0x0, 0x8(%rsp,%rax)
incq %rax
jmp 0x28b1
leaq -0x19(%rbp), %r14
leaq 0x8(%rsp), %rdi
pushq $0x8
popq %rcx
movq 0x10(%rsp), %r15
movq %r15, %rsi
movq %r14, %rdx
callq 0x2190
leaq 0xa0(%rsp), %rdi
pushq $0x20
popq %rcx
movq %r15, %rsi
movq 0x18(%rsp), %rdx
callq 0x2190
xorl %eax, %eax
cmpq $0x8, %rax
je 0x2930
movb 0x8(%rsp,%rax), %cl
movb %cl, 0x20(%rsp,%rax)
incq %rax
jmp 0x28f7
xorl %ebx, %ebx
movq %rsp, %rdi
leaq 0x8(%rsp), %rsi
pushq $0x8
popq %rcx
xorl %edx, %edx
callq 0x2190
cmpq $0x8, %rbx
je 0x294f
movb (%rsp,%rbx), %al
xorb %al, 0x60(%rsp,%rbx)
incq %rbx
jmp 0x291e
xorl %eax, %eax
cmpq $0x20, %rax
je 0x2978
movb 0xa0(%rsp,%rax), %cl
xorb 0xc0(%rsp,%rax), %cl
movb %cl, 0x28(%rsp,%rax)
incq %rax
jmp 0x2932
leaq 0x60(%rsp), %rdi
callq 0x2060
xorl %eax, %eax
cmpq $0x20, %rax
je 0x29a1
movb 0xc0(%rsp,%rax), %cl
xorb 0x68(%rsp,%rax), %cl
movb %cl, 0xa0(%rsp,%rax)
incq %rax
jmp 0x295b
leaq 0x20(%rsp), %rdi
callq 0x2100
cmpq $0x19, %rbp
jne 0x29f3
xorl %eax, %eax
cmpq $0x28, %rax
je 0x2a58
movb 0x60(%rsp,%rax), %cl
xorb %cl, 0x20(%rsp,%rax)
incq %rax
jmp 0x298a
xorl %ebx, %ebx
leaq 0x20(%rsp), %rdi
leaq 0xa0(%rsp), %rsi
pushq $0x14
popq %rcx
xorl %edx, %edx
callq 0x2080
xorl %r14d, %r14d
movq 0x10(%rsp), %rcx
cmpq $0x14, %rbx
je 0x29e1
movb $0x1, %al
testb %r14b, %r14b
jne 0x29d9
movb 0x20(%rsp,%rbx), %al
cmpb (%rcx,%rbx), %al
setne %al
incq %rbx
movl %eax, %r14d
jmp 0x29c2
movq %r13, %rdi
callq 0x20d0
xorl %eax, %eax
negb %r14b
jmp 0x2c74
movq %r12, %rcx
movq 0x18(%rsp), %r12
movq %r12, (%rbx)
movq %rbp, %rax
xorl %edx, %edx
divq %rcx
testq %rdx, %rdx
je 0x2b14
movq %rdx, %r15
xorl %ebx, %ebx
leaq 0x58(%rsp), %rdi
leaq 0x20(%rsp), %rsi
pushq $0x5
popq %rcx
xorl %edx, %edx
callq 0x2080
subq %r15, %r14
addq 0x10(%rsp), %r14
movq %r12, %rcx
subq %r15, %rcx
movq %r13, %rax
addq %rcx, %rax
pushq $0x5
popq %rsi
cmpq %rbx, %r15
je 0x2a99
movb (%r14,%rbx), %cl
xorb 0x58(%rsp,%rbx), %cl
movb %cl, (%rax,%rbx)
movb %cl, 0x4b(%rsp,%rbx)
incq %rbx
jmp 0x2a3f
pushq $-0x1f
popq %rax
xorl %ecx, %ecx
testq %rax, %rax
je 0x2a77
movb $0x1, %dl
testb %cl, %cl
jne 0x2a70
cmpb $0x0, 0x48(%rsp,%rax)
setne %dl
incq %rax
movl %edx, %ecx
jmp 0x2a5d
movb 0x28(%rsp), %al
andb $-0x11, %al
orb %al, %cl
jne 0x2cef
xorl %eax, %eax
cmpq $0x8, %rax
je 0x2af1
movb 0x20(%rsp,%rax), %cl
movb %cl, (%rsp,%rax)
incq %rax
jmp 0x2a87
movq %rbp, %rcx
movq %r13, %rbp
movq %rcx, %rax
xorl %edx, %edx
divq %rsi
leaq (%rax,%rax,4), %rax
notq %rax
addq %rcx, %rax
movb $-0x80, %cl
movb %cl, 0x4c(%rsp,%rax)
incq %rax
xorl %ecx, %ecx
cmpq $0x4, %rax
jb 0x2ab3
xorl %ebx, %ebx
movq %rsp, %rdi
leaq 0x4b(%rsp), %rsi
pushq $0x8
popq %rcx
xorl %edx, %edx
callq 0x2190
movq 0x18(%rsp), %r13
cmpq $0x8, %rbx
je 0x2b7b
movb (%rsp,%rbx), %al
xorb %al, 0x20(%rsp,%rbx)
incq %rbx
jmp 0x2adb
movq %rsp, %rsi
pushq $0x5
popq %rcx
movq %r13, %rdi
xorl %edx, %edx
callq 0x2080
cmpb $0x10, 0x28(%rsp)
jne 0x2c9b
pushq $0x5
popq %rdx
jmp 0x2cd0
addq $-0x1e, %rbp
leaq 0x8(%rsp), %rdi
pushq $0x8
popq %rcx
movq 0x10(%rsp), %rsi
movq %rbp, %rdx
callq 0x2190
xorl %eax, %eax
pushq $0x5
popq %r15
cmpq $0x8, %rax
je 0x2b49
movb 0x8(%rsp,%rax), %cl
xorb 0x20(%rsp,%rax), %cl
movb %cl, (%rsp,%rax)
incq %rax
jmp 0x2b33
movq %rsp, %rsi
pushq $0x5
popq %rcx
movq %r13, %rbp
movq %r13, %rdi
movq %r14, %rdx
callq 0x2080
xorl %eax, %eax
movq 0x18(%rsp), %r13
cmpq $0x8, %rax
je 0x2b76
movb (%rsp,%rax), %cl
xorb %cl, 0x20(%rsp,%rax)
incq %rax
jmp 0x2b64
xorb $0x10, 0x28(%rsp)
subq %r15, %r13
leaq 0x20(%rsp), %r14
pushq $0x8
popq %r15
leaq 0x58(%rsp), %rbx
pushq $0x5
popq %r12
movq %r14, %rdi
callq 0x2100
cmpq $0x5, %r13
jbe 0x2bf6
leaq -0xa(%r13), %rdx
movq %rsp, %rdi
movq 0x10(%rsp), %rsi
movl %r15d, %ecx
callq 0x2190
xorl %eax, %eax
cmpq $0x8, %rax
je 0x2bca
movb 0x20(%rsp,%rax), %cl
xorb (%rsp,%rax), %cl
movb %cl, 0x58(%rsp,%rax)
incq %rax
jmp 0x2bb4
movq %r13, %rdx
addq $-0x5, %rdx
movq %rbp, %rdi
movq %rbx, %rsi
movq %rdx, %r13
movl %r12d, %ecx
callq 0x2080
xorl %eax, %eax
cmpq $0x8, %rax
je 0x2b90
movb (%rsp,%rax), %cl
movb %cl, 0x20(%rsp,%rax)
incq %rax
jmp 0x2be4
xorl %eax, %eax
movq 0x98(%rsp), %r14
cmpq $0x8, %rax
je 0x2c16
movb 0x20(%rsp,%rax), %cl
xorb 0x60(%rsp,%rax), %cl
movb %cl, (%rsp,%rax)
incq %rax
jmp 0x2c00
xorl %ebx, %ebx
movq %rsp, %rsi
pushq $0x5
popq %rcx
movq %rbp, %rdi
xorl %edx, %edx
callq 0x2080
movq 0x90(%rsp), %rdx
cmpq $0x8, %rbx
je 0x2c42
movb (%rsp,%rbx), %al
xorb %al, 0x20(%rsp,%rbx)
incq %rbx
jmp 0x2c30
xorl %eax, %eax
xorl %ebx, %ebx
cmpq $0x20, %rax
je 0x2c64
movb $0x1, %cl
testb %bl, %bl
jne 0x2c5d
movb 0x28(%rsp,%rax), %cl
cmpb 0x68(%rsp,%rax), %cl
setne %cl
incq %rax
movl %ecx, %ebx
jmp 0x2c46
testb %bl, %bl
je 0x2c88
movq %rbp, %rdi
callq 0x20d0
xorl %eax, %eax
negb %bl
sbbl %eax, %eax
addq $0xf8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
xorl %eax, %eax
cmpq (%r14), %rax
jae 0x2c68
movb (%rbp,%rax), %cl
movb %cl, (%rdx,%rax)
incq %rax
jmp 0x2c8a
xorl %eax, %eax
xorl %edx, %edx
xorl %ecx, %ecx
cmpq $0x5, %rdx
je 0x2cb8
cmpb (%r13,%rdx), %al
seto %sil
orb %sil, %cl
incq %rdx
jmp 0x2ca1
testb %cl, %cl
je 0x2cef
pushq $0x4
popq %rax
xorl %ecx, %ecx
testl %eax, %eax
js 0x2cd3
movl %eax, %edx
decl %eax
cmpb (%r13,%rdx), %cl
jno 0x2cc1
movq %rdx, (%rbx)
xorl %eax, %eax
movq 0x90(%rsp), %rdx
cmpq (%rbx), %rax
jae 0x2cfc
movb (%r13,%rax), %cl
movb %cl, (%rdx,%rax)
incq %rax
jmp 0x2cdd
movq %r13, %rdi
callq 0x20d0
jmp 0x268a
movq %r13, %rdi
callq 0x20d0
xorl %eax, %eax
jmp 0x2c76
nop