#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <vector>
#include <algorithm>
#include "hash.h"
#include <NTL/matrix.h>
#include <NTL/GF2.h>
#include <NTL/vec_GF2.h>
#include <NTL/mat_GF2.h>
#include <NTL/mat_GF2E.h>
#include <cassert>
#include <NTL/GF2E.h>
#include <NTL/GF2EX.h>
#include <NTL/ZZX.h>
#include <NTL/lzz_pXFactoring.h>
#include <NTL/GF2EXFactoring.h>

#define u64 unsigned long
#define u32 unsigned int
#define u16 unsigned short
#define u8  unsigned char



#define NumArray (1<<30)

#define m_E 11
#define n_E 2048
#define t_E 32
#define k_E 1696
#define q_n64 32//ceil(n_E/64)
#define q_n64M1 31// q_k64-1
#define ceil_nED2 1024 // ceil{n_E/2}


#define n_R 2756//2755//8192 // n_R =2^m_R
#define t_R 121
#define k_R 2206 
#define r_R 550 // n_R = k_R + r_R
#define q_r64 9 //ceil(r_R/64)
#define q_r64M1 8//q_r64 -1
#define r_r64 38//r_R%64
#define ceil_nRD2 1378 //4096 //ceil{n_R/2} 

#define kappa 140

//#define log_NGU 	should be less than 31
//#define NGU 		(Number of group user) = 2^(log_NGU)
//#define k_1 		random part = k_E - log_NGU

#define log_NGU 16
#define NGU 65536
#define k_1 1680

/*********************************
log_NGU	 NGU			k1
 2		4				1694
 6		64				1690
 7		128				1689
 8		256				1688
10		1024			1686
12		4096			1684
14		16384			1682	
/*********************************
16		65536   		1680
17		131072			1679
18		262144			1678
19		524288			1677
20		1048576			1676
21		2097152			1675
22		4194304			1674
23		8388608			1673
24		16777216		1672
**********************************/

NTL_CLIENT

void COM(u64 message[], int NumElt, int OutputLen, u64 answer[])
{
	
	int i,j,k;
	int r,c,b;
	int NumMsgByte=0, NumMsgByteM1=0, NumMsgBlock=0,NumMsgBlockM1=0,NumTempMsgP1=0;
	int NumTempMsg=0;
	int quo_OutputLen_8=0;
	int cnt=0;
	long templong;
	u8 TempMsg[8]={0};
	u64 TempMsg64[18]={0};
	u64 temp64;
	
	u64 Intermediate1[25]={0};
	u64 Intermediate2[25]={0};
	u64 theta_Inter[5]={0};
	u64 theta_Inter_Shift[5]={0};
	
	u64 RC[24]={0x0000000000000001,0x0000000000008082,0x800000000000808a,0x8000000080008000,
				0x000000000000808b,0x0000000080000001,0x8000000080008081,0x8000000000008009,
				0x000000000000008a,0x0000000000000088,0x0000000080008009,0x000000008000000a,
				0x000000008000808b,0x800000000000008b,0x8000000000008089,0x8000000000008003,
				0x8000000000008002,0x8000000000000080,0x000000000000800a,0x800000008000000a,
				0x8000000080008081,0x8000000000008080,0x0000000080000001,0x8000000080008008};
	
	
	u8 Result[64]={0};


	c=2*OutputLen; //2*(224, 256, 384, 512)=(448, 512, 768,1024)
	b=1600;
	r=b-c; //1600-c = (1152, 1088, 832, 576)
	
	NumMsgByte = r>>3; //r-bit =>(r/8) bytes 
	NumMsgByteM1 = NumMsgByte-1; //bytes-1
	NumMsgBlock = NumMsgByte>>3;// number of 64-bit blocks
	NumMsgBlockM1=NumMsgBlock-1;

	
	int NumIteration = NumElt/NumMsgBlock;
	int NumRest = NumElt%NumMsgBlock;
	
	
	for(j=0;j<NumIteration;j++)
	{
		for (i=0;i<NumMsgBlock;i++)
		{
			TempMsg64[i]=message[i+j*NumMsgBlock];
		}
		
		
		for (i=0;i<NumMsgBlock;i++)
		{
			Intermediate1[i]^=TempMsg64[i];
		}
		Keccakf(Intermediate1, Intermediate2);
	}
	
	templong=0;
	
	for (i=0;i<NumRest;i++)
	{
		TempMsg64[i]=message[NumIteration*NumMsgBlock+i];
	}
	
	

	
	TempMsg64[NumRest]=0X01;
	
	for (i=0;i<NumRest;i++)
	{
		Intermediate1[i]^=TempMsg64[i];
	}
	
	Intermediate1[NumRest]^=TempMsg64[NumRest];
	
	Intermediate1[NumMsgBlockM1]^=0X8000000000000000;
	
	Keccakf(Intermediate1, Intermediate2)
		
	
	for(i=0;i<(OutputLen/64);i++)
	{
		answer[i] = Intermediate1[i];
	}

	
	
}



void FileHash(int OutputLen, u64 answer[])
{
	
	FILE *fp;
	//const char *FileName="test.zip";
	const char *FileName= "msg.txt";
	
	int i,j,k;
	int r,c,b;
	int NumMsgByte=0, NumMsgByteM1=0, NumMsgBlock=0,NumMsgBlockM1=0,NumTempMsgP1=0;
	int NumTempMsg=0;
	int NumElt=0;
	int quo_OutputLen_8=0;
	int cnt=0;
	long templong;
	u8 TempMsg[8]={0};
	u64 TempMsg64[18]={0};
	u64 temp64;
	
	u64 Intermediate1[25]={0};
	u64 Intermediate2[25]={0};
	u64 theta_Inter[5]={0};
	u64 theta_Inter_Shift[5]={0};
	
	u64 RC[24]={0x0000000000000001,0x0000000000008082,0x800000000000808a,0x8000000080008000,
				0x000000000000808b,0x0000000080000001,0x8000000080008081,0x8000000000008009,
				0x000000000000008a,0x0000000000000088,0x0000000080008009,0x000000008000000a,
				0x000000008000808b,0x800000000000008b,0x8000000000008089,0x8000000000008003,
				0x8000000000008002,0x8000000000000080,0x000000000000800a,0x800000008000000a,
				0x8000000080008081,0x8000000000008080,0x0000000080000001,0x8000000080008008};
	
	
	u8 Result[64]={0};
	
	c=2*OutputLen; //2*(224, 256, 384, 512)=(448, 512, 768,1024)
	b=1600;
	r=b-c; //1600-c = (1152, 1088, 832, 576)
	
	NumMsgByte = r>>3; //r-bit =>(r/8) bytes 
	NumMsgByteM1 = NumMsgByte-1; //bytes-1
	NumMsgBlock = NumMsgByte>>3;// number of 64-bit blocks
	NumMsgBlockM1=NumMsgBlock-1;
	
	fp=fopen(FileName,"rb");
	

	NumElt=fread(TempMsg64,sizeof(u64), NumMsgBlock,fp);
	
	while(NumElt==NumMsgBlock)
	{
		for (i=0;i<NumMsgBlock;i++)
		{
			Intermediate1[i]^=TempMsg64[i];
		}
		
		Keccakf(Intermediate1, Intermediate2)
		
		NumElt=fread(TempMsg64,sizeof(u64), NumMsgBlock,fp);
		
	}

	templong = ftell(fp);
	
	templong=(templong%8)*8;
	
	temp64 = 0X01;
	if(templong==0){
		TempMsg64[NumElt]=0X01;
	}
	else{
		TempMsg64[NumElt]=(TempMsg64[NumElt] &(0XFFFFFFFFFFFFFFFF>>(64-templong)))^(temp64<<templong);	
	}

	
	for (i=0;i<NumElt;i++)
	{
		Intermediate1[i]^=TempMsg64[i];
	}
	
	Intermediate1[NumElt]^=TempMsg64[NumElt];
	
	Intermediate1[NumMsgBlockM1]^=0X8000000000000000;
	
	Keccakf(Intermediate1, Intermediate2)
	
	for(i=0;i<(OutputLen/64);i++)
	{
		answer[i] = Intermediate1[i];
	}

	

	fclose(fp);

	
}


/*****************************************
Random Sampling for random_suffle
*****************************************/
int rangen(int i)
{
	return rand()%i;
}		
	
/*****************************************
Random Nonsingular Matrix Generation
*****************************************/
Mat<GF2> RanNSingMatGen(int dim)
{
	assert(dim>=1);
	
	int i=0,j=0;
	Mat<GF2> matS;
	
	matS.SetDims(dim, dim);
	do{
		for(i=0;i<dim;i++)
		{
			for(j=0;j<dim;j++) matS[i][j] = random_GF2();		
		}
	}while(determinant(matS)!=1);
	
	return matS;
}

/*****************************************
Irreducible Polynomial Generation
*****************************************/
ZZX makeIrredPoly(long p, long d)
{
	assert(d>=1);
	assert(ProbPrime(p));
	
	if(d==1) return ZZX(1,1);
	
	zz_pBak bak; bak.save();
	zz_p::init(p);
	
	return to_ZZX(BuildIrred_zz_pX(d));

}

/*****************************************
Random Permutation matrix Generation
*****************************************/
void  RanPermGen(int dim, vector<int> *permvector)
{
	assert(dim>=1);
	
	int i=0;
	
	for(i=0;i<dim;i++) (*permvector).push_back(i);
	random_shuffle((*permvector).begin(), (*permvector).end(), rangen);
}
	
/*****************************************
Parity check matrix generation for binary Goppa codes
Input: n, m, t
*****************************************/
Mat<GF2> ParityMatGen(int _n, int _k, int _m, int _t,
         GF2X irrPoly, GF2E *alpha, GF2EX *genpoly, GF2EX *invPoly_alpha)
{
	int i=0,j=0,k=0;
	GF2X temp_GF2X;
	
	
	GF2E::init(irrPoly);
	
	GF2E  temp_GF2E;
	GF2EX temp_GF2EX;
	
	Mat<GF2E> temp_Hsk;
	temp_Hsk.SetDims( _t, _n);
	
	Mat<GF2> Hsk, CheckHsk;
	Hsk.SetDims( _n-_k, _n);
	CheckHsk.SetDims( _n-_k, _n-_k);
	
	do{
	
		alpha[0]=0;
		alpha[1]=1;
	
		do{
			random(alpha[2]);
			temp_GF2E = alpha[2];
			
			for(i=0;i<(_m/2);i++)
			{
				sqr(temp_GF2E, temp_GF2E);
			}
		}while((temp_GF2E==alpha[2]) || (IsOne(temp_GF2E*alpha[2])));	
		
		for(i=3;i<_n;i++)
		{
			alpha[i] = alpha[i-1]*alpha[2];
		}
	
		BuildIrred(*genpoly, _t);
		
		for(i=0;i<_n;i++){temp_Hsk[0][i]=0;}
		for(i=0;i<_n;i++)
		{
			for(j=_t;j>=0;j--)
			{
				temp_Hsk[0][i] = (temp_Hsk[0][i]*alpha[i])+(*genpoly)[j];
			}
		}
		
		for(i=0;i<_n;i++)
		{
			temp_Hsk[0][i] = inv(temp_Hsk[0][i]);
		}
		
		for(i=1;i<_t;i++)
		{
			for(j=0;j<_n;j++)
			{
				temp_Hsk[i][j] = temp_Hsk[i-1][j]*alpha[j];
			}
		}
		
		for(i=0;i<_t;i++)
		{
			for(j=0;j<_n;j++)
			{
				temp_GF2X =rep(temp_Hsk[i][j]);
				if(deg(temp_GF2X)!=-1)
				{
					for(k=0;k<_m;k++)
					{
						Hsk[i*_m+k][j] = temp_GF2X[k];
					}		
				}
				else
				{
					for(k=0;k<_m;k++) Hsk[i*_m+k][j]=0;
				}
				
			}
		}
		
		for(i=0;i<(_n-_k);i++)
		{
			for(j=0;j<(_n-_k);j++)
			{
				CheckHsk[i][j] = Hsk[i][j];
			}
		}
			
		
	}while(determinant(CheckHsk)==0);

	SetCoeff(temp_GF2EX, 1, 1);
	
	for(i=0;i<_n;i++)
	{
		SetCoeff(temp_GF2EX, 0, -alpha[i]);
		InvMod(invPoly_alpha[i], temp_GF2EX, *genpoly);
		
	}
	
	return Hsk;
}

/*****************************************
Square Root Matrix
*****************************************/
Mat<GF2> SqrtMatrix(GF2X irrPoly, GF2EX genPoly,int _n, int _k, int _m, int _t)
{
	GF2E::init(irrPoly);
	
	int i=0,j=0, k=0, l=0;

  	Mat<GF2> Result;
	Result.SetDims((_n-_k), (_n-_k));
	
	
	GF2X temp_GF2X;
	GF2E *temp_GF2E; temp_GF2E = new GF2E[_m];
	
	for(i=0;i<_m;i++)
	{
		clear(temp_GF2X);
		SetCoeff(temp_GF2X, i, 1);
		temp_GF2E[i]=conv<GF2E>(temp_GF2X);
	}
	
	GF2EX temp_GF2EX, temp_GF2EX1;
		
	for(j=0;j<_t;j++)
	{
		for(i=0;i<_m;i++)
		{
			clear(temp_GF2EX1);
			SetCoeff(temp_GF2EX1, j, temp_GF2E[i]);
			SqrMod(temp_GF2EX, temp_GF2EX1, genPoly);
		
			for(k=0;k<=deg(temp_GF2EX);k++)
			{
				if(!IsZero(temp_GF2EX[k]))
				{	temp_GF2X = rep(temp_GF2EX[k]);
				
					for(l=0;l<_m;l++)
					{
						if(!IsZero(temp_GF2X[l])) Result[l+k*_m][i+j*_m]=1;
					}
				}
			}
		}
	}


	delete[] temp_GF2E;	
	
	return inv(Result);
		
}

/*****************************************
Generating matrix generation from parity check matrix 
for binary Goppa codes
Input: H, n, k
*****************************************/
Mat<GF2> GenMatrixCom(Mat<GF2> matH, int _n, int _k)
{
	Mat<GF2> matGsk;
	matGsk.SetDims( _k, _n);
	
	kernel(matGsk, transpose(matH));
	
	return matGsk;
}

/*****************************************
Reduecing Matrix G
Input: transpose matrix of G, n, k
*****************************************/
Mat<GF2> ReducedMatG(Mat<GF2> transG, int _n, int _k)
{
	int i=0, j=0, k=0;
	Mat<GF2> matG1, matG2, temp_row1;
	matG1.SetDims(_n, _n+_k);
	matG2.SetDims(_n, _n);
	temp_row1.SetDims(1, _n+_k);
	
	
	for(i=0;i<_n;i++)
	{
		for(j=0;j<_k;j++)
		{
			matG1[i][j] = transG[i][j];
		}
		
		matG1[i][i+_k] = 1;
	}
	


	for(i=0;i<_k;i++)
	{
		if(IsZero(matG1[i][i]))
		{
			j=i;
			do{
				j++;
			}while(IsZero(matG1[j][i]));
			
			for(k=0;k<(_n+_k);k++)
			{
				temp_row1[0][k] = matG1[i][k];
				matG1[i][k] = matG1[j][k];
				matG1[j][k] = temp_row1[0][k]; 
				
			}
		}
		

		for(k=0;k<i;k++)
		{
			if(!IsZero(matG1[k][i]))
			{
				for(j=0;j<(_n+_k);j++)
				{
					matG1[k][j]+=matG1[i][j];
				}
			}
		}
		for(k=(i+1);k<_n;k++)
		{
			if(!IsZero(matG1[k][i]))
			{
				for(j=0;j<(_n+_k);j++)
				{
					matG1[k][j]+=matG1[i][j];
				}
			}
		}
	}

	for(i=0;i<_n;i++)
	{
		for(j=0;j<_n;j++)
		{
			matG2[i][j]=matG1[i][j+_k];
		}
	}
	
	return matG2;
	
}	

/*****************************************
Computing Public Key for binary Goppa codes
Input: S, Gsk, P, n, k
*****************************************/
Mat<GF2> PKCom(Mat<GF2> matS, Mat<GF2> matGsk, vector<int> vecP, int _n, int _k)
{
	int i=0,j=0;
	Mat<GF2> matResult1, matResult2;
	matResult1.SetDims(_k, _n);
	matResult2.SetDims(_k, _n);
	
	mul(matResult1, matS, matGsk);
	
	for(i=0;i<_k;i++)
	{
		for(j=0;j<_n;j++)
		{
			matResult2[i][j] = matResult1[i][vecP[j]];
		}
	}
	
	return matResult2;
	
}

/*****************************************
Random Binary Matrix Generation
input: row_dimension, column_dimension
*****************************************/
Mat<char> RanBinMatGen(int row_dim, int column_dim)
{
	assert(row_dim>=1);
	assert(column_dim>=1);
	
	int i=0,j=0;
	Mat<char> matS;
	
	matS.SetDims(row_dim, column_dim);
	
	for(i=0;i<row_dim;i++)
	{
		for(j=0;j<column_dim;j++) matS[i][j] = rand()%2;		
	}
	
	return matS;
}

	
/*****************************************
McEliece Encryption
Input: Pulbic Key matPK, Message M, n, k, k_1, k_2, t
Output: Ctxt
*****************************************/
Mat<GF2> MEnc(Mat<GF2> matPK, long M, int _n, int _k, int _kran, int _kmes, int _t, u8 err[], u8 uran[])
{
	int i=0, flag=0;
	Mat<GF2> e, ext_m, matCtxt;
	e.SetDims(1, _n);
	ext_m.SetDims(1, _k);
	matCtxt.SetDims(1, _n);
	
	vector<int> tempvector;
	RanPermGen(_n, &tempvector);

	for(i=0;i<_t;i++)
	{
		e[0][tempvector[i]] = 1;	
	}		
		
	tempvector.clear(); 
	
	for(i=0;i<_n;i++)
	{
		if(!IsZero(e[0][i])){err[i]=1;}
		else{err[i]=0;}
	}	

	for(i=0;i<_kran;i++) random(ext_m[0][i]);

	for(i=_kran;i<_k;i++) ext_m[0][i] = ((M>>(_k-1-i)) & 0x1);
	
	for(i=0;i<_kran;i++)
	{
		if(!IsZero(ext_m[0][i])){uran[i]=1;}
		else{uran[i]=0;}
	}
	
	mul(matCtxt, ext_m, matPK);
	add(matCtxt, matCtxt, e);
	
	return matCtxt;
}	

/***********************************
partial GCD
***********************************/
void pGCD(GF2EX *output_gcd, GF2EX *output_poly1,GF2EX sqrt_syndrome,
    GF2EX genpoly,int errcap, GF2X irrPoly)
{
	int i=0;
	int bound1, bound_gcd;
	
	bound_gcd = errcap/2;
	bound1 = (errcap-1)/2;
	
	
	GF2E::init(irrPoly);
	
	GF2EX oldr, newr, oldt, newt, temp, quotient;
	
	oldr = genpoly;
	newr = sqrt_syndrome;
	clear(oldt);
	set(newt);
	
	
	while( (IsZero(newr)!=1) && ((deg(oldt)>bound1) || (deg(oldr)>bound_gcd)) )
	{
		
		DivRem(quotient, temp, oldr, newr);
		
		oldr = newr;
		newr = temp;
		temp = oldt - newt*quotient;
		oldt = newt;
		newt = temp;
	}
	
	(*output_gcd) = oldr;
	(*output_poly1) = oldt;
}
	

/*****************************************
Decoding algorithm with generating polynomial
Input:  Vector, irrPoly, genpoly, alpha,....
Output: (1*n) error-corrected matrix 
*****************************************/
Mat<GF2> EDecode(Mat<GF2> matHsk,Mat<GF2> matCtxt, GF2X irrPoly, GF2EX genpoly,
	GF2E alpha[],GF2EX invPoly_alpha[],Mat<GF2> SqrtMatrix, int _n, int _k, int _m, int _t)
{
	int i=0, j=0, flag=0;
	Mat<GF2> DecResult, matSyndrome;
	DecResult.SetDims(1, (_n-_k));
	matSyndrome.SetDims(_n-_k,1);

	GF2X temp_GF2X;
	
	GF2E::init(irrPoly);
	GF2EX syndrome, mono_GF2EX;
	GF2EX output_gcd, output_poly;
	GF2EX gcd_poly1, gcd_poly2;
	GF2E *evaluation; evaluation = new GF2E[_n];
	SetCoeff(mono_GF2EX, 1, 1);
	SetCoeff(gcd_poly1, 1, 1);
	SetCoeff(gcd_poly2, 1, 1);
	
	double timing;
	
	
	clear(syndrome);
	
	for(i=0;i<_n;i++)
	{
		if(!IsZero(matCtxt[0][i]))
		{
			syndrome += invPoly_alpha[i]; 
		}
	}
	
	DecResult = matCtxt;
	
	if(IsZero(syndrome))
	{
		return DecResult;
	}
	else{
		InvMod(syndrome, syndrome, genpoly);
		syndrome += mono_GF2EX;
		
		for(i=0;i<=deg(syndrome);i++)
		{
			clear(temp_GF2X);
			if(!IsZero(syndrome[i]))
			{
				temp_GF2X = rep(syndrome[i]);
				for(j=0;j<=deg(temp_GF2X);j++)
				{
					if(!IsZero(temp_GF2X[j])){matSyndrome[j+i*_m][0]=1;}
				}
			}
		}

		mul(matSyndrome, SqrtMatrix, matSyndrome);
	
		clear(syndrome);
	
		for(i=0;i<_t;i++)
		{
			clear(temp_GF2X);
			for(j=0;j<_m;j++)
			{
				if(!IsZero(matSyndrome[j+i*_m][0]))
				{
					SetCoeff(temp_GF2X, j, 1);
				}
			}
			SetCoeff(syndrome, i, conv<GF2E>(temp_GF2X));
		}
		
		pGCD(&output_gcd, &output_poly, syndrome, genpoly, _t, irrPoly);
		
		syndrome = power(output_gcd,2)+power(output_poly, 2)*mono_GF2EX;
		
		for(i=0;i<_n;i++)
		{
			for(j=deg(syndrome);j>=0;j--)
			{
				evaluation[i] = (evaluation[i]*alpha[i])+syndrome[j];
			}
		}

		
		for(i=0;i<_n;i++)
		{
			if(IsZero(evaluation[i]))
			{
				DecResult[0][i]+=1;
			}
		}
				
	}

	delete[] evaluation;
	
	return DecResult;
	
}


/*****************************************
McEliece Decryption
Input: Secret Key matS, matP, irrPoly, genpoly, alpha
n, k, k_1, k_2, t
Output: message
*****************************************/
long MDec(Mat<GF2> matS, Mat<GF2> matGsk, 
Mat<GF2> matHsk, vector<int> VecP,GF2X irrPoly, 
GF2EX genpoly, GF2E alpha[], GF2EX invPoly_alpha[], Mat<GF2> SqrtMatrix, Mat<GF2> transG, 
Mat<GF2> Ctxt,int _n, int _k, int _m, int _kran, int _kmes, int _t)
{
	int i=0, j=0,k=0;
	long M=0;
	
	Mat<GF2> matCtxt, DecodeResult, matMS, matShortMS;
	matCtxt.SetDims(1, _n);
	DecodeResult.SetDims(1,_n);
	matMS.SetDims(_n, 1);
	matShortMS.SetDims(1, _k);
	
	for(i=0;i<_n;i++)
	{
		matCtxt[0][VecP[i]] = Ctxt[0][i];
	}
	
	DecodeResult = EDecode(matHsk, matCtxt, irrPoly, genpoly, alpha, invPoly_alpha, SqrtMatrix, _n, _k, _m, _t);
	
	mul(matMS, transG, transpose(DecodeResult));

	for(i=0;i<_k;i++)
	{
		matShortMS[0][i] = matMS[i][0];
	}
	
	Mat<GF2> matFinal;
	matFinal.SetDims(1,_k);
	
	mul(matFinal, matShortMS, inv(matS));
	
	for(i=_kran;i<_k;i++) M = (M<<1)+conv<u64>(matFinal[0][i]);
	
	return M;

}

	
/*********************
Main Function
**********************/	
int main(int iArgc, char** pArgv)
{
	long message = 0;
	int seed = 0;
	
	if(iArgc != 3)
	{
		printf("\nusage:\n");
		printf("execution_name User_Index Seed\n");
		printf("e.g.~]$test 38 10\n");
		return -1;
	}
	
	message = atoi(pArgv[1]);
	seed = atoi(pArgv[2]);

	
	int i=0, j=0, k=0,l=0;
	int flag = 0;
	int index = 0;
		
	u64 mask[64]={0};
	u64 Hmask=0;


	for(i=0;i<64;i++)
	{
		mask[i] = (((u64)1)<<(63-i));
	}
	
	for(i=0;i< r_r64;i++)
	{
		Hmask^=mask[i];
	}


	srand(time(NULL));
	
	Mat<GF2> S_E, Hsk_E, Gsk_E, Gpk_E;
	S_E.SetDims(k_E, k_E);
	Hsk_E.SetDims(n_E-k_E, n_E);
	Gsk_E.SetDims(k_E, n_E);
	Gpk_E.SetDims(k_E, n_E);
	
	u64 u64Gpk_E[k_E+log_NGU][q_n64]={0};

	vector<int> P_E;
	
	double keygen_time = 0, sign_time = 0, verify_time=0, open_time=0;
	
	keygen_time = GetTime();
	
	cout << "Key generation for code-based group signature!" << endl;
	cout << endl;
	cout << endl;
	
	cout << "K01. Start McEliece key generation!" << endl;
	cout << endl;
	cout << "K01-01. Generating random non-singular matrix...";
	
	S_E = RanNSingMatGen(k_E);
	
	cout << "done!" << endl;
	
	cout << "K01-02. Generating permutation matrix...";
	
	RanPermGen(n_E, &P_E);
	
	cout << "done!" << endl;
	
	cout << "K01-03. Generating parity check matrix generation for Goppa codes...";
	GF2X irrPoly_E;
	irrPoly_E = conv<GF2X>(makeIrredPoly(2, m_E));
	
	GF2E::init(irrPoly_E);

	GF2EX genPoly_E;
	GF2E *alpha_E; alpha_E = new GF2E[n_E];
	GF2EX *invPoly_alpha_E; invPoly_alpha_E = new GF2EX[n_E];
	
	Hsk_E = ParityMatGen(n_E, k_E, m_E, t_E, irrPoly_E, alpha_E, &genPoly_E, invPoly_alpha_E);
	
	Mat<GF2> SqrtMatrix_E;
	SqrtMatrix_E = SqrtMatrix(irrPoly_E, genPoly_E, n_E, k_E, m_E, t_E);
	
	cout << "done!" << endl;
	
	cout << "K01-04. Computing generating matrix...";
	
	Gsk_E = GenMatrixCom(Hsk_E, n_E, k_E);
	
	Mat<GF2> transG_E;
	transG_E = ReducedMatG(transpose(Gsk_E), n_E, k_E);
	
	cout << "done!" << endl;
	
	cout << "K01-05. Computing public key...";
	
	Gpk_E = PKCom(S_E, Gsk_E, P_E, n_E, k_E);


	for(i=0;i<(k_E+log_NGU);i++)
	{
		for(j=0;j<q_n64;j++)
		{
			u64Gpk_E[i][j]=0;
		}

	}

	
	index = 0;

	for(i=0;i<k_1;i++)
	{
		for(j=0;j<q_n64;j++)
		{
			index = 64*j;
			
			for(k=0;k<64;k++)
			{
				if(Gpk_E[i][index+k]==1)
				{
					u64Gpk_E[i][j] ^= mask[k];
				}

			}
		}

	}

	index = 0;
	

	for(i=0;i<log_NGU;i++)
	{
		for(j=0;j<q_n64;j++)
		{
			index  = 64*j;
			for(k=0;k<64;k++)
			{
				if(Gpk_E[k_1 + i][index+k]==1)
				{
					u64Gpk_E[ k_1 + (2*i+1)][j] ^= mask[k];
				}
			}
		}
	}
	
	index = 0;

	unsigned long gpk_length = sizeof(u64Gpk_E)+sizeof(Gpk_E);
	
	cout << "done!" << endl;
	
	cout << endl;
	cout << "K02. User's secret key generation!" << endl;
	cout << endl;
	
	cout << "K02-01. Generating a binary random matrix...";
	
	u64 Hvk_SD[q_r64][n_R]={0};	
	
	for(i=0;i<q_r64;i++)
	{
		for(j=0;j<n_R;j++)
		{
			Hvk_SD[i][j] = (((u64)rand())<<32)^((u64)rand());
		}	
	}
	
	for(j=0;j<n_R;j++)
	{
		Hvk_SD[q_r64M1][j]  = Hvk_SD[q_r64M1][j] & Hmask;
	}
	
	cout << "done!" << endl;
	
	cout << "K02-02. Generating user's secret key and corresponding public key...";

	Mat<char> gsk;	
	u8 *extSig = new u8[n_R];
	gsk.SetDims(n_R, 1);
	
	u64 **colA = new u64*[q_r64];

	for(i=0;i<q_r64;i++)
	{
		colA[i] = new u64[NGU];
	}


	for(i=0;i<q_r64;i++)
	{	
		for(j=0;j<NGU;j++) colA[i][j]=0;
	}

	
	vector<int> tempvector;
	
	
	for(i=0;i<NGU;i++)
	{
		tempvector.clear();

		RanPermGen(n_R, &tempvector);
	
		for(j=0;j<n_R;j++)
		{
			gsk[j][0] = 0;
		}


		for(j=0;j<t_R;j++)
		{
			gsk[tempvector[j]][0] = 1;
		}
		
		if(i==((int)message)){
			for(j=0;j<n_R;j++)
			{
				extSig[j] = gsk[j][0];
			}
		}
		
		
		for(j=0;j<n_R;j++)
		{
			if(gsk[j][0] == 1)
			{
				for(k=0;k<q_r64;k++) colA[k][i] ^= Hvk_SD[k][j];
			}

		}
	}

	flag = 0;
	
	for(i=0;i<n_R;i++)
	{
		if(extSig[i]==1) flag++;
	}

	if(flag != t_R){ cout << " The weight of ext-Signature is wrong!" << endl; return 0;}

	// q_r64 radku, NGU sloupcu
	unsigned long gsk_length = sizeof(colA[0][0]) * q_r64;

	cout << "done!" << endl;
		
	keygen_time = GetTime()-keygen_time;
	
	sign_time = GetTime();
	
	cout << "Start generating signature!" << endl;
	cout << endl;
	
	long message1=0;
	
	for(j=0;j<log_NGU;j++)
	{
		if((message>>(log_NGU-j-1)) &0x1)
		{
			message1 ^= (((long)1)<<(2*(log_NGU-j-1)));
		}
		else{
			message1 ^= (((long)2)<<(2*(log_NGU-j-1)));
		}
	}
			
	cout << "S01. Encrypt the index of the signer...";
	Mat<GF2> Ctxt;
	Ctxt.SetDims(1, n_E);
	u8 enc_error[n_E]={0};
	u8 u_ran[k_1]={0};
	
	Ctxt = MEnc(Gpk_E, message, n_E, k_E, k_1, log_NGU, t_E, enc_error, u_ran);

	cout << "done!" << endl;
	
	cout << "S02. Computing zero-knowledge arguments for kappa elements...";
	
	u64 zk_b[kappa]={0};
	vector<int> zk_pi[kappa];
	vector<int> zk_sigma[kappa];
	char zk_Ch[kappa]={0};
	u64 zk_rho[kappa][12]={0};

	u8 **zk_rs  =  new u8*[kappa];
	u8 **zk_sxor =  new u8*[kappa];
	u8 **zk_pirs =  new u8*[kappa];
	u8 **zk_rx = new u8*[kappa];
	u8 **zk_xxor = new u8*[kappa];
	u8 **zk_tbrx = new u8*[kappa];

	for(i=0;i<kappa;i++)
	{
		zk_rs[i] = new u8[n_R];
		zk_sxor[i] = new u8[n_R];
		zk_pirs[i] = new u8[n_R];
		
		zk_rx[i] = new u8[NGU];
		zk_xxor[i] = new u8[NGU];
		zk_tbrx[i] = new u8[NGU];
		
	}
	
	u8 zk_rg[kappa][2*log_NGU]={0};
	u8 zk_ru[kappa][k_1]={0};
	
	u8 zk_re[kappa][n_E]={0};
	u64 zk_c1[kappa][4]={0};
	u64 zk_c2[kappa][4]={0};
	u64 zk_c3[kappa][4]={0};
	u8 encode_g[2*log_NGU]={0};
	
	u8 zk_gxor[kappa][2*log_NGU]={0};
	u8 zk_exor[kappa][n_E]={0};	
	
	u8 zk_tbrg[kappa][2*log_NGU]={0};
	u8 zk_sigmare[kappa][n_E]={0};
	

	u8 *temp_u8array = new u8[NumArray];	

	for(j=0;j<log_NGU;j++)
	{
		if((message>>(log_NGU-j-1)) &0x1)
		{
			encode_g[2*j]=0; encode_g[2*j+1]=1;
		}
		else{
			encode_g[2*j]=1; encode_g[2*j+1]=0;
		}
	}
	
	u8 temp_encode[2*log_NGU]={0};
	
	for(j=0;j<(2*log_NGU);j++)
	{
		temp_encode[j]=encode_g[j];
	}
	
	int temp_int = 0;
	int cnt = 0, cnt_aux = 0;
			
	/********************************
	Set All Random Values
	*********************************/
	
	srand(seed);
	
	for(i=0;i<kappa;i++)
	{
		RanPermGen(n_R, &(zk_pi[i]));
		RanPermGen(n_E, &(zk_sigma[i]));
	}

	for(i=0;i<kappa;i++)
	{
		zk_b[i] = (rand()>>(32-log_NGU));
			
		for(j=0;j<12;j++)
		{
			zk_rho[i][j] = (((u64)rand())<<32)^rand();
		}
			
		cnt = 0;
			
		for(j=0;j<n_R;j++)
		{
			if(cnt == 0){temp_int = rand(); cnt=32;}
			cnt--;
			temp_int = (temp_int>>1);
			zk_rs[i][j] = (temp_int & 0x1);
		}
			
		cnt = 0;
			
		for(j=0;j<NGU;j++)
		{
			if(cnt == 0){temp_int = rand(); cnt=32;}
			cnt--;
			temp_int = (temp_int>>1);
			zk_rx[i][j] = (temp_int & 0x1);
		}
		
		cnt = 0;
			
		for(j=0;j< k_1 ;j++)
		{
			if(cnt == 0){temp_int = rand(); cnt=32;}
			cnt--;
			temp_int = (temp_int>>1);
			zk_ru[i][j] = (temp_int & 0x1);
 		}

		cnt = 0;
			
		for(j=0;j<(2*log_NGU);j++)
		{
			if(cnt == 0){temp_int = rand(); cnt=32;}
			cnt--;
			temp_int = (temp_int>>1);
			zk_rg[i][j] = (temp_int & 0x1);
		}

		cnt = 0;
			
		for(j=0;j<n_E;j++)
		{
			if(cnt == 0){temp_int = rand();cnt=32;}
			cnt--;
			temp_int = (temp_int>>1);
			zk_re[i][j] = (temp_int & 0x1);
		}
			
	}

	/******************************************
	Computing c1, c2, c3
	******************************************/		
	u64 *HashInputMessage = new u64[NumArray];

	u64 u64Result1[q_r64]={0};
	u64 u64Result2[q_r64]={0};
	u64 Finalu64Result[q_r64]={0};

	u64 u64Result3[q_n64]={0};

	u8 extErr[kappa][n_E]={0};
	u8 temp_index[t_R]={0};
	
	u64 HashResult[4]={0};
	u64 HashResult_512[8]={0};

	u8 zk_tbgxor[kappa][2*log_NGU]={0};
	

	for(i=0;i<kappa;i++)
	{
		/********************
		Computing C1
		Starting Point
		********************/

		//Start Computing c1
		cnt = 0;
		HashInputMessage[cnt]=zk_b[i];
		
		cnt++;
		
		for(j=0;j<ceil_nRD2;j++)
		{
			HashInputMessage[cnt] = ((u64)zk_pi[i][j*2]<<32)^zk_pi[i][j*2+1];
			cnt++;
		}
		
		for(j=0;j<ceil_nED2;j++)
		{
			HashInputMessage[cnt] = ((u64)zk_sigma[i][j*2]<<32)^zk_sigma[i][j*2+1];
			cnt++;
		}

	
		for(j=0; j< n_R;j++)
		{
			if(zk_rs[i][j]==1)
			{
				for(k=0;k<q_r64;k++)  u64Result1[k] ^= Hvk_SD[k][j]; 
			}
		}	

		for(j=0;j<NGU;j++)
		{
			if(zk_rx[i][j]==1)
			{
				for(k=0;k<q_r64;k++) u64Result2[k] ^= colA[k][j];
			}
		}
		
		for(k=0;k<q_r64;k++) Finalu64Result[k]= u64Result1[k]^u64Result2[k];
	
		cnt_aux =0;
		
		for(k=0;k<q_r64;k++)
		{
			HashInputMessage[cnt] = Finalu64Result[k];
			cnt++;
		}		
		
		for(k=0;k<q_r64;k++)
		{
			u64Result1[k]=0;
			u64Result2[k]=0;
			Finalu64Result[k]=0;
		}

		for(k=0;k<q_n64;k++)
		{
			u64Result3[k]=0;
		}


		for(j=0;j<k_1;j++)
		{
			if(zk_ru[i][j]==1)
			{
				for(k=0;k<q_n64;k++) u64Result3[k] ^= u64Gpk_E[j][k];
			}
		}


		
		for(j=0;j<(2*log_NGU);j++)
		{
			if(zk_rg[i][j]==1)
			{
				for(k=0;k<q_n64;k++) u64Result3[k] ^= u64Gpk_E[k_1 + j][k];
			}
		}

		index = 0;

		for(j=0;j<q_n64;j++)
		{
			index = 64*j;

			for(k=0;k<64;k++)
			{
				if(zk_re[i][index+k]!=0) u64Result3[j]^=mask[k];
			} 
		}
		
		index = 0;

		
		for(j=0;j<q_n64;j++)
		{
			HashInputMessage[cnt] = u64Result3[j];cnt++;
		
		}

		
		for(j=0;j<q_n64;j++)
		{
			u64Result3[j]=0;
		}

		
		HashInputMessage[cnt] = zk_rho[i][0];
		cnt++;
		HashInputMessage[cnt] = zk_rho[i][1];
		cnt++;
		HashInputMessage[cnt] = zk_rho[i][2];
		cnt++;
		HashInputMessage[cnt] = zk_rho[i][3];
		cnt++;
		
		COM(HashInputMessage, cnt, 256, HashResult);
		
		zk_c1[i][0]=HashResult[0];
		zk_c1[i][1]=HashResult[1];
		zk_c1[i][2]=HashResult[2];
		zk_c1[i][3]=HashResult[3];
		
		for(j=0;j<cnt;j++)
		{
			HashInputMessage[j]=0;
		}
			
		cnt =0; cnt_aux =0;
			
	
		//Starting computing c2
		for(j=0;j<n_R;j++)
		{
			zk_pirs[i][j]=zk_rs[i][zk_pi[i][j]];
		}
		
		for(j=0;j<n_R;j++)
		{
			if(zk_pirs[i][j]!=0)
			{
				HashInputMessage[cnt]^=(((u64)1)<<(63-cnt_aux));
			}
			cnt_aux++;
			if(cnt_aux==64){cnt++; cnt_aux=0;}
		}
		if(cnt_aux!=0){cnt++;}
		
		for(j=0;j<NGU;j++)
		{
			zk_tbrx[i][j] = zk_rx[i][(j^zk_b[i])];
		}		
		cnt_aux = 0;
	
		for(j=0;j<NGU;j++)
		{
			if(zk_tbrx[i][j]!=0)
			{
				HashInputMessage[cnt]^=(((u64)1)<<(63-cnt_aux));
			}
			cnt_aux++;
			if(cnt_aux==64){cnt++;cnt_aux=0;}
		}
		if(cnt_aux!=0){cnt++;}
		
		for(j=0;j<log_NGU;j++)
		{
			if((zk_b[i]>>(log_NGU-j-1)) & 0x1)
			{
				zk_tbrg[i][2*j] = zk_rg[i][2*j+1];
				zk_tbrg[i][2*j+1] = zk_rg[i][2*j];
			}
			else{
				zk_tbrg[i][2*j] = zk_rg[i][2*j];
				zk_tbrg[i][2*j+1] = zk_rg[i][2*j+1];
			}
		}
		
		cnt_aux=0;
		
		for(j=0;j<(2*log_NGU);j++)
		{
			if(zk_tbrg[i][j]!=0)
			{
				HashInputMessage[cnt] ^=(((u64)1)<<(63-cnt_aux));
			}
			cnt_aux++;
			if(cnt_aux==64){cnt++; cnt_aux=0;}
		}
		if(cnt_aux!=0){cnt++;}
		
		for(j=0;j<n_E;j++)
		{
			zk_sigmare[i][j] = zk_re[i][zk_sigma[i][j]];
		}
		cnt_aux = 0;
		
		for(j=0;j<n_E;j++)
		{
			if(zk_sigmare[i][j]!=0)
			{
				HashInputMessage[cnt] ^=(((u64)1)<<(63-cnt_aux));
			}
			cnt_aux++;
			if(cnt_aux==64){cnt++; cnt_aux=0;}
		}
		
		if(cnt_aux!=0){cnt++;}
		
		HashInputMessage[cnt] = zk_rho[i][4];
		cnt++;
		HashInputMessage[cnt] = zk_rho[i][5];
		cnt++;
		HashInputMessage[cnt] = zk_rho[i][6];
		cnt++;
		HashInputMessage[cnt] = zk_rho[i][7];
		cnt++;
		
		COM(HashInputMessage, cnt, 256, HashResult);
		
		zk_c2[i][0]=HashResult[0];
		zk_c2[i][1]=HashResult[1];
		zk_c2[i][2]=HashResult[2];
		zk_c2[i][3]=HashResult[3];

		for(j=0;j<cnt;j++)
		{
			HashInputMessage[j]=0;
		}

		cnt = 0; cnt_aux = 0;
		
		//Starting computing c3...
		for(j=0;j<n_R;j++)
		{
			zk_sxor[i][j] = (extSig[j]^zk_rs[i][j]);
		}
		for(j=0;j<n_R;j++)
		{
			temp_u8array[j] = zk_sxor[i][zk_pi[i][j]];
		}
		cnt_aux=0;
	
		for(j=0;j<n_R;j++)
		{
			if(temp_u8array[j]!=0)
			{
				HashInputMessage[cnt] ^=(((u64)1)<<(63-cnt_aux));
			}
			cnt_aux++;
			if(cnt_aux==64){cnt++;cnt_aux=0;}
		}
		if(cnt_aux!=0){cnt++;}
		
		for(j=0;j<NGU;j++)
		{
			zk_xxor[i][j]=zk_rx[i][j];
		}
		zk_xxor[i][message]^=1;
		
		for(j=0;j<NGU;j++)
		{
			temp_u8array[j] = zk_xxor[i][(j^zk_b[i])];
		}
		cnt_aux = 0;
			
		for(j=0;j<NGU;j++)
		{
			if(temp_u8array[j]!=0)
			{
				HashInputMessage[cnt] ^=(((u64)1)<<(63-cnt_aux));
			}
			cnt_aux++;
			if(cnt_aux==64){cnt++;cnt_aux=0;}
		}
		if(cnt_aux!=0){cnt++;}
		
		for(j=0;j<(2*log_NGU);j++)
		{
			temp_encode[j] = encode_g[j];
		}
		
		for(j=0;j<(2*log_NGU);j++)
		{
			zk_gxor[i][j] = (temp_encode[j]^zk_rg[i][j]);
		}
		
		for(j=0;j<log_NGU;j++)
		{
			if((zk_b[i]>>(log_NGU-j-1)) & 0x1)
			{
				zk_tbgxor[i][2*j] = zk_gxor[i][2*j+1];
				zk_tbgxor[i][2*j+1] = zk_gxor[i][2*j];
			}
			else{
				zk_tbgxor[i][2*j] = zk_gxor[i][2*j];
				zk_tbgxor[i][2*j+1] = zk_gxor[i][2*j+1];
			}
		}
		cnt_aux = 0;
		
		for(j=0;j<(2*log_NGU);j++)
		{
			if(zk_tbgxor[i][j]!=0)
			{
				HashInputMessage[cnt] ^=(((u64)1)<<(63-cnt_aux));
			}
			cnt_aux++;
			if(cnt_aux==64){cnt++; cnt_aux=0;}
		}
		if(cnt_aux!=0){cnt++;}
		
		for(j=0;j<n_E;j++)
		{
			extErr[i][j] = enc_error[j];
		}
		

		for(j=0;j<n_E;j++)
		{
			zk_exor[i][j] = extErr[i][j]^zk_re[i][j];
		}
				
		for(j=0;j<n_E;j++)
		{
			temp_u8array[j] = zk_exor[i][zk_sigma[i][j]];
		}
		cnt_aux=0;
		
		for(j=0;j<n_E;j++)
		{
			if(temp_u8array[j]!=0)
			{
				HashInputMessage[cnt] ^=(((u64)1)<<(63-cnt_aux));
			}
			cnt_aux++;
			if(cnt_aux==64){cnt++; cnt_aux=0;}
		}
		if(cnt_aux!=0){cnt++;}
		cnt_aux=0;
		
		HashInputMessage[cnt] = zk_rho[i][ 8];
		cnt++;
		HashInputMessage[cnt] = zk_rho[i][ 9];
		cnt++;
		HashInputMessage[cnt] = zk_rho[i][10];
		cnt++;
		HashInputMessage[cnt] = zk_rho[i][11];
		cnt++;
		
		COM(HashInputMessage, cnt, 256, HashResult);
		
		zk_c3[i][0] = HashResult[0];
		zk_c3[i][1] = HashResult[1];
		zk_c3[i][2] = HashResult[2];
		zk_c3[i][3] = HashResult[3];
		
		for(j=0;j<cnt;j++)
		{
			HashInputMessage[j]=0;
		}
		
		cnt=0;
		cnt_aux=0;


	}

	/******************************************
	Computing Challenge
	******************************************/	
	cnt = 0;
	
	FileHash(256, HashResult);
	
	HashInputMessage[cnt] = HashResult[0]; cnt++;
	HashInputMessage[cnt] = HashResult[1]; cnt++;
	HashInputMessage[cnt] = HashResult[2]; cnt++;
	HashInputMessage[cnt] = HashResult[3]; cnt++;
	
	for(i=0;i<kappa;i++)
	{
		HashInputMessage[cnt] = zk_c1[i][0];cnt++;
		HashInputMessage[cnt] = zk_c1[i][1];cnt++;
		HashInputMessage[cnt] = zk_c1[i][2];cnt++;
		HashInputMessage[cnt] = zk_c1[i][3];cnt++;
		HashInputMessage[cnt] = zk_c2[i][0];cnt++;
		HashInputMessage[cnt] = zk_c2[i][1];cnt++;
		HashInputMessage[cnt] = zk_c2[i][2];cnt++;
		HashInputMessage[cnt] = zk_c2[i][3];cnt++;
		HashInputMessage[cnt] = zk_c3[i][0];cnt++;
		HashInputMessage[cnt] = zk_c3[i][1];cnt++;
		HashInputMessage[cnt] = zk_c3[i][2];cnt++;
		HashInputMessage[cnt] = zk_c3[i][3];cnt++;
	}	
	

	for(i=0;i<(k_E+log_NGU);i++)
	{
		for(j=0;j<q_n64;j++)
		{
			HashInputMessage[cnt] = u64Gpk_E[i][j];cnt++;
		}
	}

	cnt_aux=0;

	for(i=0;i<n_R;i++)
	{
		for(j=0;j<q_r64;j++)
		{
			HashInputMessage[cnt] = Hvk_SD[j][i];
			cnt++;
		}	
	}

	for(i=0;i<NGU;i++)
	{
		for(j=0;j<q_r64;j++)
		{
			HashInputMessage[cnt] = colA[j][i];
			cnt++;
		}
	}

	for(i=0;i<n_E;i++)
	{
		if(Ctxt[0][i]!=0)
		{
			HashInputMessage[cnt] ^=(((u64)1)<<(63-cnt_aux));
		}
		cnt_aux++;
		if(cnt_aux==64){cnt++;cnt_aux=0;}
	}
	if(cnt_aux!=0){cnt++;}
	cnt_aux=0;

	COM(HashInputMessage, cnt, 512, HashResult_512);
	
	ZZ Challenge_result1, Challenge_result2;
	ZZ temp_ZZ;
	
	for(i=0;i<8;i++)
	{
		Challenge_result1 = (Challenge_result1<<64)^HashResult_512[i];
	}	
	
	for(j=0;j<cnt;j++)
	{
		HashInputMessage[j]=0;
	}	
	
	cnt = 0;
	cnt_aux = 0;
	
	temp_ZZ = Challenge_result1;
	
	cnt = 0;
	do{
		if((temp_ZZ & 0X3) == 0){zk_Ch[cnt]=0;cnt++;}
		else if((temp_ZZ & 0X3) == 1){ zk_Ch[cnt]=1;cnt++;}
		else if((temp_ZZ & 0X3) == 2){ zk_Ch[cnt]=2;cnt++;}
		temp_ZZ = (temp_ZZ >> 2);	
	}while(cnt<kappa);
	
	cnt = 0;
	
	/******************************************
	Computing Response
	******************************************/
	u64 resp_b[kappa]={0};
	u64 resp_rho[kappa][8]={0};

	u8 **resp_s1 = new u8*[kappa];
	u8 **resp_s2 = new u8*[kappa];

	u8 **resp_x1 = new u8*[kappa];
	u8 **resp_x2 = new u8*[kappa];

	for(i=0;i<kappa;i++)
	{
		resp_s1[i] = new u8[n_R];
		resp_s2[i] = new u8[n_R];

		resp_x1[i] = new u8[NGU];
		resp_x2[i] = new u8[NGU];
		
	}
	

	

	u8 resp_u[kappa][k_1]={0};
	u8 resp_g1[kappa][2*log_NGU]={0};
	u8 resp_g2[kappa][2*log_NGU]={0};
	u8 resp_e1[kappa][n_E]={0};
	u8 resp_e2[kappa][n_E]={0};
	u64 resp_c1[kappa][4]={0};
	u64 resp_c2[kappa][4]={0};
	u64 resp_c3[kappa][4]={0};
	
	u8 *resp_zerox = new u8[NGU];

	for(i=0;i<kappa;i++)
	{
		if(zk_Ch[i]==0)
		{
			resp_b[i]= message^zk_b[i];
			
			resp_rho[i][0]=zk_rho[i][ 4];resp_rho[i][1]=zk_rho[i][ 5];resp_rho[i][2]=zk_rho[i][ 6];resp_rho[i][3]=zk_rho[i][ 7];
			resp_rho[i][4]=zk_rho[i][ 8];resp_rho[i][5]=zk_rho[i][ 9];resp_rho[i][6]=zk_rho[i][10];resp_rho[i][7]=zk_rho[i][11];
		
			for(j=0;j<n_R;j++)
			{
				resp_s1[i][j] = zk_pirs[i][j];
			}
		
			for(j=0;j<NGU;j++)
			{
				resp_x1[i][j] = zk_tbrx[i][j];
			}
			
			for(j=0;j<(2*log_NGU);j++)
			{
				resp_g1[i][j] = zk_tbrg[i][j];
			}
			for(j=0;j<n_E;j++)
			{
				resp_e1[i][j] = zk_sigmare[i][j];
			}
			
			for(j=0;j<n_R;j++){resp_s2[i][j]=extSig[zk_pi[i][j]];}

			for(j=0;j<n_E;j++){resp_e2[i][j]=extErr[i][zk_sigma[i][j]];}
						
			resp_c1[i][0]=zk_c1[i][0];resp_c1[i][1]=zk_c1[i][1];resp_c1[i][2]=zk_c1[i][2];resp_c1[i][3]=zk_c1[i][3];
			resp_c2[i][0]=zk_c2[i][0];resp_c2[i][1]=zk_c2[i][1];resp_c2[i][2]=zk_c2[i][2];resp_c2[i][3]=zk_c2[i][3];
			resp_c3[i][0]=zk_c3[i][0];resp_c3[i][1]=zk_c3[i][1];resp_c3[i][2]=zk_c3[i][2];resp_c3[i][3]=zk_c3[i][3];
		}
		
		else if(zk_Ch[i]==1)
		{
			resp_b[i] = zk_b[i];
	
			resp_rho[i][0]=zk_rho[i][ 0];resp_rho[i][1]=zk_rho[i][ 1];resp_rho[i][2]=zk_rho[i][ 2];resp_rho[i][3]=zk_rho[i][ 3];
			resp_rho[i][4]=zk_rho[i][ 8];resp_rho[i][5]=zk_rho[i][ 9];resp_rho[i][6]=zk_rho[i][10];resp_rho[i][7]=zk_rho[i][11];
			
			for(j=0;j<n_R;j++)
			{
				resp_s1[i][j] = zk_sxor[i][j];
			}
			
			for(j=0;j<NGU;j++)
			{
				resp_x1[i][j] = zk_xxor[i][j];
			}
			
			for(j=0;j<k_1;j++)
			{
				resp_u[i][j] = u_ran[j]^zk_ru[i][j];
			}
			
			for(j=0;j<(2*log_NGU);j++)
			{
				resp_g1[i][j]=zk_gxor[i][j];
			}
			
			for(j=0;j<n_E;j++)
			{
				resp_e1[i][j]=zk_exor[i][j];
			}
			
			resp_c1[i][0]=zk_c1[i][0];resp_c1[i][1]=zk_c1[i][1];resp_c1[i][2]=zk_c1[i][2];resp_c1[i][3]=zk_c1[i][3];
			resp_c2[i][0]=zk_c2[i][0];resp_c2[i][1]=zk_c2[i][1];resp_c2[i][2]=zk_c2[i][2];resp_c2[i][3]=zk_c2[i][3];
			resp_c3[i][0]=zk_c3[i][0];resp_c3[i][1]=zk_c3[i][1];resp_c3[i][2]=zk_c3[i][2];resp_c3[i][3]=zk_c3[i][3];
		}
		else if(zk_Ch[i]==2)
		{
			resp_b[i] = zk_b[i];
						
			resp_rho[i][0]=zk_rho[i][0];resp_rho[i][1]=zk_rho[i][1];resp_rho[i][2]=zk_rho[i][2];resp_rho[i][3]=zk_rho[i][3];
			resp_rho[i][4]=zk_rho[i][4];resp_rho[i][5]=zk_rho[i][5];resp_rho[i][6]=zk_rho[i][6];resp_rho[i][7]=zk_rho[i][7];
		
			
			for(j=0;j<n_R;j++)
			{
				resp_s1[i][j] = zk_rs[i][j];
			}
			for(j=0;j<NGU;j++)
			{
				resp_x1[i][j] = zk_rx[i][j];
			}
			for(j=0;j<k_1;j++)
			{
				resp_u[i][j] = zk_ru[i][j];
			}
			for(j=0;j<(2*log_NGU);j++)
			{
				resp_g1[i][j] = zk_rg[i][j];
			}
			for(j=0;j<n_E;j++)
			{
				resp_e1[i][j] = zk_re[i][j];
			}
			
			resp_c1[i][0]=zk_c1[i][0];resp_c1[i][1]=zk_c1[i][1];resp_c1[i][2]=zk_c1[i][2];resp_c1[i][3]=zk_c1[i][3];
			resp_c2[i][0]=zk_c2[i][0];resp_c2[i][1]=zk_c2[i][1];resp_c2[i][2]=zk_c2[i][2];resp_c2[i][3]=zk_c2[i][3];
			resp_c3[i][0]=zk_c3[i][0];resp_c3[i][1]=zk_c3[i][1];resp_c3[i][2]=zk_c3[i][2];resp_c3[i][3]=zk_c3[i][3];
		}
		
	}
	
	sign_time = GetTime()-sign_time;	

	cout << "done!" << endl;

	unsigned long sig_length =  sizeof(Ctxt) + sizeof(resp_x1) + sizeof(zk_Ch) + sizeof(resp_b) + sizeof(resp_rho) + sizeof(resp_s1)  + sizeof(resp_g1) + sizeof(resp_c1) + sizeof(resp_c2) + sizeof(resp_c3) + sizeof(zk_c1) + sizeof(zk_c2) + sizeof(zk_c3);


	cout << endl;
	cout << "All signing part is done!" << endl;
	cout << endl;


	


/**********************************************************
Verification Algorithm 
**********************************************************/	
	verify_time = GetTime();
	cout << endl;
	cout << "Verifying algorithm for group signature" << endl;
	cout << endl;
	cout << "V01. Compute challenge values...";
	
	u8 zk_VeriCh[kappa]={0};
	cnt = 0;
	
	FileHash(256, HashResult);
	
	HashInputMessage[cnt] = HashResult[0]; cnt++;
	HashInputMessage[cnt] = HashResult[1]; cnt++;
	HashInputMessage[cnt] = HashResult[2]; cnt++;
	HashInputMessage[cnt] = HashResult[3]; cnt++;
	
	for(i=0;i<kappa;i++)
	{
		HashInputMessage[cnt] = resp_c1[i][0]; cnt++;
		HashInputMessage[cnt] = resp_c1[i][1]; cnt++;
		HashInputMessage[cnt] = resp_c1[i][2]; cnt++;
		HashInputMessage[cnt] = resp_c1[i][3]; cnt++;
		HashInputMessage[cnt] = resp_c2[i][0]; cnt++;
		HashInputMessage[cnt] = resp_c2[i][1]; cnt++;
		HashInputMessage[cnt] = resp_c2[i][2]; cnt++;
		HashInputMessage[cnt] = resp_c2[i][3]; cnt++;
		HashInputMessage[cnt] = resp_c3[i][0]; cnt++;
		HashInputMessage[cnt] = resp_c3[i][1]; cnt++;
		HashInputMessage[cnt] = resp_c3[i][2]; cnt++;
		HashInputMessage[cnt] = resp_c3[i][3]; cnt++;
	}
	
	cnt_aux = 0;
	
	for(i=0;i<(k_E+log_NGU);i++)
	{
		for(j=0;j<q_n64;j++)
		{
			HashInputMessage[cnt] = u64Gpk_E[i][j];cnt++;
		}
	}

	cnt_aux=0;

	for(i=0;i<n_R;i++)
	{
		for(j=0;j<q_r64;j++)
		{
			HashInputMessage[cnt] = Hvk_SD[j][i];
			cnt++;
		}	
	}	

	for(i=0;i<NGU;i++)
	{
		for(j=0;j<q_r64;j++)
		{
			HashInputMessage[cnt] = colA[j][i];
			cnt++;
		}
	}

	for(i=0;i<n_E;i++)
	{
		if(Ctxt[0][i]!=0)
		{
			HashInputMessage[cnt] ^=(((u64)1)<<(63-cnt_aux));
		}
		cnt_aux++;
		if(cnt_aux==64){cnt++;cnt_aux=0;}
	}
	if(cnt_aux!=0){cnt++;}
	cnt_aux=0;

	COM(HashInputMessage, cnt, 512, HashResult_512);
	
	ZZ VeriCh_result1, VeriCh_result2;
	
	for(i=0;i<8;i++)
	{
		VeriCh_result1 = (VeriCh_result1<<64)^HashResult_512[i];
	}	
		
	for(j=0;j<cnt;j++)
	{
		HashInputMessage[j]=0;
	}	
	
	cnt = 0;
	cnt_aux = 0;
	
	temp_ZZ = VeriCh_result1;
	
	cnt = 0;
	do{
		if((temp_ZZ & 0X3) == 0X0){zk_VeriCh[cnt]=0;cnt++;}
		else if((temp_ZZ & 0X3) == 0X1){ zk_VeriCh[cnt]=1;cnt++;}
		else if((temp_ZZ & 0X3) == 0X2){ zk_VeriCh[cnt]=2;cnt++;}
		temp_ZZ = (temp_ZZ >> 2);	
	}while(cnt<kappa);
	
	cnt = 0;
	
	cout << "done!" << endl;

	for(i=0;i<kappa;i++)
	{
		if(zk_Ch[i]!=zk_VeriCh[i]){cout << i << "-th Verifying challenge is failed!" << endl; return 0;}
	}
	
	cout << "Challenge is verified!" << endl;
	cout << "V02. Verify zero-knowlege arguments...";
	vector<int> resp_pi[kappa];
	vector<int> resp_sigma[kappa];
	int wt_flag = 0, wt_flag1 = 0;
	u8 verify_encode[2*log_NGU]={0};

	srand(seed);
	for(i=0;i<kappa;i++)
	{
		RanPermGen(n_R, &(resp_pi[i]));
		RanPermGen(n_E, &(resp_sigma[i]));

	}
	
	for(i=0;i<kappa;i++)
	{
		if(zk_VeriCh[i]==0)
		{
			cnt=0;
			cnt_aux=0;

			for(j=0;j<n_R;j++)
			{
				if(resp_s1[i][j]!=0)
				{
					HashInputMessage[cnt]^=(((u64)1)<<(63-cnt_aux));
				}
				cnt_aux++;
				if(cnt_aux==64){cnt++; cnt_aux=0;}
			}
			if(cnt_aux!=0){cnt++;}
			
			cnt_aux=0;
			for(j=0;j<NGU;j++)
			{
				if(resp_x1[i][j]!=0)
				{
					HashInputMessage[cnt]^=(((u64)1)<<(63-cnt_aux));
				}
				cnt_aux++;
				if(cnt_aux==64){cnt++; cnt_aux=0;}
			}
			if(cnt_aux!=0){cnt++;}


			
			for(j=0;j<NGU;j++){resp_x2[i][j]=0;}
			resp_x2[i][resp_b[i]]=1;
	


			cnt_aux=0;
			for(j=0;j<(2*log_NGU);j++)
			{
				if(resp_g1[i][j]!=0)
				{
					HashInputMessage[cnt]^=(((u64)1)<<(63-cnt_aux));
				}
				cnt_aux++;
				if(cnt_aux==64){cnt++; cnt_aux=0;}
			}
			if(cnt_aux!=0){cnt++;}


			for(j=0;j<log_NGU;j++)
			{
				if((resp_b[i]>>(log_NGU-j-1)) & 0x1)
				{
					resp_g2[i][2*j]=0; resp_g2[i][2*j+1] = 1;
				}
				else{
					resp_g2[i][2*j]=1; resp_g2[i][2*j+1] = 0;
				}
			}
	
			
			cnt_aux=0;
			for(j=0;j<n_E;j++)
			{
				if(resp_e1[i][j]!=0)
				{
					HashInputMessage[cnt]^=(((u64)1)<<(63-cnt_aux));
				}
				cnt_aux++;
				if(cnt_aux==64){cnt++; cnt_aux=0;}
			}
			if(cnt_aux!=0){cnt++;}
			
			HashInputMessage[cnt] = resp_rho[i][0];cnt++;
			HashInputMessage[cnt] = resp_rho[i][1];cnt++;
			HashInputMessage[cnt] = resp_rho[i][2];cnt++;
			HashInputMessage[cnt] = resp_rho[i][3];cnt++;
			
			COM(HashInputMessage, cnt, 256, HashResult);
			
			if(resp_c2[i][0]!=HashResult[0]){cout << i << "-th zk=0 and  2-i:" << i << endl;cout << "error1!" << endl; return 0;}
			if(resp_c2[i][1]!=HashResult[1]){cout << i << "-th zk=0 and  2-i:" << i << endl;cout << "error1!" << endl; return 0;}
			if(resp_c2[i][2]!=HashResult[2]){cout << i << "-th zk=0 and  2-i:" << i << endl;cout << "error1!" << endl; return 0;}
			if(resp_c2[i][3]!=HashResult[3]){cout << i << "-th zk=0 and  2-i:" << i << endl;cout << "error1!" << endl; return 0;}
		
			for(j=0;j<cnt;j++)
			{
				HashInputMessage[j]=0;
			}
			
			cnt =0;
			cnt_aux =0;
			
			//starting to compute c3
			for(j=0;j<n_R;j++)
			{
				if((resp_s1[i][j]^resp_s2[i][j])!=0)	
				{	
					HashInputMessage[cnt] ^=(((u64)1)<<(63-cnt_aux));
				}
				cnt_aux++;
				if(cnt_aux==64){cnt++; cnt_aux=0;}
			}
			if(cnt_aux!=0){cnt++;}
			
			cnt_aux = 0;
			for(j=0;j<NGU;j++)
			{
				if((resp_x1[i][j]^resp_x2[i][j])!=0)	
				{	
					HashInputMessage[cnt] ^=(((u64)1)<<(63-cnt_aux));
				}
				cnt_aux++;
				if(cnt_aux==64){cnt++; cnt_aux=0;}
			}
			if(cnt_aux!=0){cnt++;}
			
			cnt_aux = 0;
			for(j=0;j<(2*log_NGU);j++)
			{
				if((resp_g1[i][j]^resp_g2[i][j])!=0)
				{	
					HashInputMessage[cnt] ^=(((u64)1)<<(63-cnt_aux));
				}
				cnt_aux++;
				if(cnt_aux==64){cnt++; cnt_aux=0;}
			}
			if(cnt_aux!=0){cnt++;}
			
			cnt_aux = 0;
			for(j=0;j<n_E;j++)
			{
				if((resp_e1[i][j]^resp_e2[i][j])!=0)
				{	
					HashInputMessage[cnt] ^=(((u64)1)<<(63-cnt_aux));
				}
				cnt_aux++;
				if(cnt_aux==64){cnt++; cnt_aux=0;}
			}
		
			if(cnt_aux!=0){cnt++;}
			
			HashInputMessage[cnt] = resp_rho[i][4];cnt++;
			HashInputMessage[cnt] = resp_rho[i][5];cnt++;
			HashInputMessage[cnt] = resp_rho[i][6];cnt++;
			HashInputMessage[cnt] = resp_rho[i][7];cnt++;
			
			COM(HashInputMessage, cnt, 256, HashResult);
			
			if(resp_c3[i][0]!=HashResult[0]){cout << i << "-th zk=0 and  3-i: 0: error1!" << endl; return 0;}
			if(resp_c3[i][1]!=HashResult[1]){cout << i << "-th zk=0 and  3-i: 1: error1!" << endl; return 0;}
			if(resp_c3[i][2]!=HashResult[2]){cout << i << "-th zk=0 and  3-i: 2: error1!" << endl; return 0;}
			if(resp_c3[i][3]!=HashResult[3]){cout << i << "-th zk=0 and  3-i: 3: error1!" << endl; return 0;}
			
			for(j=0;j<cnt;j++)
			{
				HashInputMessage[j]=0;
			}
			
			cnt=0;
			cnt_aux=0;

			wt_flag=0; wt_flag1=0;

			for(j=0;j<n_R;j++)
			{
				if(resp_s2[i][j]==1) wt_flag++;
				
			}
			if(wt_flag != t_R){cout << "wt_flag: " << wt_flag << endl; cout << i << "-th s problem" << endl; return 0;}

			wt_flag =0;

			for(j=0;j<NGU;j++)
			{
				if((j==resp_b[i]) && (resp_x2[i][j]==0))
				{
					cout << "problem x" << endl; return 0;
				}
				if((j!=resp_b[i]) && (resp_x2[i][j]!=0))
				{
					cout << "problem x" << endl; return 0;
				}
			}
			
			for(j=0;j<n_E;j++)
			{
				if(resp_e2[i][j]==1) wt_flag++;
			}
			
			if(wt_flag != t_E){cout << "wt_flag:" << wt_flag << endl; cout << "problem e" << endl; return 0;}
			
			wt_flag = 0;
			
			for(j=0;j<log_NGU;j++)
			{
				if((resp_b[i]>>(log_NGU-j-1)) & 0x1)
				{
					verify_encode[2*j]=0; verify_encode[2*j+1]=1;
				}
				else{
					verify_encode[2*j]=1; verify_encode[2*j+1]=0;
				}
			}
			
			for(j=0;j<(2*log_NGU);j++)
			{
				if(verify_encode[j]!=resp_g2[i][j])
				{
					cout << "Problem g! " << endl; return 0;
				}
			}
		}
		else if(zk_VeriCh[i]==1)
		{

			cnt = 0;
			cnt_aux = 0;

			HashInputMessage[cnt] = resp_b[i];cnt++;


			
			for(j=0;j<ceil_nRD2;j++)
			{
				HashInputMessage[cnt] = (((u64)resp_pi[i][j*2])<<32)^resp_pi[i][j*2+1];
			       cnt++;
			
			}
			
			for(j=0;j<ceil_nED2;j++)
			{
				HashInputMessage[cnt] = (((u64)resp_sigma[i][j*2])<<32)^resp_sigma[i][j*2+1];cnt++;
			}
			
			
			for(k=0;k<q_r64;k++)
			{
				u64Result1[k]=0;
				u64Result2[k]=0;
				Finalu64Result[k]=0;
			}
			
			for(j=0;j<n_R;j++)
			{
				if(resp_s1[i][j]==1)
				{
					for(k=0;k<q_r64;k++)
					{
						u64Result1[k] ^= Hvk_SD[k][j];
					}
				}
			}


			for(j=0;j<NGU;j++)
			{
				if(resp_x1[i][j]==1)
				{
					for(k=0;k<q_r64;k++)
					{
						u64Result2[k] ^= colA[k][j];
					}

				}

			}


			for(k=0;k<q_r64;k++){
				Finalu64Result[k] = (u64Result1[k]^u64Result2[k]);
			}
		
			cnt_aux=0;

			for(k=0;k<q_r64;k++)
			{
				HashInputMessage[cnt] = Finalu64Result[k];cnt++;
			}
			
			for(k=0;k<q_r64;k++)
			{
				u64Result1[k]=0;
				u64Result2[k]=0;
				Finalu64Result[k]=0;
			}

				
			for(j=0;j<q_n64;j++)
			{
				u64Result3[j]=0;
			}
	
			
			for(j=0;j<k_1;j++)
			{
				if(resp_u[i][j]==1)
				{
					for(k=0;k<q_n64;k++) u64Result3[k] ^= u64Gpk_E[j][k];
				}
			}

			for(j=0;j<(2*log_NGU);j++)
			{
				if(resp_g1[i][j]==1)
				{
					for(k=0;k<q_n64;k++) u64Result3[k] ^= u64Gpk_E[k_1 + j][k];
				}
			}	

			index = 0;

			for(j=0;j<q_n64;j++)
			{
				index = 64*j;
	
				for(k=0;k<64;k++)
				{
					if(resp_e1[i][index+k]!=0) u64Result3[j]^=mask[k];
				} 
			}
		
			index = 0;
			
			for(j=0;j<q_n64;j++)
			{
				index = 64*j;
	
				for(k=0;k<64;k++)
				{
					if(Ctxt[0][index+k]!=0) u64Result3[j]^=mask[k];
				} 
			}
		
			index = 0;

					
			for(j=0;j<q_n64;j++)
			{
				HashInputMessage[cnt] = u64Result3[j];cnt++;
		
			}


			for(j=0;j<q_n64;j++)
			{
				u64Result3[j]=0;
			}

			HashInputMessage[cnt] = resp_rho[i][0];cnt++;	
			HashInputMessage[cnt] = resp_rho[i][1];cnt++;
			HashInputMessage[cnt] = resp_rho[i][2];cnt++;
			HashInputMessage[cnt] = resp_rho[i][3];cnt++;


			COM(HashInputMessage, cnt, 256, HashResult);
			
			if(resp_c1[i][0]!=HashResult[0]){cout << i << "-th zk=1 and 1-i: 0: error1!" << endl; return 0;}
			if(resp_c1[i][1]!=HashResult[1]){cout << i << "-th zk=1 and 1-i: 1: error1!" << endl; return 0;}
			if(resp_c1[i][2]!=HashResult[2]){cout << i << "-th zk=1 and 1-i: 2: error1!" << endl; return 0;}
			if(resp_c1[i][3]!=HashResult[3]){cout << i << "-th zk=1 and 1-i: 3: error1!" << endl; return 0;}
		
			for(j=0;j<cnt;j++)
			{
				HashInputMessage[j]=0;
			}

			cnt=0;
			cnt_aux=0;
			
			//Start to compute c3
			for(j=0;j<n_R;j++)
			{
				temp_u8array[j]= resp_s1[i][resp_pi[i][j]];
			} 
			cnt_aux=0;
			for(j=0;j<n_R;j++)
			{
				if(temp_u8array[j]!=0)
				{	HashInputMessage[cnt] ^=(((u64)1)<<(63-cnt_aux));}
				cnt_aux++;
				if(cnt_aux==64){cnt++; cnt_aux=0;}
			}
			if(cnt_aux!=0){cnt++;}
			cnt_aux=0;
			
			for(j=0;j<NGU;j++)
			{
				temp_u8array[j]= resp_x1[i][resp_b[i]^j];
			} 
			cnt_aux=0;
			for(j=0;j<NGU;j++)
			{
				if(temp_u8array[j]!=0)
				{	HashInputMessage[cnt] ^=(((u64)1)<<(63-cnt_aux));}
				cnt_aux++;
				if(cnt_aux==64){cnt++; cnt_aux=0;}
			}
			if(cnt_aux!=0){cnt++;}
			cnt_aux=0;
	
			for(j=0;j<log_NGU;j++)
			{
				if((resp_b[i]>>(log_NGU-j-1)) & 0x1)
				{
					temp_u8array[2*j] = resp_g1[i][2*j+1];
					temp_u8array[2*j+1] = resp_g1[i][2*j];
				}
				else{
					temp_u8array[2*j] = resp_g1[i][2*j];
					temp_u8array[2*j+1] = resp_g1[i][2*j+1];
				
				}
			}
		
			for(j=0;j<(2*log_NGU);j++)
			{
				if(temp_u8array[j]!=0)
				{	HashInputMessage[cnt] ^=(((u64)1)<<(63-cnt_aux));}
				cnt_aux++;
				if(cnt_aux==64){cnt++; cnt_aux=0;}
			}
			if(cnt_aux!=0){cnt++;}
			cnt_aux=0;
			
			for(j=0;j<n_E;j++)
			{
				temp_u8array[j]= resp_e1[i][resp_sigma[i][j]];
			} 
			cnt_aux=0;
			for(j=0;j<n_E;j++)
			{
				if(temp_u8array[j]!=0)
				{	HashInputMessage[cnt] ^=(((u64)1)<<(63-cnt_aux));}
				cnt_aux++;
				if(cnt_aux==64){cnt++; cnt_aux=0;}
			}
			if(cnt_aux!=0){cnt++;}
			cnt_aux=0;
			
		
			HashInputMessage[cnt] = resp_rho[i][4];
			cnt++;
			HashInputMessage[cnt] = resp_rho[i][5];
			cnt++;
			HashInputMessage[cnt] = resp_rho[i][6];
			cnt++;
			HashInputMessage[cnt] = resp_rho[i][7];
			cnt++;
		
			COM(HashInputMessage, cnt, 256, HashResult);
			
			if(resp_c3[i][0]!=HashResult[0]){cout << i << "-th zk=1 and 3-i: 0: error1!" << endl; return 0;}
			if(resp_c3[i][1]!=HashResult[1]){cout << i << "-th zk=1 and 3-i: 1: error1!" << endl; return 0;}
			if(resp_c3[i][2]!=HashResult[2]){cout << i << "-th zk=1 and 3-i: 2: error1!" << endl; return 0;}
			if(resp_c3[i][3]!=HashResult[3]){cout << i << "-th zk=1 and 3-i: 3: error1!" << endl; return 0;}
			
			
			for(j=0;j<cnt;j++)
			{
				HashInputMessage[j]=0;
			}
	
			cnt=0;
			cnt_aux=0;
			
		}
		else if(zk_VeriCh[i]==2)
		{
			cnt = 0;
			cnt_aux = 0;
	
			HashInputMessage[cnt]=resp_b[i];cnt++;
			
			for(j=0;j<ceil_nRD2;j++)
			{
				HashInputMessage[cnt] = (((u64)resp_pi[i][j*2])<<32)^resp_pi[i][j*2+1];cnt++;
			}
				
			for(j=0;j<ceil_nED2;j++)
			{
				HashInputMessage[cnt]= (((u64)resp_sigma[i][j*2])<<32)^resp_sigma[i][j*2+1];cnt++;	
			}

			
			for(k=0;k<q_r64;k++)
			{
				u64Result1[k]=0;
				u64Result2[k]=0;
				Finalu64Result[k]=0;
			}
			
			for(j=0;j<n_R;j++)
			{
				if(resp_s1[i][j]==1)
				{	
					for(k=0;k<q_r64;k++){
						u64Result1[k] ^= Hvk_SD[k][j];
					}
				}
			}

			for(j=0;j<NGU;j++)
			{	
				if(resp_x1[i][j]==1)
				{
					for(k=0;k<q_r64;k++){
						u64Result2[k]^=colA[k][j];
					}
				}
			}			

			for(k=0;k<q_r64;k++) {Finalu64Result[k] = (u64Result1[k]^u64Result2[k]);}		
			cnt_aux=0;
			
			for(k=0;k<q_r64;k++) 
			{
				HashInputMessage[cnt] = Finalu64Result[k];
				cnt++;
			}
			
			for(k=0;k<q_r64;k++)
			{
				u64Result1[k]=0;
				u64Result2[k]=0;
				Finalu64Result[k]=0;
			}
			

			for(j=0;j<q_n64;j++)
			{
				u64Result3[j]=0;
			}

			for(j=0;j<k_1;j++)
			{	
				if(resp_u[i][j]==1)
				{
					for(k=0;k<q_n64;k++) u64Result3[k] ^= u64Gpk_E[j][k];
				}
			}	


			for(j=0;j<(2*log_NGU);j++)
			{
				if(resp_g1[i][j]==1)
				{
					for(k=0;k<q_n64;k++) u64Result3[k] ^= u64Gpk_E[k_1+j][k];
				}
			}

			index = 0;

			for(j=0;j<q_n64;j++)
			{
				index = 64*j;

				for(k=0;k<64;k++)
				{
					if(resp_e1[i][index+k]!=0) u64Result3[j]^=mask[k];
				} 
			}
		
			index = 0;

			for(j=0;j<q_n64;j++)
			{
				HashInputMessage[cnt] = u64Result3[j];cnt++;
			}

			for(j=0;j<q_n64;j++)
			{
				u64Result3[j]=0;
			}
			
			HashInputMessage[cnt] = resp_rho[i][0];cnt++;
			HashInputMessage[cnt] = resp_rho[i][1];cnt++;
			HashInputMessage[cnt] = resp_rho[i][2];cnt++;
			HashInputMessage[cnt] = resp_rho[i][3];cnt++;
		
			COM(HashInputMessage, cnt, 256, HashResult);
			
			if(resp_c1[i][0]!=HashResult[0]){cout << i << "-th zk=2 and 1-i: 0: error1!" << endl; return 0;}
			if(resp_c1[i][1]!=HashResult[1]){cout << i << "-th zk=2 and 1-i: 1: error1!" << endl; return 0;}
			if(resp_c1[i][2]!=HashResult[2]){cout << i << "-th zk=2 and 1-i: 2: error1!" << endl; return 0;}
			if(resp_c1[i][3]!=HashResult[3]){cout << i << "-th zk=2 and 1-i: 3: error1!" << endl; return 0;}
			
			for(j=0;j<cnt;j++)
			{
				HashInputMessage[j]=0;
			}
			
			cnt=0;
			cnt_aux=0;
			
			for(j=0;j<n_R;j++)
			{
				temp_u8array[j]= resp_s1[i][resp_pi[i][j]];
			} 
			cnt_aux=0;
			for(j=0;j<n_R;j++)
			{
				if(temp_u8array[j]!=0)
				{	HashInputMessage[cnt] ^=(((u64)1)<<(63-cnt_aux));}
				cnt_aux++;
				if(cnt_aux==64){cnt++; cnt_aux=0;}
			}
			if(cnt_aux!=0){cnt++;}
			cnt_aux=0;
			
			for(j=0;j<NGU;j++)
			{
				temp_u8array[j]= resp_x1[i][resp_b[i]^j];
			} 
			cnt_aux=0;
			for(j=0;j<NGU;j++)
			{
				if(temp_u8array[j]!=0)
				{	HashInputMessage[cnt] ^=(((u64)1)<<(63-cnt_aux));}
				cnt_aux++;
				if(cnt_aux==64){cnt++; cnt_aux=0;}
			}
			if(cnt_aux!=0){cnt++;}
			cnt_aux=0;
	
			for(j=0;j<log_NGU;j++)
			{
				if((resp_b[i]>>(log_NGU-j-1)) & 0x1)
				{
					temp_u8array[2*j] = resp_g1[i][2*j+1];
					temp_u8array[2*j+1] = resp_g1[i][2*j];
				}
				else{
					temp_u8array[2*j] = resp_g1[i][2*j];
					temp_u8array[2*j+1] = resp_g1[i][2*j+1];
				}
			}
		
			for(j=0;j<(2*log_NGU);j++)
			{
				if(temp_u8array[j]!=0)
				{	HashInputMessage[cnt] ^=(((u64)1)<<(63-cnt_aux));}
				cnt_aux++;
				if(cnt_aux==64){cnt++; cnt_aux=0;}
			}
			if(cnt_aux!=0){cnt++;}
			cnt_aux=0;
			
			for(j=0;j<n_E;j++)
			{
				temp_u8array[j]= resp_e1[i][resp_sigma[i][j]];
			} 
			cnt_aux=0;
			for(j=0;j<n_E;j++)
			{
				if(temp_u8array[j]!=0)
				{	HashInputMessage[cnt] ^=(((u64)1)<<(63-cnt_aux));}
				cnt_aux++;
				if(cnt_aux==64){cnt++; cnt_aux=0;}
			}
			if(cnt_aux!=0){cnt++;}
			cnt_aux=0;
			
		
			HashInputMessage[cnt] = resp_rho[i][4];cnt++;
			HashInputMessage[cnt] = resp_rho[i][5];cnt++;
			HashInputMessage[cnt] = resp_rho[i][6];cnt++;
			HashInputMessage[cnt] = resp_rho[i][7];cnt++;
		
			COM(HashInputMessage, cnt, 256, HashResult);
			
			if(resp_c2[i][0]!=HashResult[0]){cout << i << "-th zk=2 and 2-i: 0: error1!" << endl; return 0;}
			if(resp_c2[i][1]!=HashResult[1]){cout << i << "-th zk=2 and 2-i: 1: error1!" << endl; return 0;}
			if(resp_c2[i][2]!=HashResult[2]){cout << i << "-th zk=2 and 2-i: 2: error1!" << endl; return 0;}
			if(resp_c2[i][3]!=HashResult[3]){cout << i << "-th zk=2 and 2-i: 3: error1!" << endl; return 0;}
			
			for(j=0;j<cnt;j++)
			{
				HashInputMessage[j]=0;
			}
	
			cnt=0;
			cnt_aux=0;		
		}
	}
	
	cout << "done!" << endl;
	verify_time = GetTime()-verify_time;
	cout << "Verification succeeds!" << endl;
	
	
	open_time = GetTime();
	cout << endl;
	cout << "Opening algorithm for group signature" << endl;
	cout << endl;
	
	cout << "O01. Decrypt the ciphertext in the singature...";
	long OutputM=0; 
	int FinalResult=0;
	
	OutputM = MDec(S_E, Gsk_E, Hsk_E, P_E, irrPoly_E, genPoly_E, alpha_E, invPoly_alpha_E, SqrtMatrix_E, transG_E, Ctxt, n_E, k_E, m_E, k_1, log_NGU, t_E);
	
	cout << "done!" << endl;
	
	open_time = GetTime()-open_time;
	
	if(message == OutputM)
	{
		cout << "The decryption is correct!" << endl;
		cout << "The illegal user for this signature is " << OutputM << "." <<  endl;
		cout << "The illegal user for this signature is " << message << "." <<  endl;
	}
		
	cout << endl << "Key Generation time for " << NGU << " users: " << keygen_time << endl;
	cout << "Signing time: " << sign_time << endl;
	cout << "Verifying time: " << verify_time << endl;
	cout << "Opening time: " << open_time << endl;
	cout << "GPK: " << gpk_length << " B" << endl;
	cout << "GSK: " << gsk_length << " B" << endl;
	cout << "SIG: " << sig_length << " B" << endl;


	for(i=0;i<kappa;i++)
	{
		delete[] zk_rs[i];
		delete[] zk_sxor[i];
		delete[] zk_pirs[i];
		delete[] zk_rx[i];
		delete[] zk_xxor[i];
		delete[] zk_tbrx[i];
		delete[] resp_s1[i];
		delete[] resp_s2[i];
		delete[] resp_x1[i];
		delete[] resp_x2[i];
	}


	delete[] alpha_E;
	delete[] invPoly_alpha_E;
	delete[] zk_rs;
	delete[] zk_sxor;
	delete[] zk_pirs;
	delete[] zk_rx;
	delete[] zk_xxor;
	delete[] zk_tbrx;
	delete[] extSig;	
	delete[] resp_s1;
	delete[] resp_s2;
	delete[] resp_x1;
	delete[] resp_x2;
	delete[] resp_zerox;
	delete[] temp_u8array;
	delete[] HashInputMessage;


	return 0;
	
	
	
	
}



