// File: /workspace/github_c_makefile_star2_O1/mjosaarinen[P]brutus/crypto_aead/paeq160/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
     )
     {
       Init();//Initializing GF(256) multiplication table for AES

		 if(mlen==NULL)
			 return -1;
		 if((clen==0) && (adlen==0))
		 {
			 *mlen=0;
			 return 0;
		 }

		 //Here we do decryption and/or authentication so we need a key and a plaintext pointer valid
		 if( (k==NULL) || (m==NULL) )
			 return -2;

		 //Minimum tag length verification
		 if (clen < CRYPTO_ABYTES)
			 return -1;

		 //Initializing constants
		unsigned char D0[2];
		D0[0] = CRYPTO_NPUBBYTES*8; //nonce length in bits
		D0[1] = CRYPTO_KEYBYTES*8; //key length in bits
		(*mlen)=0;
		 
		 //Initializing the last input to F
		 unsigned char BlockLastInput[64];  //Z1 - input to the last call of F
		 memset(BlockLastInput,0,64);
		 unsigned char Tag[64]; //Tag output
		 for(unsigned i=0; i<CRYPTO_KEYBYTES; ++i) //Key to the Z input
			BlockLastInput[64-CRYPTO_KEYBYTES+i] = k[i];
		 BlockLastInput[0] = D0[0]+6;
		 BlockLastInput[1] = D0[1];

		 unsigned long long decrypted_bytes=0;//Encrypted bytes counter
		 

		 //Encryption part
		 if(clen!=CRYPTO_ABYTES) //Ciphertext is more than just a tag
		 {
			 if(c==NULL)
				 return -3;
			 unsigned char BlockInput[64];  //V1 - input to the first layer call of F
			 unsigned char BlockMiddle[64];  //W1 - output of the first layer call of F
			 unsigned char BlockOutput[64];  //Y1 - output of the second layer call of F
			 unsigned long long mblock_counter=1;   //Message block counter
			 
			 while((clen>CRYPTO_ABYTES))
			 {
				 /* I. First layer */

				 //1. Domain-separation constant
				 BlockInput[1] = D0[1]; 
				 if(clen>= (CRYPTO_MBLOCK+CRYPTO_ABYTES))
					 BlockInput[0] = D0[0];
				 else //Last incomplete block
					 BlockInput[0] = D0[0]+1;

				 //2. Counter
				 for(unsigned i=0; i<CRYPTO_COUNTERBYTES; ++i)
				 {
					 BlockInput[i+2] = (i<sizeof(mblock_counter))?(mblock_counter>>(8*i))&0xff :0;//copying counter bytewise
				 }
				 
				 //3. Nonce
				 for(unsigned i=0; i<CRYPTO_NPUBBYTES; ++i) 
				 {
					 BlockInput[i+2+CRYPTO_COUNTERBYTES] = npub[i];
				 }

				 //4. Key
				 for(unsigned i=0; i<CRYPTO_KEYBYTES; ++i) 
				 {
					 BlockInput[i+2+CRYPTO_COUNTERBYTES+CRYPTO_NPUBBYTES] = k[i];
				 }	 

				 //5. Permutation call
				 FPerm(BlockInput, BlockMiddle); //First layer call to F

				 /* II. Encryption*/

				 if(clen>=CRYPTO_MBLOCK+CRYPTO_ABYTES)//Full block encryption
				 {
					 for(unsigned i=0; i<CRYPTO_MBLOCK; ++i)
					 {
						 m[decrypted_bytes] = BlockMiddle[i+2]^c[decrypted_bytes];
						 BlockMiddle[i+2] = c[decrypted_bytes];
						 decrypted_bytes++;
						 
					 }
					 BlockMiddle[1] =  D0[1];
					 BlockMiddle[0] = D0[0]+2;  //New Di constant

				 }

				 else //Last incomplete block
				 {
					 for(unsigned i=0; i<(unsigned)clen-CRYPTO_ABYTES; ++i)//Incomplete block Encryption
					 {
						  m[decrypted_bytes] = BlockMiddle[i+2]^c[decrypted_bytes];
						 BlockMiddle[i+2] = c[decrypted_bytes];
						 decrypted_bytes++;
					 }
					 for(unsigned i=(unsigned)clen-CRYPTO_ABYTES; i<CRYPTO_MBLOCK; ++i)
					 {
						 BlockMiddle[i+2] ^=  (unsigned char)(clen-CRYPTO_ABYTES);  //Extra Padding: extra bytes filled with the last block length in bytes
					 }

					 BlockMiddle[1] =  D0[1];
					 BlockMiddle[0] = D0[0]+3;  //New Di constant
				 }

				 //III. Second permutation call
				 //1. Call
				 FPerm(BlockMiddle, BlockOutput); //Second layer call to F
				 
				 //2. Buffer update
				 for(unsigned i=0; i<64-2-CRYPTO_KEYBYTES; ++i)//Adding the output to tag preparation buffer
				 {
					 BlockLastInput[i+2] ^= BlockOutput[i+2];
				 }


				 //Counters increment
				 mblock_counter++;
				 if(clen>=CRYPTO_MBLOCK+CRYPTO_ABYTES)
					 clen-=CRYPTO_MBLOCK;
				 
				 else 
				 	 clen=CRYPTO_ABYTES;
				 (*mlen) = decrypted_bytes;
			 }
		 }

		//Associated data part	  
		if(adlen!=0)
		{
			if(ad==NULL)
				return -4;

			unsigned char BlockInput[64];  //V1 - input to the first layer call of F
			 unsigned char BlockOutput[64];  //Y1 - output of the second layer call of F
			 unsigned long long adblock_counter=1;   //AD block counter
			 unsigned long long auth_bytes=0;

			while(adlen>0)
			{
				//1. Constant
				BlockInput[1] = D0[1];
				if(adlen>= CRYPTO_ADBLOCK)
					 BlockInput[0] = D0[0]+4;
				 else //Last incomplete block
					 BlockInput[0] = D0[0]+5;


				//2. Counter
				for(unsigned i=0; i<CRYPTO_KEYBYTES; ++i)
					BlockInput[i+2] = (i<sizeof(adblock_counter))? (adblock_counter>>(8*i))&0xff:0;//copying counter bytewise

				//3. AD block
				if(adlen >= CRYPTO_ADBLOCK) //Filling AD block
				{
					for(unsigned i=0; i<CRYPTO_ADBLOCK; ++i)
						BlockInput[i+2+CRYPTO_KEYBYTES] = ad[auth_bytes+i];
					
				}
				else //Last incomplete block
				{
					for(unsigned i=0; i<adlen; ++i)
						BlockInput[i+2+CRYPTO_KEYBYTES] = ad[auth_bytes+i];
					for(unsigned i=(unsigned)adlen; i<CRYPTO_ADBLOCK; ++i)
						BlockInput[i+2+CRYPTO_KEYBYTES] = (unsigned char)adlen;
				}

				//4. Key
				for(unsigned i=0; i<CRYPTO_KEYBYTES; ++i) 
				{
					 BlockInput[i+CRYPTO_ADBLOCK+CRYPTO_KEYBYTES+2] = k[i];
				}
				

				//5.Call to the F permutation

				FPerm(BlockInput,BlockOutput);//Call to the F permutation

				 for(unsigned i=0; i<64-2-CRYPTO_KEYBYTES; ++i)//Adding the output to Z
				 {
					 BlockLastInput[i+2] ^= BlockOutput[i+2];
				 }

				//Counters increment
				 adblock_counter++;
				 if(adlen>=CRYPTO_ADBLOCK)
				 {
					 auth_bytes += CRYPTO_ADBLOCK;
					 adlen-=CRYPTO_ADBLOCK;
				 }
				 else 
				 {
					 auth_bytes += adlen;
					 adlen=0;
				 }
			}
		}

		// Tag production 

		//1. Permutation call
		FPerm(BlockLastInput,Tag);
		//2. Key injection
		for(unsigned i=0; i<CRYPTO_KEYBYTES; ++i) 
		{
				Tag[64-CRYPTO_KEYBYTES+i] ^= k[i];
		}

		//3. Truncation
		if(clen!=CRYPTO_ABYTES)//Incorrect tag length
			return -1;

		for(unsigned i=0; i<CRYPTO_ABYTES; ++i)
		{
			if(c[(*mlen)+i] != Tag[i])
			{
				for(unsigned j=0; j< (*mlen); ++j)//Erasing decryption result
					m[j]=0;
				return -1; //Invalid
			}
		}
       return 0;
     }

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x128, %rsp            # imm = 0x128
movq %r9, 0x18(%rsp)
movq %r8, %rbp
movq %rcx, %r15
movq %rsi, %rbx
movq %rdi, %r14
callq 0x1050
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
testq %rbx, %rbx
je 0x2c44
movq 0x160(%rsp), %r13
movq %r13, %rax
orq %rbp, %rax
je 0x2c23
cmpq $0x0, 0x170(%rsp)
sete %al
testq %r14, %r14
sete %cl
orb %al, %cl
movl $0xfffffffe, %eax       # imm = 0xFFFFFFFE
jne 0x2c44
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
cmpq $0x14, %rbp
jb 0x2c44
movq $0x0, (%rbx)
vxorps %xmm0, %xmm0, %xmm0
vmovups %ymm0, 0xc0(%rsp)
vmovups %ymm0, 0xa0(%rsp)
movq 0x170(%rsp), %rax
vmovdqu (%rax), %xmm0
vmovdqu %xmm0, 0xcc(%rsp)
movl 0x10(%rax), %eax
movl %eax, 0xdc(%rsp)
movw $0xa0a6, 0xa0(%rsp)     # imm = 0xA0A6
je 0x28f8
testq %r15, %r15
je 0x2c35
movq %r15, 0x8(%rsp)
movq %r14, 0x10(%rsp)
movl $0x1, %r15d
leaq 0xa2(%rsp), %r14
xorl %r12d, %r12d
vpbroadcastq 0xc3b(%rip), %ymm5 # 0x3238
vpbroadcastq 0xc22(%rip), %ymm6 # 0x3228
movb $-0x60, 0x21(%rsp)
cmpq $0x3e, %rbp
setae %al
xorb $-0x5f, %al
movb %al, 0x20(%rsp)
vpbroadcastq %r15, %ymm0
movl $0x2, %eax
vpmovsxbq 0xc24(%rip), %ymm1 # 0x3250
vpmovsxbq 0xc1f(%rip), %ymm2 # 0x3254
vpcmpltuq %ymm5, %ymm1, %k0
vpcmpltuq %ymm5, %ymm2, %k1
kshiftlb $0x4, %k1, %k1
korb %k1, %k0, %k0
kmovb %k0, %k1
vpcmpltuq %ymm6, %ymm1, %k0
vpcmpltuq %ymm6, %ymm2, %k2
kshiftlb $0x4, %k2, %k2
korb %k2, %k0, %k2
vpsllq $0x3, %ymm1, %ymm3
vpsllq $0x3, %ymm2, %ymm4
vpsrlvq %ymm4, %ymm0, %ymm4
vpsrlvq %ymm3, %ymm0, %ymm3
vpmovqb %ymm3, %xmm3
vpmovqb %ymm4, %xmm4
vpunpckldq %xmm4, %xmm3, %xmm3 # xmm3 = xmm3[0],xmm4[0],xmm3[1],xmm4[1]
vmovdqu8 %xmm3, %xmm3 {%k2} {z}
vmovdqu8 %xmm3, 0x20(%rsp,%rax) {%k1}
vpaddq %ymm6, %ymm1, %ymm1
vpaddq %ymm6, %ymm2, %ymm2
addq $0x8, %rax
cmpq $0x1a, %rax
jne 0x2635
movq 0x168(%rsp), %rcx
movl 0x10(%rcx), %eax
leaq 0x38(%rsp), %rdx
movl %eax, 0x10(%rdx)
vmovups (%rcx), %xmm0
vmovups %xmm0, (%rdx)
movq 0x170(%rsp), %rcx
movl 0x10(%rcx), %eax
movl %eax, 0x24(%rdx)
vmovdqu (%rcx), %xmm0
vmovdqu %xmm0, 0x14(%rdx)
leaq 0x20(%rsp), %rdi
leaq 0x60(%rsp), %rsi
vzeroupper
callq 0x1080
cmpq $0x3e, %rbp
jb 0x2730
movq 0x8(%rsp), %rax
addq %r12, %rax
movq 0x10(%rsp), %rcx
leaq (%rcx,%r12), %rdx
xorl %ecx, %ecx
movb (%rax,%rcx), %sil
xorb 0x62(%rsp,%rcx), %sil
movb %sil, (%rdx,%rcx)
movb (%rax,%rcx), %sil
movb %sil, 0x62(%rsp,%rcx)
incq %rcx
cmpq $0x2a, %rcx
jne 0x270a
addq %rcx, %r12
movb $-0x5e, %cl
jmp 0x278c
movl %ebp, %edx
addl $-0x14, %edx
movl %edx, %eax
je 0x276d
movq 0x8(%rsp), %rcx
addq %r12, %rcx
movq 0x10(%rsp), %rsi
leaq (%rsi,%r12), %rdi
xorl %esi, %esi
movb (%rcx,%rsi), %r8b
xorb 0x62(%rsp,%rsi), %r8b
movb %r8b, (%rdi,%rsi)
movb (%rcx,%rsi), %r8b
movb %r8b, 0x62(%rsp,%rsi)
incq %rsi
cmpq %rsi, %rax
jne 0x274c
addq %rsi, %r12
movb $-0x5d, %cl
cmpl $0x29, %edx
ja 0x278c
leal -0x14(%rbp), %edx
incq %rax
movq %rax, %rsi
xorb %dl, 0x61(%rsp,%rax)
incq %rsi
cmpl $0x2a, %eax
movq %rsi, %rax
jne 0x277d
movb $-0x60, 0x61(%rsp)
movb %cl, 0x60(%rsp)
leaq 0x60(%rsp), %rdi
leaq 0xe0(%rsp), %rsi
callq 0x1080
xorl %eax, %eax
vpmovsxbq 0xaa6(%rip), %ymm8 # 0x3258
vpmovsxbq 0xaa1(%rip), %ymm9 # 0x325c
vpmovsxbq 0xa9c(%rip), %ymm10 # 0x3260
vpmovsxbq 0xa97(%rip), %ymm11 # 0x3264
vpmovsxbq 0xa92(%rip), %ymm12 # 0x3268
vpmovsxbq 0xa8d(%rip), %ymm13 # 0x326c
vpmovsxbq 0xa6c(%rip), %ymm14 # 0x3254
vpmovsxbq 0xa5f(%rip), %ymm15 # 0x3250
vpbroadcastq 0xa45(%rip), %ymm16 # 0x3240
vpbroadcastq %rax, %ymm0
vpor %ymm0, %ymm8, %ymm1
vpor %ymm0, %ymm9, %ymm2
vpor %ymm0, %ymm10, %ymm3
vpor %ymm0, %ymm11, %ymm4
vpor %ymm0, %ymm12, %ymm5
vpor %ymm0, %ymm13, %ymm6
vpor %ymm0, %ymm14, %ymm7
vpor %ymm0, %ymm15, %ymm0
vpcmpltuq %ymm16, %ymm0, %k0
vpcmpltuq %ymm16, %ymm7, %k1
kshiftlb $0x4, %k1, %k1
korb %k1, %k0, %k0
vpcmpltuq %ymm16, %ymm6, %k1
vpcmpltuq %ymm16, %ymm5, %k2
kshiftlb $0x4, %k2, %k2
korb %k2, %k1, %k1
kunpckbw %k0, %k1, %k0
vpcmpltuq %ymm16, %ymm4, %k1
vpcmpltuq %ymm16, %ymm3, %k2
kshiftlb $0x4, %k2, %k2
korb %k2, %k1, %k1
vpcmpltuq %ymm16, %ymm2, %k2
vpcmpltuq %ymm16, %ymm1, %k3
kshiftlb $0x4, %k3, %k3
korb %k3, %k2, %k2
kunpckbw %k1, %k2, %k1
kunpckwd %k0, %k1, %k1
vmovdqu8 0xe2(%rsp,%rax), %ymm0 {%k1} {z}
vmovdqu8 (%r14,%rax), %ymm1 {%k1} {z}
vpxor %ymm0, %ymm1, %ymm0
vmovdqu8 %ymm0, (%r14,%rax) {%k1}
addq $0x20, %rax
cmpq $0x40, %rax
jne 0x27fb
incq %r15
cmpq $0x3e, %rbp
leaq -0x2a(%rbp), %rax
movl $0x14, %ecx
cmovbq %rcx, %rax
movq %r12, (%rbx)
movq %rax, %rbp
cmpq $0x14, %rax
vpbroadcastq 0x959(%rip), %ymm5 # 0x3238
vpbroadcastq 0x940(%rip), %ymm6 # 0x3228
ja 0x2606
movq 0x10(%rsp), %r14
movq 0x8(%rsp), %r15
testq %r13, %r13
je 0x2b83
cmpq $0x0, 0x18(%rsp)
je 0x2c2e
movq %r15, 0x8(%rsp)
movq %r14, 0x10(%rsp)
leaq 0x36(%rsp), %r14
movl $0x1, %r15d
leaq 0xa2(%rsp), %r12
vpbroadcastq 0x915(%rip), %ymm3 # 0x3248
vpbroadcastq 0x8ec(%rip), %ymm4 # 0x3228
vpbroadcastq 0x8eb(%rip), %ymm5 # 0x3230
xorl %ebp, %ebp
movb $-0x60, 0x21(%rsp)
cmpq $0x16, %r13
setae %al
xorb $-0x5b, %al
movb %al, 0x20(%rsp)
vpbroadcastq %r15, %ymm0
movl $0x2, %eax
vpmovsxbq 0x8e3(%rip), %ymm1 # 0x3250
vpcmpltuq %ymm3, %ymm1, %k1
vpcmpltuq %ymm4, %ymm1, %k2
vpsllq $0x3, %ymm1, %ymm2
vpsrlvq %ymm2, %ymm0, %ymm2
vpmovqb %ymm2, %xmm2
vmovdqu8 %xmm2, %xmm2 {%k2} {z}
vmovdqu8 %xmm2, 0x20(%rsp,%rax) {%k1}
vpaddq %ymm5, %ymm1, %ymm1
addq $0x4, %rax
cmpq $0x16, %rax
jne 0x296d
movq 0x18(%rsp), %rax
addq %rbp, %rax
cmpq $0x15, %r13
jbe 0x29c8
movq 0xe(%rax), %rcx
movq %rcx, 0xe(%r14)
vmovdqu (%rax), %xmm0
vmovdqu %xmm0, (%r14)
jmp 0x29f6
xorl %ecx, %ecx
movb (%rax,%rcx), %dl
leal 0x16(%rcx), %esi
movb %dl, 0x20(%rsp,%rsi)
incq %rcx
cmpl %r13d, %ecx
jb 0x29ca
leaq (%r14,%r13), %rdi
movl $0x15, %edx
subl %r13d, %edx
incq %rdx
movl %r13d, %esi
vzeroupper
callq 0x1030
movq 0x170(%rsp), %rcx
movl 0x10(%rcx), %eax
movl %eax, 0x26(%r14)
vmovups (%rcx), %xmm0
vmovups %xmm0, 0x16(%r14)
leaq 0x20(%rsp), %rdi
leaq 0x60(%rsp), %rsi
vzeroupper
callq 0x1080
xorl %eax, %eax
vpmovsxbq 0x82c(%rip), %ymm8 # 0x3258
vpmovsxbq 0x827(%rip), %ymm9 # 0x325c
vpmovsxbq 0x822(%rip), %ymm10 # 0x3260
vpmovsxbq 0x81d(%rip), %ymm11 # 0x3264
vpmovsxbq 0x818(%rip), %ymm12 # 0x3268
vpmovsxbq 0x813(%rip), %ymm13 # 0x326c
vpmovsxbq 0x7f2(%rip), %ymm14 # 0x3254
vpmovsxbq 0x7e5(%rip), %ymm15 # 0x3250
vpbroadcastq 0x7cb(%rip), %ymm16 # 0x3240
vpbroadcastq %rax, %ymm0
vpor %ymm0, %ymm8, %ymm1
vpor %ymm0, %ymm9, %ymm2
vpor %ymm0, %ymm10, %ymm3
vpor %ymm0, %ymm11, %ymm4
vpor %ymm0, %ymm12, %ymm5
vpor %ymm0, %ymm13, %ymm6
vpor %ymm0, %ymm14, %ymm7
vpor %ymm0, %ymm15, %ymm0
vpcmpltuq %ymm16, %ymm0, %k0
vpcmpltuq %ymm16, %ymm7, %k1
kshiftlb $0x4, %k1, %k1
korb %k1, %k0, %k0
vpcmpltuq %ymm16, %ymm6, %k1
vpcmpltuq %ymm16, %ymm5, %k2
kshiftlb $0x4, %k2, %k2
korb %k2, %k1, %k1
kunpckbw %k0, %k1, %k0
vpcmpltuq %ymm16, %ymm4, %k1
vpcmpltuq %ymm16, %ymm3, %k2
kshiftlb $0x4, %k2, %k2
korb %k2, %k1, %k1
vpcmpltuq %ymm16, %ymm2, %k2
vpcmpltuq %ymm16, %ymm1, %k3
kshiftlb $0x4, %k3, %k3
korb %k3, %k2, %k2
kunpckbw %k1, %k2, %k1
kunpckwd %k0, %k1, %k1
vmovdqu8 0x62(%rsp,%rax), %ymm0 {%k1} {z}
vmovdqu8 (%r12,%rax), %ymm1 {%k1} {z}
vpxor %ymm0, %ymm1, %ymm0
vmovdqu8 %ymm0, (%r12,%rax) {%k1}
addq $0x20, %rax
cmpq $0x40, %rax
jne 0x2a75
incq %r15
leaq -0x16(%r13), %rax
cmpq $0x16, %r13
movl $0x0, %ecx
cmovbq %rcx, %rax
movl $0x16, %ecx
cmovaeq %rcx, %r13
addq %r13, %rbp
movq %rax, %r13
testq %rax, %rax
vpbroadcastq 0x6e7(%rip), %ymm3 # 0x3248
vpbroadcastq 0x6be(%rip), %ymm4 # 0x3228
vpbroadcastq 0x6bd(%rip), %ymm5 # 0x3230
jne 0x2947
movq 0x10(%rsp), %r14
movq 0x8(%rsp), %r15
leaq 0xa0(%rsp), %rdi
leaq 0x20(%rsp), %r12
movq %r12, %rsi
vzeroupper
callq 0x1080
movl $0xfffff, %eax          # imm = 0xFFFFF
kmovd %eax, %k1
movq 0x170(%rsp), %rax
vmovdqu8 (%rax), %ymm0 {%k1} {z}
vmovdqu8 0x2c(%r12), %ymm1 {%k1} {z}
vpxor %ymm0, %ymm1, %ymm0
vmovdqu8 %ymm0, 0x2c(%r12) {%k1}
movq (%rbx), %rcx
movb (%r15,%rcx), %dl
movb $0x1, %al
cmpb (%r12), %dl
jne 0x2c06
leaq (%rcx,%r15), %rax
incq %rax
xorl %ecx, %ecx
cmpq $0x13, %rcx
je 0x2c3c
movb (%rax,%rcx), %sil
leaq 0x1(%rcx), %rdx
cmpb 0x21(%rsp,%rcx), %sil
movq %rdx, %rcx
je 0x2be4
decq %rdx
cmpq $0x13, %rdx
setb %al
cmpq $0x0, (%rbx)
je 0x2c3f
movl $0x1, %ecx
xorl %edx, %edx
movb $0x0, (%r14,%rdx)
movl %ecx, %edx
incl %ecx
cmpq %rdx, (%rbx)
ja 0x2c13
jmp 0x2c3f
movq $0x0, (%rbx)
xorl %eax, %eax
jmp 0x2c44
movl $0xfffffffc, %eax       # imm = 0xFFFFFFFC
jmp 0x2c44
movl $0xfffffffd, %eax       # imm = 0xFFFFFFFD
jmp 0x2c44
setb %al
movzbl %al, %eax
negl %eax
addq $0x128, %rsp            # imm = 0x128
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
vzeroupper
retq
nopl (%rax)