#include <NTL/ZZ.h>
#include <NTL/ZZ_pX.h>
#include <NTL/ZZ_pEX.h>
#include<NTL/ZZX.h>
#include<NTL/ZZ_pXFactoring.h>
#include <NTL/vec_ZZ_p.h>
#include <NTL/mat_ZZ.h>
#include<iostream>
#include<fstream>
#include<ctime>
#include<cassert>
#include<vector>
#include"123.h"
using namespace std;
using namespace NTL;


const int N = 257;
ZZ p = to_ZZ("3");
int Get_k(vector<int>& v)
{
	ZZ one = to_ZZ("1");
	ZZ two = to_ZZ("2");
	ZZ three_256_sub_1 = power_ZZ(3,256) - one;
	for(int k = 1;k < 255;k++)
	{
		ZZ three_k_add_1 = power_ZZ(3,k) + one;
		if(GCD(three_k_add_1, three_256_sub_1) == two )			
		{
			cout << k;
			v.push_back(k);
		}			
	}
	/*vector<int>::iterator it = v.begin();
	for(;it < v.end();it++)
		cout << *it << " ";*/
	return 1;
}
/****************************8***function:产生一个可逆矩阵A,一个随机向量V**************************************
**************************** output:输出一个产生一个N*(N+1)的矩阵A_X,A_X=A+V1*******************************8**/
Mat<ZZ_p> generate_Matrix(Mat<ZZ_p>& A,Vec<ZZ_p>& V)
{
loop:
	int a = 10;
	srand(time(0) + a);
	//产生一个可逆的矩阵	
	for(int i = 0; i < A.NumRows();i++)
	{
		for(int j = 0; j < A.NumCols();j++)
		{
			int a = rand() % 3;
			A.put(i,j,to_ZZ_p(a));
		}
	}
	if(determinant(A) == 0)
	{
		a++;
		goto loop;
	}
		
	//产生一个随机的向量
	for(int i = 0;i < V.length();i++)
	{
		int b = rand() % 3;
		V.put(i,to_ZZ_p(b));
	}
	Mat<ZZ_p> A_X;	
	A_X.SetDims(N,N + 1);
	for(int i = 0; i < A.NumRows();i++)
	{
		for(int j = 0; j < A.NumCols();j++)
			A_X.put(i,j,A[i][j]);
		A_X.put(i,A_X.NumCols() - 1,V[i]);
	}
	return A_X;
}

/***************************function:把生成的可逆矩阵输出到文件***********************************************/
int output_Inv_M_V(Mat<ZZ_p>& A, Vec<ZZ_p>& V, char* M_path)
{
	ofstream fout_Inv_M(M_path, ios::app);
	assert(fout_Inv_M);
	for(int i = 0;i < A.NumRows();i++)
		fout_Inv_M << A[i];
	fout_Inv_M << V;
	fout_Inv_M.close();
	return 1;
}
int output_Inv_M_V(Mat<ZZ_p>& A, char* M_path)
{
	ofstream fout_Inv_M(M_path, ios::app);
	assert(fout_Inv_M);
	for(int i = 0;i < A.NumRows();i++)
		fout_Inv_M << A[i];
	fout_Inv_M.close();
	return 1;
}
/***************************function:从文件读取生成的可逆矩阵输出到文件***************************************/
int read_Inv_M_V(char* M_path, Mat<ZZ_p>& A,Vec<ZZ_p>& V)
{
	Vec<ZZ_p> V_tmp;
	V_tmp.SetLength(N);

	ifstream fin_Inv_M(M_path,ios::in);
	assert(fin_Inv_M);
	for(int i = 0;i < N;i++)
	{
		fin_Inv_M >> V_tmp;
		A[i] = V_tmp;
	}
	fin_Inv_M >> V;
	fin_Inv_M.close();

	return 1;
}
int read_Inv_M_V(char* M_path, Mat<ZZ_p>& A)//读N*N的矩阵
{
	Vec<ZZ_p> V_tmp;
	V_tmp.SetLength(N);

	ifstream fin_Inv_M(M_path,ios::in);
	assert(fin_Inv_M);
	for(int i = 0;i < N;i++)
	{
		fin_Inv_M >> V_tmp;
		A[i] = V_tmp;
	}
	fin_Inv_M.close();

	return 1;
}
int read_Inv_M(char* M_path, Mat<ZZ_p>& A_X)//读N*(N+1）的矩阵
{
	Vec<ZZ_p> V_tmp;
	V_tmp.SetLength(N + 1);

	ifstream fin_Inv_M(M_path,ios::in);
	assert(fin_Inv_M);
	for(int i = 0;i < N;i++)
	{
		fin_Inv_M >> V_tmp;
		A_X[i] = V_tmp;
	}
	fin_Inv_M.close();

	return 1;
}
int read_XeMod_Mat(char* M_path, Mat<ZZ_p>& A)//读(2*N - 2)*N的矩阵
{
	Vec<ZZ_p> V_tmp;
	V_tmp.SetLength(N);

	ifstream fin_Inv_M(M_path,ios::in);
	assert(fin_Inv_M);
	for(int i = 0;i < 2 * N - 2;i++)
	{
		fin_Inv_M >> V_tmp;
		A[i] = V_tmp;
	}
	fin_Inv_M.close();

	return 1;
}
/****************************function:读取公钥PK,是N个（N+1)*(N+1）的矩阵************************************/
int read_Pk(char* M_path, vector<Mat<ZZ_p> >& Pk)
{
	Vec<ZZ_p> V_tmp;
	V_tmp.SetLength(N + 1);
	Mat<ZZ_p> Mat;	
	Mat.SetDims(N + 1,N + 1);

	ifstream fin_Pk(M_path, ios::in);
	assert(fin_Pk);
	for(int i = 0;i < N;i++)
	{
		for(int j = 0;j < N + 1;j++)
		{
			fin_Pk >> V_tmp;
			Mat[j] = V_tmp;
		}
		Pk.push_back(Mat);
		clear(Mat);
	}
	fin_Pk.close();
	return 1;
}
/***********************function:读取私钥******************************************************************/
int read_Sk(char* M_path, vector<ZZ_p>& sk)
{
	ZZ_p tmp;
	ifstream fin_sk(M_path, ios::in);
	assert(fin_sk);
	for(int i = 0;i < N;i++)
	{
		fin_sk >> tmp;
		sk.push_back(tmp);
	}
	fin_sk.close();
	return 1;
		
}
/********************函数L1及逆函数L1_Inc*************************************************************/
/**************input:可逆阵A,对应的明文输入Var_input,随机产生的向量Var*******************************/
/**************output:L1函数之后产生的向量结果******************************************************/
Vec<ZZ_p> L1_function(Mat<ZZ_p>& A, Vec<ZZ_p>& Var_input,Vec<ZZ_p>& Var)
{
	return A * Var_input + Var;
}

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>& Var_input2,Vec<ZZ_p>& Var2)
{
	return B * Var_input2 + Var2;
}
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:函数Vec_to_Poly(F(X))及逆函数Poly_to_Vec**********************************************/
/**************input:向量Vec 或者多项式 Poly***********************************************************/
/**************output:多项式Poly 或者 向量Vec**********************************************************/
ZZ_pX Vec_to_Poly(Vec<ZZ_p>& Vec)
{
	ZZ_pX Poly;
	Poly.SetLength(Vec.length());
	for(int i = 0;i < Vec.length();i++)
		SetCoeff(Poly,i,Vec[i]);
		//SetCoeff(Poly,i,rep(Vec[i]));
	return Poly;
}
Vec<ZZ_p> Poly_to_Vec(ZZ_pX& Poly)//inverse of F(X)
{
	Vec<ZZ_p> Vec;
	Vec.SetLength(N);
	for(int i = 0;i <= deg(Poly);i++)
		Vec.put(i,Poly[i]);
		//Vec.put(i,to_ZZ_p(Poly.rep[i]));
	return Vec;
}
/***************function:计算X^3及 X^27***********************************************************************/
/***************input:矩阵A_X为A+V1这个矩阵，IrredPoly_fx为不可约多项式，A_X3_Sum为最终计算的矩阵的和*********/
/***************output:A_X3_Sum,A_X27_Sum为输出矩阵的值****************************************************************/
void X3_Sum_Calc(Mat<ZZ_p> A_X, ZZ_pX IrredPoly_fx, Mat<ZZ_p>& A_X3_Sum)
{
	ZZ_pX x_var;
	Mat<ZZ_p> A1;
	A1.SetDims(N,N + 1);
	//先把A_X的前86行分别放在A_X3_Sum的第3*i行
	for(int i = 0; i < 86;i++)
		A_X3_Sum[3 * i] = A_X[i];

	for(int i = 86;i < N;i++)
	{
		SetCoeff(x_var, 3 * i);
		ZZ_pX y;
		y.SetLength(N);
		y = (deg(x_var) < deg(IrredPoly_fx)) ? x_var : (x_var % IrredPoly_fx);
		//ZZ_pX y;
		//rem(y, x_var, IrredPoly_fx);// y = a%b
		for(int j = 0;j < N;j++)
			A1[j] = y[j] * A_X[i];
		A_X3_Sum += A1;
		/*cout << "多项式y为"<< y << endl;*/
		clear(x_var);	
		clear(A1);
	}
	//output_Inv_M_V(A_X3_Sum,"A_X3.txt");
	//cout << "矩阵A_X3_Sumy为"<< A_X3_Sum << endl;	
}
void X27_Sum_Calc(Mat<ZZ_p> A_X, ZZ_pX IrredPoly_fx, Mat<ZZ_p>& A_X27_Sum)
{
	ZZ_pX x_var;
	Mat<ZZ_p> A1;
	A1.SetDims(N,N + 1);
	//先把A_X的前10行分别放在A_X27_Sum的第27*i行
	for(int i = 0; i < 10;i++)
		A_X27_Sum[27 * i] = A_X[i];

	for(int i = 10;i < N;i++)
	{
		SetCoeff(x_var, 27 * i);
		ZZ_pX y;
		y.SetLength(N);
		y = (deg(x_var) < deg(IrredPoly_fx)) ? x_var : (x_var % IrredPoly_fx);
		//ZZ_pX y;
		//rem(y, x_var, IrredPoly_fx);// y = a%b
		for(int j = 0;j < N;j++)
			A1[j] = y[j] * A_X[i];
		A_X27_Sum += A1;
		/*cout << "多项式y为"<< y << endl;*/
		clear(x_var);	
		clear(A1);
	}
	//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,  ZZ_pX& IrredPoly_fx, vector<Mat<ZZ_p> >& Total_Sum)
{
	Mat<ZZ_p> M1;//中间变量存储矩阵
	M1.SetDims(N+1,N+1);	
	Mat<ZZ_p> M1_Sum;
	M1_Sum.SetDims(N+1,N+1);
	ZZ_pX x;
	//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++)
				M1[col] = A_X27_Sum[i][col] * A_X3_Sum[j];			
			M1_Sum += M1;
		}	
		//cout << "122";
		Total_Sum.push_back(M1_Sum);
		clear(M1);
		clear(M1_Sum);
	}
	//cout << "dadsa";
	for(int k = N;k < 2 * N-1;k++)
	{
		Mat<ZZ_p> M2_Sum;
		M2_Sum.SetDims(N+1,N+1);
		SetCoeff(x, k);
		ZZ_pX y;
		y.SetLength(N);
		y = (deg(x) < deg(IrredPoly_fx)) ? x : (x % IrredPoly_fx);
		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++)
				M1[col] = A_X27_Sum[s][col] * A_X3_Sum[t];
			M2_Sum += M1;
		}
		//Total_M2.push_back(M2_Sum);
		for(int m = 0;m < N;m++)
			Total_Sum[m] += y[m] * M2_Sum;
		clear(M2_Sum);
		clear(x);
	}
	return 1;
}
/***************function:计算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;//中间变量存储矩阵
	M_Sum.SetDims(N+1,N+1);

	for(int i = 0;i < N;i++)
	{
		for(int j = 0;j < N;j++)
			M_Sum += A[i][j] * X30[j];
		M_Sum[N][N] += V1[i];
		Pk.push_back(M_Sum);
		clear(M_Sum);
	}
	return Pk;
}
Mat<ZZ_p> L2_Func_A_X(Mat<ZZ_p>& A,Vec<ZZ_p>& V)
{
	Mat<ZZ_p> A_X;	
	A_X.SetDims(N,N + 1);
	for(int i = 0; i < A.NumRows();i++)
	{
		for(int j = 0; j < A.NumCols();j++)
			A_X.put(i,j,A[i][j]);
		A_X.put(i,A_X.NumCols() - 1,V[i]);
	}
	return A_X;
}
/****************function:计算私钥（p0,p1,...,p(n-1)）*********************************************************/
/****************output: 把私钥输出到一个vector中存储********************************************************/
vector<ZZ_p> Get_sk(vector<Mat<ZZ_p> >& Pk )
{
	vector<ZZ_p> Sk;
	Sk.reserve(N);
	ZZ_p sum;

	for(int i = 0;i < N;i++)
	{
		for(int j = 0;j < N + 1;j++)
			sum += Pk[i][j][j];
		Sk.push_back(sum);
		clear(sum);
	}
	return Sk;
}
/*************************多项式模乘运算*********************************************************************/
ZZ_pX Poly_Mul_Mod(ZZ_pX& Poly1,ZZ_pX& Poly2,ZZ_pX& IrredPoly_fx)
{
	ZZ_pX Res;
	ZZ_pX Tmp;
	ZZ_pX x_var;
	for(int i = 0;i < N;i++)
	{
		for(int j = 0;j < N - i;j++)
			Tmp[i + j] = Poly1[i] * Poly2[j];
		Res += Tmp;
		for(int j = N - i;j < N;j++)
		{
			SetCoeff(x_var, i + j);
			ZZ_pX y;
			y.SetLength(N);
			y = x_var % IrredPoly_fx;
			Res += Poly1[i] * Poly2[j] * y;
			clear(x_var);
		}
		clear(Tmp);		
	}
	return Res;

}
/*************************多项式模运算***********************************************************************/
/****************function:加密一个N长的明文，输出一个N长的密文**********************************************/
Vec<ZZ_p> MultiVar_Enc(Vec<ZZ_p>& Plaintext,vector<Mat<ZZ_p> >& Px)
{
	Vec<ZZ_p> chiper;
	chiper.SetLength(N);
	ZZ_p c;//1bit密文
	for(int  i = 0;i < N;i++ )
	{
		for(int row = 0;row < N;row++)
		{
			for(int col = row + 1;col < N;col++)
				c += ( Px[i][row][col] + Px[i][col][row] ) * Plaintext[row] * Plaintext[col];
			c += ( Px[i][row][N] + Px[i][N][row] ) * Plaintext[row];
		}
		cout << c << " ";
		chiper.put(i,c);
		clear(c);
	}
	return chiper;
	
}
/*****************function:解密出来两个N长的密文******************************************************************************/
int MultiVar_Dec(Vec<ZZ_p>& chiper, vector<ZZ_p>& sk, ZZ_pX& IrredPoly_fx,
		Mat<ZZ_p>& A_Inv, Vec<ZZ_p>& V1, ZZ& e, Mat<ZZ_p>& B_Inv, Vec<ZZ_p>& V2,vector<Vec<ZZ_p> >&m)
{
	Vec<ZZ_p> chiper_trans1;
	chiper_trans1.SetLength(N);
	Vec<ZZ_p> chiper_trans2;
	chiper_trans2.SetLength(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);

	ZZ_pX a;
	a.SetLength(N);
	a = Vec_to_Poly(chiper_trans2);
	//PowerMod(const ZZ_pX& a, const ZZ& e, const ZZ_pXModulus& F);// x = a^e % f;deg(a) < n 
	ZZ_pX b1;
	b1.SetLength(N);
	b1 = PowerMod(a,e,IrredPoly_fx);
	ZZ_pX b2 = -1 * b1;

	Vec<ZZ_p> c1 = Poly_to_Vec(b1);
	Vec<ZZ_p> c2 = Poly_to_Vec(b2);

	Vec<ZZ_p> m1;
	m1.SetLength(N);
	Vec<ZZ_p> m2;
	m2.SetLength(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 1;

}


/**************input:输入Y,不可约多项式，（2N-2）*N的x^i mod fx的多项式，i>=N,一个空的N*N的矩阵********************/
/**************output:Y^3^0,Y^3^1,...,Y^3^256modfx的一个矩阵*****************************************************************/
int PolyY_3Mod_IrredPoly(ZZ_pX& Y, ZZ_pX& IrredPoly_fx, Mat<ZZ_p>& Xi_modIrred, Mat<ZZ_p>& Y3i )//Y3i为一个N*N的矩阵
{
	Vec<ZZ_p> YY;
	YY.SetLength(N);
	YY = Poly_to_Vec(Y);
	Vec<ZZ_p> V_Res;
	V_Res.SetLength(N);

	for(int k = 1;k < N;k++)
	{
		for(int i = 0; i < 86;i++)
			V_Res.put(3 * i, YY[i]);
		for(int i = 86;i < N;i++)
		{
			if(YY[i] == 0) continue;
			V_Res += YY[i] * Xi_modIrred[3 * i - N];
		}
		Y3i[k] = V_Res;
		YY = V_Res;
		clear(V_Res);
	}
	return 1;
}

int main1()
{
	ZZ_p::init(p);	
	//产生两个矩阵及他的逆阵
	Mat<ZZ_p> A;	
	A.SetDims(N,N);
	Vec<ZZ_p> V1;
	V1.SetLength(N);
	Mat<ZZ_p> A_Inv;	
	A_Inv.SetDims(N,N);
	Mat<ZZ_p> A_X;	
	A_X.SetDims(N,N + 1);

	A_X = generate_Matrix(A,V1);
	A_Inv = inv(A);
	cout << "L1的A与V1" <<endl;
	cout << A <<endl;
	cout << V1 << endl;

	vector<Mat<ZZ_p> > X30;	
	Mat<ZZ_p> B;	
	B.SetDims(N+1, N+1);
	cout <<"X_30："<< endl;
	for(int k = 0;k < N;k++)
	{
		for(int i = 0; i < B.NumRows();i++)
		{
			for(int j = 0; j < B.NumCols();j++)
			{
				int a = rand() % 3;
				B.put(i,j,to_ZZ_p(a));
			}
		}
		cout << B << endl;
		X30.push_back(B);
	}

	vector<Mat<ZZ_p> > Pk;
	Pk.reserve(N);
	Mat<ZZ_p> M_Sum;//中间变量存储矩阵
	M_Sum.SetDims(N+1,N+1);
	cout << "PK结果为："<< endl;
	for(int i = 0;i < N;i++)
	{
		for(int j = 0;j < N;j++)
			M_Sum += A[i][j] * X30[j];
		M_Sum[N][N] += V1[i];

		cout << M_Sum<<endl;
		Pk.push_back(M_Sum);
		clear(M_Sum);
	}

	//测试：产生一个随机向量作为明文
	Vec<ZZ_p> Plaintext;
	Plaintext.SetLength(N);
	for(int i = 0;i < N;i++)
	{
		int b = rand() % 2 + 1;
		Plaintext.put(i,to_ZZ_p(b));
	}
	cout << "测试明文为："<< Plaintext<<endl;
	Vec<ZZ_p> chiper;
	chiper.SetLength(N);
	ZZ_p c;//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 += ( Pk[i][row][col] + Pk[i][col][row] ) * Plaintext[row] * Plaintext[col];
			c += ( Pk[i][row][N] + Pk[i][N][row] ) * Plaintext[row];
		}
		cout << c << " ";
		chiper.put(i,c);
		clear(c);
	}

	getchar();
	return 0;
}
int main()
{
	//产生一个不可约多项式IrredPoly_Fx
	ZZ_p::init(p);	//设置模数p
	ZZ_pX IrredPoly_fx; 
	
	//从文件中读不可约多项式
	ifstream fin_irredPoly_fx("irredPoly_fx.txt");
	fin_irredPoly_fx >> IrredPoly_fx;
	fin_irredPoly_fx.close();
	cout << "不可约多项式f(x)为："<<IrredPoly_fx <<endl;

	ZZ one = to_ZZ("1");
	ZZ three_257_sub_1 = power_ZZ(3,257) - one;
	ZZ three_257_add_1 = power_ZZ(3,257) + one;
	//cout<< GCD(three_257_add_1,4) << endl;
	ZZ three_257_add_1_div_4 = three_257_add_1 / 4;
	//cout << three_257_sub_1<< endl;	
	ZZ a1 = InvMod(to_ZZ("15"), three_257_sub_1);
	cout << "15mod (3^257 -1)的逆元为:" <<endl;
	cout << a1 <<endl;
	ZZ e = MulMod(a1, three_257_add_1_div_4, three_257_sub_1);
	//ZZ e;
	//ifstream fin_e("模数e.txt",ios::in);
	//fin_e >> e;
	//fin_e.close();
	//cout << e << endl;
	/*for(int i = 256;i >= 0 && e >= 0;i--)
	{
		if(e >= power_ZZ(3,i))
		{
			e -= power_ZZ(3,i);
			cout << i << " ";	
		}

	}
	cout << endl;
	cout << e << endl;*/
	//Mat<ZZ_p> A_X;	
	//A_X.SetDims(N,N + 1);
	////读入选取好的两个可逆矩阵及逆阵，向量V1,V2
	//Mat<ZZ_p> A;	
	//A.SetDims(N,N);
	//Mat<ZZ_p> A_Inv;	
	//A_Inv.SetDims(N,N);
	//Vec<ZZ_p> V1;
	//V1.SetLength(N);

	//Mat<ZZ_p> B;	
	//B.SetDims(N,N);
	//Mat<ZZ_p> B_Inv;	
	//B_Inv.SetDims(N,N);
	//Vec<ZZ_p> V2;
	//V2.SetLength(N);
	//
	///*read_Inv_M_V("Mat_A_Vec1.txt",A,V1);
	//read_Inv_M_V("Inv_A.txt",A_Inv);
	//read_Inv_M_V("Mat_B_Vec2.txt",B,V2);*/
	//read_Inv_M_V("Inv_B.txt",B_Inv);
	///*A_X =  L2_Func_A_X(B,V2);*/

	//ofstream f_B("new Inv_BB.txt",ios::app);
	//for(int i = 0;i < N;i++)
	//{
	//	for(int j = 0;j < N;j++)
	//		f_B << B_Inv[i][j];
	//}
	//f_B.close();
	////计算A_X^3，以及A_X^27
	//Mat<ZZ_p> A_X3_Sum;
	//A_X3_Sum.SetDims(N,N + 1);
	////X3_Sum_Calc(A_X, IrredPoly_fx, A_X3_Sum); 
	//read_Inv_M("A_X3.txt",A_X3_Sum);
	//
	//Mat<ZZ_p> A_X27_Sum;
	//A_X27_Sum.SetDims(N,N + 1);
	////X27_Sum_Calc(A_X, IrredPoly_fx, A_X27_Sum); 
	//read_Inv_M("A_X27.txt",A_X27_Sum);

	////计算A_X^30
	//vector<Mat<ZZ_p> > A_X30_Sum;
	//X30_FXCalc( A_X27_Sum, A_X3_Sum, IrredPoly_fx, A_X30_Sum);

	//vector<Mat<ZZ_p> > PK;
	//PK = L1_Function( A, V1, A_X30_Sum);

	/*ofstream fout_Pk("Pk.txt", ios::app);
	assert(fout_Pk);
	vector<Mat<ZZ_p> >::iterator it = PK.begin();
	for(;it != PK.end();it++)
	{
		for(int i = 0;i < (*it).NumRows();i++)
			fout_Pk << (*it)[i];
	}	
	fout_Pk.close();*/

	/*vector<ZZ_p> sk;
	sk = Get_sk(PK);
	ofstream fout_sk("sk.txt", ios::app);
	assert(fout_sk);

	for(int i = 0;i < sk.size();i++)
		fout_sk << sk[i] << " ";
	cout<< "私钥sk个数为："<< sk.size() << endl;
	for(int j = 0;j < sk.size();j++)		
		cout << sk[j] << " ";
	fout_sk.close();
*/
	/*vector<ZZ_p> Sk;
	read_Sk("sk.txt",Sk);
	cout << "私钥为：";
	for(int i = 0;i < N;i++)
		cout << Sk[i]<< " ";*/




	//vector<Mat<ZZ_p> > PK;
	//read_Pk("Pk.txt",PK);
	//
	//vector<ZZ_p> Sk;
	//Sk.reserve(N);
	//ZZ_p sum;
	//cout <<"私钥为";
	//for(int i = 0;i < N;i++)
	//{
	//	for(int j = 0;j < N + 1;j++)
	//		sum += PK[i][j][j];
	//	cout << sum << " ";
	//	Sk.push_back(sum);
	//	clear(sum);
	//}

	////测试：产生一个随机向量作为明文
	//Vec<ZZ_p> Plaintext;
	//Plaintext.SetLength(N);
	//ofstream f_out("random plaintext.txt",ios::app);
	//for(int i = 0;i < N;i++)
	//{
	//	srand(time(0)+i);
	//	int b = rand() % 2 + 1;
	//	Plaintext.put(i,to_ZZ_p(b));
	//	f_out << b;
	//}
	//f_out.close();
	//cout << "随机明文为："<< endl;
	//cout << Plaintext << endl;

	//Vec<ZZ_p> chiper;
	//chiper.SetLength(N);
	//cout << "加密得到的密文为：" << endl;
	//chiper = MultiVar_Enc(Plaintext,PK);

	//cout << "解密得到的明文："<< endl;
	//vector<Vec<ZZ_p> > decrypt_m;
	//MultiVar_Dec( chiper, Sk, IrredPoly_fx, A_Inv, V1, e, B_Inv, V2, decrypt_m );
	//cout << decrypt_m[0] << endl;
	//cout << decrypt_m[1] << endl;
	//cout << "hello world!";

	getchar();
	return 0;
}
int main3()
{
	ZZ_p::init(p);	
	ZZ_pX IrredPoly_fx; 	
	//从文件中读不可约多项式
	ifstream fin_irredPoly_fx("irredPoly_fx.txt");
	fin_irredPoly_fx >> IrredPoly_fx;
	fin_irredPoly_fx.close();
	cout << "不可约多项式f(x)为："<<IrredPoly_fx <<endl;
	vector<Mat<ZZ_p> > PK;
	read_Pk("Pk.txt",PK);//PK,是N个（N+1)*(N+1）的矩阵
	ofstream fout("new pk.txt",ios::app);
	for(int k = 0;k < N;k++)
	{
		for(int i = 0;i < N + 1;i++)
		{
			for(int j = 0;j < N + 1;j++)
				fout << PK[k][i][j];
		}
	}
	fout.close();
	/*cout << sizeof(index)/4 << endl;*/
	//ofstream fout_Xe("Xe_mod_Irredfx.txt",ios::app);
	//for(int i = 0;i < 2 * N - 2;i++)
	//{
	//	SetCoeff(x, i + N);
	//	fout_Xe << Poly_to_Vec(x % IrredPoly_fx);
	//	clear(x);
	//}		
	//fout_Xe.close();
	//Mat<ZZ_p> A;
	//A.SetDims(N ,N);
	//read_Inv_M_V("X_27i_mod_Irredfx.txt",A);
	//ofstream fout("new X_27i_mod_Irredfx.txt",ios::app);
	//for(int i = 0; i < N;i++)
	//{
	//	for(int j = 0;j < N;j++)
	//		fout << A[i][j] << " ";
	//}
	//fout.close();
	/*ZZ_pX x_var;
	ofstream fout_X27("new X_27i_mod_Irredfx.txt",ios::app);
	for(int i = 0;i <  N ;i++)
	{
		SetCoeff(x_var, 27 * i);
		ZZ_pX y;
		y.SetLength(N);
		y = (deg(x_var) < deg(IrredPoly_fx)) ? x_var : (x_var % IrredPoly_fx);

		for(int j = 0;j < N;j++)
			fout_X27 << y[j];
		clear(x_var);
	}		
	fout_X27.close();*/

	//ZZ_pX a;
	//SetCoeff(a,1);
	//SetCoeff(a,2,2);
	//SetCoeff(a,4);
	//SetCoeff(a,5,2);
	//SetCoeff(a,7);
	//SetCoeff(a,8,2);

	//ZZ_pX b;
	//SetCoeff(b,0);
	//SetCoeff(b,1);
	//SetCoeff(b,2,2);
	//SetCoeff(b,3,2);
	//SetCoeff(b,4,2);
	//SetCoeff(b,5);
	//SetCoeff(b,6);
	//SetCoeff(b,9);
	//SetCoeff(b,10,2);

	//cout << a<<endl;
	//cout << b<<endl;
	//cout << a*b<<endl;
	//cout << b % a;
	//Mat<ZZ_p> A;	//读取(2N-2)*N的矩阵
	//A.SetDims(2* N - 2,N);
	//read_XeMod_Mat("Xe_mod_Irredfx.txt",A);
	//cout << A[511];

	//Mat<ZZ_p> B;
	//B.SetDims(N,N);
	cout << "hello world!"<<endl;
	getchar();
	return 0;
}

int main4()
{
	ZZ_p::init(p);	

	ZZ one = to_ZZ("1");
	ZZ three_257_sub_1 = power_ZZ(3,257) - one;
	ZZ three_257_add_1 = power_ZZ(3,257) + one;
	//cout<< GCD(three_257_add_1,4) << endl;
	ZZ three_257_add_1_div_4 = three_257_add_1 / 4;
	cout << three_257_sub_1<< endl;	
	ZZ a1 = InvMod(to_ZZ("15"), three_257_sub_1);	
	ZZ e = MulMod(a1, three_257_add_1_div_4, three_257_sub_1);
	ZZ_pX IrredPoly_fx; 	
	//从文件中读不可约多项式
	ifstream fin_irredPoly_fx("irredPoly_fx.txt");
	fin_irredPoly_fx >> IrredPoly_fx;
	fin_irredPoly_fx.close();

	Vec<ZZ_p> chiper;
	chiper.SetLength(N);
	ifstream fin("test chiper121.txt",ios::in);
	for(int i = 0;i < N;i++)
	{
		char ch;
		fin >> ch;
		chiper.put(i,to_ZZ_p(ch - '0'));
	}
	fin.close();
	cout << chiper<<endl;


	Mat<ZZ_p> A;	
	A.SetDims(N,N);
	Mat<ZZ_p> A_Inv;	
	A_Inv.SetDims(N,N);
	Vec<ZZ_p> V1;
	V1.SetLength(N);

	read_Inv_M_V("Mat_A_Vec1.txt",A,V1);
	read_Inv_M_V("Inv_A.txt",A_Inv);
	
	Vec<ZZ_p> chiper_trans1;
	chiper_trans1.SetLength(N);
	Vec<ZZ_p> chiper_trans2;
	chiper_trans2.SetLength(N);

	Vec<ZZ_p> sk;
	ifstream fin_sk("sk.txt",ios::in);	
	fin_sk >> sk;
	fin_sk.close();
	cout << sk<<endl;
	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);
	ZZ_pX Poly;
	Poly.SetLength(N);
	for(int i = 0;i < N;i++)
		SetCoeff(Poly,i,chiper_trans2[i]);
	cout << "chiper_trans2:"<<endl;
	cout << Poly << endl;

	ZZ_pX b1;
	b1.SetLength(N);
	b1 = PowerMod(Poly,e,IrredPoly_fx);
	cout << b1 << endl;
	cout << "hello world!";
	getchar();
	return 0;
}





