#include<iostream>
#include"Vec_ZZ_p.h"
#include"Mat_ZZ_p.h"
#include"123.h"
#include"pke_api.h"
#include<vector>
#include<ctime>
#include<cassert>
using namespace std;
const int N = 257;
#define PK_LEN N * (N + 1) * (N + 1)
#define SK_LEN N
#define N_Add_1_Square 66564
#define N_Add_1 258
#define N_Mul_N_Add_1 66306
typedef struct Poly_ZZ_p
{
	int deg; 
	unsigned char poly[N];
}Poly;//deg不用管它

int generate_Matrix(Mat_ZZ_p& A,Vec_ZZ_p& V)
{
loop:
	int a = 1;
	srand(time(0) + a);
	//产生一个可逆的矩阵	
	for(int i = 0; i < A.getRow();i++)
	{
		for(int j = 0; j < A.getCol();j++)
		{
			int c = rand() % 3;
			A.put(i,j,c);
		}
	}
	if(det(A) == 0)
	{
		a++;
		goto loop;
	}
		
	//产生一个随机的向量
	for(int i = 0;i < V.getlength();i++)
	{
		int b = rand() % 3;
		V.put(i,b);
	}
	
	return 0;
}
/**********************function:读入可逆矩阵B，向量V，计算A_X，即计算L2仿射函数!第一步！！！！！！*************************************/
Mat_ZZ_p L2_Func_A_X(Mat_ZZ_p& A,Vec_ZZ_p& V)
{
	Mat_ZZ_p A_X(N, N + 1);	
	for(int i = 0; i < A.getRow();i++)
	{
		for(int j = 0; j < A.getCol();j++)
			A_X.put(i,j,A.elem(i,j));
		A_X.put(i, A_X.getCol() - 1,V[i]);
	}
	return A_X;
}

/***************function:计算X^3及 X^27,,A_X3_Sum为输出矩阵的值***********************************************************************/
/***************input:矩阵A_X为A+V1这个矩阵，*****************************************************************
******************(2N-2）*N的x^i mod fx的多项式，i>=N,(i=257--3*256,i=257对应矩阵第0行，i=3*256对应矩阵第511行)，
*******************A_X3_Sum为最终计算的矩阵的和*******************************************************************/
void X3_Sum_Calc(Mat_ZZ_p& A_X, Mat_ZZ_p& Xi_mod_Irredfx, Mat_ZZ_p& A_X3_Sum)
{
	Mat_ZZ_p A1(N, N + 1);
	//先把A_X的前86行分别放在A_X3_Sum的第3*i行
	for(int i = 0; i < 86;i++)
	{
		for(int j = 0;j < N + 1;j++)
			A_X3_Sum.put(3 * i,j,A_X.elem(i,j));
	}
	for(int i = 86;i < N;i++)
	{
		Poly y = {0,{0}};
		for(int k = 0;k < N; k++)
			y.poly[k] = Xi_mod_Irredfx.elem(3 * i - N, k);

		for(int row = 0;row < N;row++)
		{
			for(int col = 0;col < N + 1;col++)
			{
				if(y.poly[row] == 0)continue;
				else if(y.poly[row] == ONE)
					A1.put(row, col, A_X.elem(i, col));
				else if(y.poly[row] == TWO)
					A1.put(row, col, y.poly[row] * A_X.elem(i, col));
			}
				
		}			
		A_X3_Sum += A1;
		/*cout << "多项式y为"<< y << endl;*/
		A1.clear();
	}
	//output_Inv_M_V(A_X3_Sum,"A_X3.txt");
	//cout << "矩阵A_X3_Sumy为"<< A_X3_Sum << endl;	
}

/***************function:计算 X^27,A_X27_Sum为输出矩阵的值*********************************************************/
/***************input:矩阵A_X为A+V1这个矩阵，*****************************************************************
******************N*N的x^27i mod fx的多项式,(i=0--256,x^27i mod irredfx对应矩阵第i行
*******************A_X3_Sum为最终计算的矩阵的和*******************************************************************/
void X27_Sum_Calc(Mat_ZZ_p A_X, Mat_ZZ_p& X_27imod_Irredfx, Mat_ZZ_p& A_X27_Sum)
{
	Mat_ZZ_p A1(N, N + 1);
	//先把A_X的前10行分别放在A_X27_Sum的第27*i行
	for(int i = 0; i < 10;i++)
	{
		for(int j = 0;j < N + 1;j++)
			A_X27_Sum.put(27 * i, j, A_X.elem(i,j));
	}

	for(int i = 10;i < N;i++)
	{
		Poly y = {0,{0}};
		for(int k = 0;k < N; k++)
			y.poly[k] = X_27imod_Irredfx.elem(i, k);

		for(int row = 0;row < N;row++)
		{
			for(int col = 0;col < N + 1;col++)
			{
				if(y.poly[row] == 0) continue;
				else if(y.poly[row] == 1)
					A1.put(row, col, A_X.elem(i, col));
				else if(y.poly[row] == 2)
					A1.put(row, col, y.poly[row] * A_X.elem(i, col));
			}				
		}			
		A_X27_Sum += A1;
		/*cout << "多项式y为"<< y << endl;*/
		A1.clear();
	}
	//output_Inv_M_V(A_X27_Sum,"A_X27.txt");
	//cout << "矩阵A_X27_Sumy为"<< A_X27_Sum << endl;	
}

/***************function:计算X^36，为F（X）这个函数，其实际为N个（N+1,N+1）的矩阵*******************************************************************/
int X30_FXCalc( Mat_ZZ_p& A_X27_Sum, Mat_ZZ_p& A_X3_Sum, Mat_ZZ_p& Xi_mod_Irredfx, vector<Mat_ZZ_p>& Total_Sum)
{
	Mat_ZZ_p M1(N + 1,N + 1);//中间变量存储矩阵
	Mat_ZZ_p M1_Sum(N + 1,N + 1);
	//k代表x^k
	int i,j,s,t;
	for(int k = 0;k < N;k++)
	{			
		for(i = 0,j = k - i;i <= k && j >= 0 && i + j == k;i++,j--)//第一个矩阵第i行 * 第二个矩阵第j行
		{
			for(int col = 0;col < N + 1;col++)
			{
				for(int line = 0;line < N + 1;line++)
				{
					if(A_X27_Sum.elem(i,col) == 0) continue;
					else if(A_X27_Sum.elem(i,col) == ONE)
						M1.put(col,line, A_X3_Sum.elem(j,line));
					else 
						M1.put(col,line, A_X27_Sum.elem(i,col) * A_X3_Sum.elem(j,line));
				}
			}						
			M1_Sum += M1;
			M1.clear();
		}	
		//cout << "122";
		Total_Sum.push_back(M1_Sum);
		//M1.clear();
		M1_Sum.clear();
	}
	//cout << "dadsa";
	Poly y = {0,{0}};
	for(int k = N;k < 2 * N - 1;k++)
	{
		Mat_ZZ_p M2_Sum(N+1,N+1);		
		for(int var = 0;var < N; var++)
			y.poly[var] = Xi_mod_Irredfx.elem(k - N, var);

		for(t = N - 1,s = k - t;s < N && t >= 1 && s + t == k;s++,t--)//第s行 * 第t行
		{
			for(int col = 0;col < N + 1;col++)
			{
				for(int line = 0;line < N + 1;line++)
				{
					if(A_X27_Sum.elem(s,col) == 0) continue;
					else if(A_X27_Sum.elem(s,col) == ONE)
						M1.put(col,line, A_X3_Sum.elem(t,line));
					else 
						M1.put(col,line, A_X27_Sum.elem(s,col) * A_X3_Sum.elem(t,line));				
				}
			}
			M2_Sum += M1;
			M1.clear();
		}
		//Total_M2.push_back(M2_Sum);
		for(int m = 0;m < N;m++)
		{
			if(y.poly[m] == 0) continue;
			else if(y.poly[m] == 1) 
				Total_Sum[m] +=  M2_Sum;
			else 
				Total_Sum[m] += y.poly[m] * M2_Sum;
		}			
		M2_Sum.clear();
	}
	return 1;
}

/***************function:生成公钥PK,PK是N个(N+1,N+1)的一个矩阵（计算L1仿射函数）************************************************************************/
/****************output:输出P0,P1,P2,...Pn-1**********************************************************/
vector<Mat_ZZ_p> L1_Function(Mat_ZZ_p& A,Vec_ZZ_p& V1,vector<Mat_ZZ_p>& X30)
{
	vector<Mat_ZZ_p> Pk;
	Pk.reserve(N);
	Mat_ZZ_p M_Sum(N+1,N+1);//中间变量存储矩阵

	for(int i = 0;i < N;i++)
	{
		for(int j = 0;j < N;j++)
			M_Sum += A.elem(i,j) * X30[j];
		M_Sum.put(N, N, M_Sum.elem(N,N) + V1[i]);
		//M_Sum.elem(N,N) += V1[i];
		Pk.push_back(M_Sum);
		M_Sum.clear();
	}
	return Pk;
}
/****************function:计算私钥（p0,p1,...,p(n-1)）*********************************************************/
/****************output: 把私钥输出到一个vector中存储********************************************************/
vector<unsigned char> Get_sk(vector<Mat_ZZ_p>& Pk )
{
	vector<unsigned char> Sk;
	Sk.reserve(N);
	unsigned char sum1 = 0;
	for(int i = 0;i < N;i++)
	{
		for(int j = 0;j < N + 1;j++)
			sum1 = (sum1 + Pk[i].elem(j,j)) % THREE;
			//sum += Pk[i][j][j];
		Sk.push_back(sum1);
		sum1 = 0;
	}
	return Sk;
}
/**************input:输入多项式Ymod3(必须mod3),（2N-2）*N的x^i mod fx的多项式，i>=N,(i=257--3*256,i=257对应矩阵第0行，i=3*256对应矩阵第511行)
********************************Y3i是一个空的N*N的矩阵*********************************************************************/
/**************output:Y^3^0,Y^3^1,...,Y^3^256modfx的一个矩阵*****************************************************************/
int PolyY_3Mod_IrredPoly(Poly& Y, Mat_ZZ_p& Xi_modIrred, Mat_ZZ_p& Y3i )//Y3i为一个N*N的空矩阵
{
	Poly V_Res = {0,{0}};
	for(int k = 1;k < N;k++)
	{
		for(int i = 0; i < 86;i++)
			V_Res.poly[3 * i] = Y.poly[i];
		for(int i = 86;i < N;i++)
		{
			if(Y.poly[i] == 0) continue;
			for(int col = 0;col < N;col++)
			{
				if(Y.poly[i] == 1)
					V_Res.poly[col] = (V_Res.poly[col] + Xi_modIrred.elem(3 * i - N, col)) % THREE;
				else
				{
					switch(Xi_modIrred.elem(3 * i - N,col))
					{
						case 0: break;
						case 1:
							V_Res.poly[col] = (V_Res.poly[col] + TWO) % 3;break;
						case 2:
							V_Res.poly[col] = (V_Res.poly[col] + ONE) % 3;break;
					}			
				}
					//V_Res.poly[col] = (V_Res.poly[col] + Y.poly[i] * Xi_modIrred.elem(3 * i - N,col)) % THREE;				
			}
		}
		for(int j = 0;j < N;j++)
		{
			Y.poly[j] = V_Res.poly[j];
			Y3i.put(k,j,V_Res.poly[j]);			
		}
		memset(&V_Res,0,sizeof(V_Res));
	}
	return 1;
}
//int PolyY_3Mod_IrredPoly(Poly& Y, Mat_ZZ_p& Xi_modIrred, Mat_ZZ_p& Y3i )//Y3i为一个N*N的空矩阵
//{
//	Poly V_Res = {0,{0}};
//	for(int k = 1;k < N;k++)
//	{
//		for(int i = 0; i < 86;i++)
//			V_Res.poly[3 * i] = Y.poly[i];
//		for(int i = 86;i < N;i++)
//		{
//			if(Y.poly[i] == 0) continue;
//			for(int col = 0;col < N;col++)
//			{
//				if(Y.poly[i] == 1)
//					V_Res.poly[col] = (V_Res.poly[col] + Xi_modIrred.elem(3 * i - N, col)) % THREE;
//				else
//					V_Res.poly[col] = (V_Res.poly[col] + Y.poly[i] * Xi_modIrred.elem(3 * i - N,col)) % THREE;				
//			}
//			//V_Res += Y.poly[i] * Xi_modIrred[3 * i - N];
//		}
//		for(int j = 0;j < N;j++)
//		{
//			Y.poly[j] = V_Res.poly[j];
//			Y3i.put(k,j,V_Res.poly[j]);			
//		}
//		memset(&V_Res,0,sizeof(V_Res));
//	}
//	return 1;
//}
/*******************function:计算多项式a*b mod Irredpoly的结果,结果存在Res中，Res输入的时候需初始化：Poly Res = {0,{0}};********************/
int Poly_Mul_Poly(Poly& a, Poly& b, Mat_ZZ_p& Xi_modIrred, Poly& Res)
{
	unsigned char* c = new unsigned char[2 * N - 1]();//初始化为0
	/*for(int k = 0;k < 2 * N - 1;k++)
	{
		for(int i = 0;i <= k && i < N && (k - i < N);i++)
		{
			if(a.poly[i] == 0 || b.poly[k - i] == 0)continue;
			else
				c[k] = (c[k] + a.poly[i] * b.poly[k - i]) % 3;
		}		
	}*/
	for(int i = 0;i < N;i++)
	{
		if(a.poly[i] == 0)continue;
		for(int j = 0;j < N;j++)
		{
			if(b.poly[j] == 0)continue;
			else
				c[i + j] = (c[i + j] + a.poly[i] * b.poly[j]) % THREE;
		}
	}

	for(int i = 0;i < N;i++)
		Res.poly[i] = c[i];
	for(int i = N;i < 2 * N - 1;i++)
	{
		if(c[i] == 0 )continue;
		for(int j = 0;j < N;j++)
		{
			if( Xi_modIrred.elem(i - N, j) == 0)continue;
			else
			{	
				if(c[i]==1)
				    Res.poly[j] = (Res.poly[j] + Xi_modIrred.elem(i - N, j)) % THREE;	
				else
			        switch(Xi_modIrred.elem(i - N, j))
					{
						case 0: break;
						case 1:
							Res.poly[j] = (Res.poly[j] + TWO ) % THREE;break;
						case 2:
							Res.poly[j] = (Res.poly[j] + ONE ) % THREE;break;
					}
			}
				//Res.poly[j] = (Res.poly[j] + c[i] * Xi_modIrred.elem(i - N, j)) % 3;
		}	
	}
	/*for(int i = N;i < 2 * N - 1;i++)
	{
		for(int j = 0;j < N;j++)
		{
			if(c[i] == 0 || Xi_modIrred.elem(i - N, j) == 0)continue;
			else
				Res.poly[j] = (Res.poly[j] + c[i] * Xi_modIrred.elem(i - N, j)) % THREE;
		}	
	}*/
	delete[] c;
	return 1;
}
/*******************function:计算上面的多项式Y^e mod IrredPoly结果，e已经分解在123.h文件中，只需将Mat_ZZ_p Y3i中对应项相乘就ok了***********/
/***************************note:Final_Res这个多项式输入的时候也要初始化*****************************************************************/
/************************Output:最终的结果就是Y^e***********************************************************************/
int ComposeCompute(Mat_ZZ_p& Y3i, Mat_ZZ_p& Xi_modIrred, Poly& Final_Res)//Xi_modIrred为（2N-2）*N矩阵，Y3i为一个N*N矩阵
{
	Poly aa = {0,{0}};
	Poly bb = {0,{0}};	
	for(int col = 0;col < N;col++)
		Final_Res.poly[col] = Y3i.elem(index[0],col);

	for(int i = 1;i < 129;i++)//129是123.h中index的个数
	{
		for(int col = 0;col < N;col++)
		{		
			aa.poly[col] = Final_Res.poly[col] ;
			bb.poly[col] = Y3i.elem(index[i],col);		
		}
		memset(&Final_Res,0,sizeof(Final_Res));//清空Final_Res
		Poly_Mul_Poly(aa, bb, Xi_modIrred, Final_Res);	
	}		
	return 1;
}
/*************************多项式模运算***********************************************************************/
/****************function:加密一个N长的明文，输出一个N长的密文**********************************************/
Vec_ZZ_p MultiVar_Enc(Vec_ZZ_p& Plaintext,vector<Mat_ZZ_p>& Px)
{
	Vec_ZZ_p chiper(N);
	unsigned char c = 0;//1bit密文
	cout << "产生的密文为："<<endl;
	for(int  i = 0;i < N;i++ )
	{
		for(int row = 0;row < N;row++)
		{
			for(int col = row + 1;col < N;col++)
				c = (c + ( /*Px[i].elem(row, col) +*/ Px[i].elem(col, row)) * Plaintext[row] * Plaintext[col] ) % THREE;
			c = (c + ( /*Px[i].elem(row,N) +*/ Px[i].elem(N,row) ) * Plaintext[row] ) % THREE;
			//c += ( Px[i][row][N] + Px[i][N][row] ) * Plaintext[row];
		}
		cout << (int)c << " ";
		chiper.put(i,c);
		c = 0;
	}
	return chiper;	
}
/********************函数L1及逆函数L1_Inc*************************************************************/
/**************input:可逆阵A,对应的明文输入Var_input,随机产生的向量Var*******************************/
/**************output:L1函数之后产生的向量结果******************************************************/
Vec_ZZ_p L1_function(Mat_ZZ_p& A, Vec_ZZ_p& Input,Vec_ZZ_p& V1)
{
	return A * Input + V1;
}
Vec_ZZ_p L1_Inv_function(Mat_ZZ_p& A_Inv,Vec_ZZ_p& Input,Vec_ZZ_p& V1)
{
	return  A_Inv * (Input - V1);
}
/**************function:函数L2及逆函数L2_Inv*************************************************************/
/**************input:可逆阵A,对应的明文输入Var_input,随机产生的向量Var**********************************/
/**************output:L2函数之后产生的向量结果**********************************************************/
Vec_ZZ_p L2_function(Mat_ZZ_p& B, Vec_ZZ_p& Input,Vec_ZZ_p& V2)
{
	return B * Input + V2;
}
Vec_ZZ_p L2_Inv_function(Mat_ZZ_p& B_Inv,Vec_ZZ_p& Input,Vec_ZZ_p& V2)
{
	return B_Inv * (Input - V2);
}

/*****************function:解密出来两个N长的密文******************************************************************************/
int MultiVar_Dec(Vec_ZZ_p& chiper, vector<unsigned char>& sk,Mat_ZZ_p& A_Inv, Vec_ZZ_p& V1, Mat_ZZ_p& B_Inv, Vec_ZZ_p& V2,
											Mat_ZZ_p& Xi_modIrred, vector<Vec_ZZ_p>& m)
{
	Vec_ZZ_p chiper_trans1(N);
	Vec_ZZ_p chiper_trans2(N);

	for(int i  = 0;i < N;i++)
		chiper_trans1.put(i, chiper[i] + sk[i]); 
	chiper_trans2 = L1_Inv_function(A_Inv,chiper_trans1, V1);

	Poly a = {0,{0}};
	//把向量转为多项式
	for(int j = 0; j < N;j++)
		a.poly[j] = chiper_trans2[j];
	//求a^e mod IrredPoly
	Poly b1 = {0,{0}};
	Mat_ZZ_p Y3i(N,N);
	PolyY_3Mod_IrredPoly(a, Xi_modIrred, Y3i);
	ComposeCompute(Y3i, Xi_modIrred, b1);
	//b1 = PowerMod(a,e,IrredPoly_fx);与上面等价，上面自己写的，这是库里的
	Poly b2 = {0,{0}};
	for(int i = 0;i < N;i++)
		b2.poly[i] = (THREE - b1.poly[i]) % THREE;
	//把Poly转换为Vec
	Vec_ZZ_p c1(N);
	Vec_ZZ_p c2(N);
	for(int i = 0;i < N;i++)
	{
		c1.put(i, b1.poly[i]);
		c2.put(i, b2.poly[i]);
	}

	Vec_ZZ_p m1(N);
	Vec_ZZ_p m2(N);
	m1 = L2_Inv_function(B_Inv,c1,V2);
	m2 = L2_Inv_function(B_Inv,c2,V2);

	m.push_back(m1);
	m.push_back(m2);

	return 0;

}
/****************************function:把公钥,私钥保存到文件中************************************************/
int Save_Pk(char* M_path, vector<Mat_ZZ_p>& PK)
{
	ofstream fout_Pk(M_path, ios::app);
	assert(fout_Pk);
	vector<Mat_ZZ_p>::iterator it = PK.begin();
	for(;it != PK.end();it++)
	{
		for(int i = 0;i < (*it).getRow();i++)
		{
			for(int j = 0;j < (*it).getCol();j++)
				fout_Pk << (int)((*it).elem(i,j));
		}
			
	}	
	fout_Pk.close();
	return 1;
}
int Save_Sk(char* M_path, vector<unsigned char>& sk)
{
	ofstream fout_sk(M_path, ios::app);
	assert(fout_sk);
	for(int i = 0;i < sk.size();i++)
		fout_sk << (int)(sk[i]);
	fout_sk.close();
	return 1;
}
/****************************function:读取公钥PK,是N个（N+1)*(N+1）的矩阵************************************/
int read_Pk(char* M_path, vector<Mat_ZZ_p>& Pk)
{
	Mat_ZZ_p Mat(N + 1, N + 1);	
	ifstream fin_Pk(M_path, ios::in);
	assert(fin_Pk);
	int tmp;
	for(int i = 0;i < N;i++)
	{
		for(int row = 0;row < N + 1;row++)
		{
			for(int col = 0;col < N + 1;col++)
			{
				char ch;
				fin_Pk >> ch;
				tmp = ch - '0';
				Mat.put(row,col,tmp);
			}
		}
		
		Pk.push_back(Mat);
		Mat.clear();
	}
	fin_Pk.close();
	return 1;
}
int read_Pk(char* M_path, unsigned char* pk)
{
	ifstream fin_Pk(M_path, ios::in);
	assert(fin_Pk);
	for(int i = 0;i < N * (N + 1) * (N + 1);i++)
	{

		char ch;
		fin_Pk >> ch;
		pk[i] = ch - '0';
	}
	fin_Pk.close();
	return 1;
}
/***********************function:读取私钥******************************************************************/
int read_Sk(char* M_path, vector<unsigned char>& sk)
{
	unsigned char tmp;
	ifstream fin_sk(M_path, ios::in);
	assert(fin_sk);
	for(int i = 0;i < N;i++)
	{
		char ch;
		fin_sk >> ch;
		tmp = ch - '0';
		sk.push_back(tmp);
	}
	fin_sk.close();
	return 1;		
}
int read_Sk(char* M_path, unsigned char* sk)
{
	ifstream fin_sk(M_path, ios::in);
	assert(fin_sk);
	for(int i = 0;i < N;i++)
	{
		char ch;
		fin_sk >> ch;
		sk[i] = ch - '0';
	}
	fin_sk.close();
	return 1;		
}
int handle_PK(vector<Mat_ZZ_p>& PK )
{
	for(int i = 0;i < N;i++)
	{
		//对角线变为0
		for(int j = 0;j < N + 1;j++)
			PK[i].put(j,j,0);
		//变为半三角
		for(int row = 0;row < N;row++)
		{
			for(int col = row + 1;col < N;col++)
			{
				unsigned char k = ( PK[i].elem(row, col) + PK[i].elem(col, row) ) % THREE;
				PK[i].put(row, col, 0);
				PK[i].put(col, row, k);
			}	

			unsigned char x = ( PK[i].elem(row, N) + PK[i].elem(N, row) ) % THREE;
			PK[i].put(row, N, 0);
			PK[i].put(N, row, x);
		}
	}
	return 1;
}
int pke_keygen(unsigned char *pk, unsigned char *sk)
{
	if(pk == nullptr || sk == nullptr)
		return -1;
	Mat_ZZ_p mat_A(N, N);
	Vec_ZZ_p V1(N);
	generate_Matrix(mat_A, V1);
	Mat_ZZ_p mat_B(N, N);
	Vec_ZZ_p V2(N);
	generate_Matrix(mat_B, V2);
	//逆阵
	Mat_ZZ_p A_Inv(N, N);	
	Mat_ZZ_p B_Inv(N, N);
	A_Inv = inv(mat_A);
	B_Inv = inv(mat_B);
	//矩阵向量保存到文件中
	mat_A.SaveToTxt("new Mat_A.txt");
	V1.SaveToTxt("new V1.txt");
	mat_B.SaveToTxt("new Mat_B.txt");
	V2.SaveToTxt("new V2.txt");	
	A_Inv.SaveToTxt("new Inv_A.txt");	
	B_Inv.SaveToTxt("new Inv_B.txt");

	Mat_ZZ_p Xi_modIrred(2 * N - 2, N);
	Xi_modIrred.LoadFromTxt("new Xe_mod_Irredfx.txt");
	Mat_ZZ_p X_27i_modIrred(N, N);
	X_27i_modIrred.LoadFromTxt("new X_27i_mod_Irredfx.txt");
	
	Mat_ZZ_p A_X(N, N + 1);
	A_X =  L2_Func_A_X(mat_B, V2);
	//计算A_X^3
	Mat_ZZ_p A_X3_Sum(N, N + 1);
	X3_Sum_Calc(A_X, Xi_modIrred, A_X3_Sum); 
	//计算A_X^27
	Mat_ZZ_p A_X27_Sum(N, N + 1);
	X27_Sum_Calc(A_X, X_27i_modIrred, A_X27_Sum); 
	//计算A_X^30
	vector<Mat_ZZ_p> A_X30_Sum;
	X30_FXCalc( A_X27_Sum, A_X3_Sum, Xi_modIrred, A_X30_Sum);

	vector<Mat_ZZ_p> PK;
	PK = L1_Function( mat_A, V1, A_X30_Sum);
	vector<unsigned char> SK;
	SK = Get_sk(PK);
	handle_PK(PK);
	
	Save_Pk("new pk.txt", PK);
	Save_Sk("new sk.txt", SK);
	read_Pk("new pk.txt",pk);
	read_Sk("new sk.txt",sk);
	return 0;
}
int pke_enc(unsigned char* pk, unsigned char* m, unsigned long long mlen, unsigned char* c, unsigned long long *clen)
{
	if(pk == nullptr || m == nullptr || mlen != N)
		return -1;
	unsigned char c1 = 0;//1bit密文 	
	for(int  i = 0;i < mlen; i++ )
	{
		for(int row = 0;row < N;row++)
		{
			for(int col = row + 1;col < N;col++)
				c1 = (c1 + ( /*Px[i].elem(row, col) +*/ pk[i * N_Add_1_Square + col * N_Add_1 + row ]) * m[row] * m[col] ) % THREE;
				//c = (c + ( /*Px[i].elem(row, col) +*/ Px[i].elem(col, row)) * Plaintext[row] * Plaintext[col] ) % THREE;
			c1 = (c1 + ( /*Px[i].elem(row,N) +*/ pk[i * N_Add_1_Square + N_Mul_N_Add_1 + row ]) * m[row] ) % THREE;
			//c += ( Px[i][row][N] + Px[i][N][row] ) * Plaintext[row];
		}
		//cout << (int)c1 << " ";
		c[i] = c1;
		c1 = 0;
	}
	*clen = mlen;
	return 0;	
}
int pke_dec(unsigned char* sk, unsigned char* c, unsigned long long clen, unsigned char* m,unsigned long long* mlen)
{
	if(sk == nullptr || c == nullptr || clen != N)
		return -1;
	Mat_ZZ_p A_Inv(N,N);	
	A_Inv.LoadFromTxt("new Inv_A.txt");
	Mat_ZZ_p B_Inv(N,N);	
	B_Inv.LoadFromTxt("new Inv_B.txt");	
	Vec_ZZ_p V1(N);
	V1.LoadFromTxt("new V1.txt");
	Vec_ZZ_p V2(N);
	V2.LoadFromTxt("new V2.txt");

	Mat_ZZ_p Xi_modIrred(2 * N - 2, N);
	Xi_modIrred.LoadFromTxt("new Xe_mod_Irredfx.txt");

	Vec_ZZ_p chiper_trans1(N);
	Vec_ZZ_p chiper_trans2(N);

	for(int i  = 0;i < N;i++)
		chiper_trans1.put(i, c[i] + sk[i]); 
	chiper_trans2 = L1_Inv_function(A_Inv,chiper_trans1, V1);

	Poly a = {0,{0}};
	//把向量转为多项式
	for(int j = 0; j < N;j++)
		a.poly[j] = chiper_trans2[j];
	//求a^e mod IrredPoly
	Poly b1 = {0,{0}};
	Mat_ZZ_p Y3i(N,N);
	PolyY_3Mod_IrredPoly(a, Xi_modIrred, Y3i);
	ComposeCompute(Y3i, Xi_modIrred, b1);
	//b1 = PowerMod(a,e,IrredPoly_fx);与上面等价，上面自己写的，这是库里的
	Poly b2 = {0,{0}};
	for(int i = 0;i < N;i++)
		b2.poly[i] = (THREE - b1.poly[i]) % THREE;
	//把Poly转换为Vec
	Vec_ZZ_p c1(N);
	Vec_ZZ_p c2(N);
	for(int i = 0;i < N;i++)
	{
		c1.put(i, b1.poly[i]);
		c2.put(i, b2.poly[i]);
	}

	Vec_ZZ_p m1(N);
	Vec_ZZ_p m2(N);
	m1 = L2_Inv_function(B_Inv,c1,V2);
	m2 = L2_Inv_function(B_Inv,c2,V2);

	*mlen = 2 * N;
	for(int i = 0;i < clen; i++)
		m[i] = m1[i];
	for(int i = 0;i < clen; i++)
		m[i + clen] = m2[i];
	return 0;

}
int main()
{
	unsigned char* Pk = new unsigned char[PK_LEN];
	read_Pk("new pk.txt", Pk);
	unsigned char* Sk = new unsigned char[SK_LEN];
	read_Sk("new sk.txt",Sk);
	unsigned long long mlen = N;
	unsigned long long clen;
	unsigned long long decrypt_mlen;
	unsigned char* chiper = new unsigned char[mlen];
	unsigned char* m = new unsigned char[mlen];
	for(int i = 0;i < mlen;i++)
	{
		srand(time(0)+ i + 20);
		unsigned char b = rand() % 2 + 1;
		m[i] = b;
	}
	cout << "随机产生的一组明文为："<< endl;
	cout << "[";
	for(int i = 0;i < mlen; i++)
		cout <<(int)m[i] << " ";
	cout << (int)(m[mlen - 1]) << "]" << endl;
	//加密部分	
	pke_enc(Pk, m, mlen, chiper, &clen);

	cout << "加密产生的密文为："<<endl;
	cout << "[";
	for(int i = 0;i < N; i++)
		cout <<(int)chiper[i] << " ";
	cout << (int)(chiper[N- 1]) << "]" << endl;
	cout << endl;	
	//解密部分
	unsigned char* decrypt_m = new unsigned char[2 * N];
	pke_dec(Sk, chiper, clen, decrypt_m, &decrypt_mlen);

	cout << "相应的两组解密明文为："<< endl;
	cout << "[";
	for(int i = 0;i < N; i++)
		cout <<(int)decrypt_m[i] << " ";
	cout << (int)(decrypt_m[N- 1]) << "]" << endl;
	cout << "[";
	for(int i = 0;i < N; i++)
		cout <<(int)decrypt_m[i + N] << " ";
	cout << (int)(decrypt_m[2 * N- 1]) << "]" << endl;
	//cout << decrypt_m[0] << endl;
	//cout << decrypt_m[1] << endl;
	cout << decrypt_mlen << " "<< clen<< endl;
	delete[] Pk;
	delete[] Sk;
	delete[] m;
	delete[] chiper;
	delete[] decrypt_m;
	cout << "hello world!";	
	getchar();
	
	return 0;
} 
int main2()
{
	unsigned char *pk = new unsigned char[PK_LEN];
	unsigned char *sk = new unsigned char[SK_LEN];
	pke_keygen(pk, sk);
	delete[] pk;
	delete[] sk;
	cout << "hello world!";
	getchar();	
	return 0;
} 
