SEAL icon indicating copy to clipboard operation
SEAL copied to clipboard

Can SEALContext object transmit by socket?

Open hui09-m opened this issue 2 years ago • 6 comments

Can SEALContext object transmit by socket? I want to use socket to imitate the comminucations between server and clients. Then I write code to acchieve the fundation. But some errors occured. image If I write parameters for SEALContext object in Client, it can print corectly. However, I can not suitable for the parameters from Server. I will show you the code. server: `#include <server.h> #pragma comment(lib,"ws2_32.lib") using namespace std; using namespace seal; const int PORT = 8000; #define MaxClient 10 #define MaxBufSize 4096 #define _CRT_SECURE_NO_WARINGS //服务线程 DWORD WINAPI ServerThread(LPVOID lpParameter) { SOCKET* ClientSocket = (SOCKET*)lpParameter; int receByt = 0; //* char RecvBuf[MaxBufSize]; char RecvBuf[1]; char SendBuf[MaxBufSize]; while (1) { //数据接收 receByt = recv(*ClientSocket, RecvBuf, sizeof(RecvBuf), 0); cout << "receByt = " << receByt << endl; string str_buff = RecvBuf; cout << "str_buff = " << str_buff << endl; if (receByt > 0) { cout << "接收到的消息是:" << RecvBuf << " 来自客户端:" << *ClientSocket << endl; if (str_buff == "1") { cout << "If you are ready for FHE servive,please write 1" << endl; } else cout << "Service wronged!" << endl; } else { cout << "接收消息结束!" << endl; break; } memset(RecvBuf, 0, sizeof(RecvBuf));

	//数据处理


	//数据发送
	fgets(SendBuf, MaxBufSize, stdin);
	EncryptionParameters parms(scheme_type::bfv);
	size_t poly_modulus_degree = 8192;
	parms.set_poly_modulus_degree(poly_modulus_degree);
	parms.set_coeff_modulus(CoeffModulus::BFVDefault(poly_modulus_degree));
	parms.set_plain_modulus(PlainModulus::Batching(poly_modulus_degree, 20));
	SEALContext context(parms);
	print_parameters(context);
	int k = 0;
	//k = send(*ClientSocket, (char*)&parms, sizeof(EncryptionParameters), 0);
	k = send(*ClientSocket, (char*)&context, sizeof(SEALContext), 0);

	if (k < 0) {
		cout << "发送失败" << endl;  
	}

	/* //source
	cout << "请输入要发送到客户端的信息:" << endl;
	fgets(SendBuf, MaxBufSize, stdin);
	int k = 0;
	k = send(*ClientSocket, SendBuf, sizeof(SendBuf), 0);
	if (k < 0) {
		cout << "发送失败" << endl;
	}
	memset(SendBuf, 0, sizeof(SendBuf));

*/ } closesocket(*ClientSocket); free(ClientSocket); return 0; }

int main() { WSAData wsd; WSAStartup(MAKEWORD(2, 2), &wsd); SOCKET ListenSocket = socket(AF_INET, SOCK_STREAM, 0); SOCKADDR_IN ListenAddr; ListenAddr.sin_family = AF_INET; ListenAddr.sin_addr.S_un.S_addr = INADDR_ANY;//表示填入本机ip ListenAddr.sin_port = htons(PORT); int n; //n = bind(ListenSocket, (LPSOCKADDR)&ListenAddr, sizeof(ListenAddr)); n = ::bind(ListenSocket, (LPSOCKADDR)&ListenAddr, sizeof(ListenAddr));

if (n == SOCKET_ERROR) {
	cout << "端口绑定失败!" << endl;
	return -1;
}
else {
	cout << "端口绑定成功:" << PORT << endl;
}
int l = listen(ListenSocket, 20);
cout << "服务端准备就绪,等待连接请求" << endl;

while (1) {
	//循环接收客户端连接请求并创建服务线程
	SOCKET* ClientSocket = new SOCKET;
	ClientSocket = (SOCKET*)malloc(sizeof(SOCKET));
	//接收客户端连接请求
	int SockAddrlen = sizeof(sockaddr);
	*ClientSocket = accept(ListenSocket, 0, 0);
	cout << "一个客户端已连接到服务器,socket是:" << *ClientSocket << endl;
	CreateThread(NULL, 0, &ServerThread, ClientSocket, 0, NULL);
}//while
closesocket(ListenSocket);
WSACleanup();
return(0);

}//main`

client: `//#include "Client.h" #include "client.h" #pragma comment(lib,"ws2_32.lib") #pragma warning(disable:4996) using namespace std; using namespace seal; const int PORT = 8000; #define MaxBufSize 4096 #define _CRT_SECURE_NO_WARINGS int main() { WSADATA wsd; WSAStartup(MAKEWORD(2, 2), &wsd); //* SOCKET SocketClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); SOCKET SocketClient = socket(AF_INET, SOCK_STREAM, 0);

SOCKADDR_IN  ClientAddr;

ClientAddr.sin_family = AF_INET;
ClientAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
ClientAddr.sin_port = htons(PORT);
int n = 0;
n = connect(SocketClient, (struct sockaddr*)&ClientAddr, sizeof(ClientAddr));
if (n == SOCKET_ERROR) {
	cout << "连接失败" << endl;
	return -1;
}
cout << "已经连接到服务器,可以向服务器发送消息了!" << endl;
char info[1024], SendBuff[MaxBufSize], RecvBuff[MaxBufSize];
while (1) {

//* cout << "请输入要发送的信息,按回车结束发送:" << endl; //数据处理

	cout << "If you are ready for FHE ,please write 1" << endl;
	//数据处理结束,准备发送数据


	fgets(info, 1024, stdin);
	//*		gets(info);		//error,change to the former
	if (info[0] == '\0')
		break;		
	strcpy(SendBuff, info);
	memset(info, 0, sizeof(info));
	int k = 0;
	k = send(SocketClient, SendBuff, sizeof(SendBuff), 0);
	memset(SendBuff, 0, sizeof(SendBuff));
	if (k < 0) {
		cout << "发送失败" << endl;
	}
	Sleep(500);

	//数据接收
	
	EncryptionParameters parms(scheme_type::bfv);
	int m = 0;
	//n = recv(SocketClient, (char*)&parms, sizeof(EncryptionParameters), 0);
	/*
	size_t poly_modulus_degree = 8192;
	parms.set_poly_modulus_degree(poly_modulus_degree);
	parms.set_coeff_modulus(CoeffModulus::BFVDefault(poly_modulus_degree));
	parms.set_plain_modulus(PlainModulus::Batching(poly_modulus_degree, 20));
	m = 1;

*/

	SEALContext context(parms);
	m = recv(SocketClient, (char*)&context, sizeof(SEALContext), 0);
	cout << "m = " << m << endl;
	if (m > 0) {
		cout << "Having got the paramerters" << endl;
		//SEALContext context(parms);
		print_parameters(context);	//error,异常,读取访问权限冲突
		cout << endl;

	}

	memset(RecvBuff, 0, sizeof(RecvBuff));

/*//*	
	int n = 0;
	n = recv(SocketClient, RecvBuff, sizeof(RecvBuff), 0);
	if (n > 0) {
		cout << "接收到来自服务器的消息为:" << RecvBuff << endl;
	}
	memset(RecvBuff, 0, sizeof(RecvBuff));
*/	
}
closesocket(SocketClient);
WSACleanup();
return 0;

} `

hui09-m avatar Feb 24 '23 08:02 hui09-m

  • It seems you have misunderstood what sizeof(EncryptionParameters) means.
  • Instead using std::stringstream to de/serialize
    std::stringstream ss;
    parms.save(ss); 
    std::string parms_to_send  = ss.str();
    

Then on the other side, first recv a string and use std::stringstream to de-serialize

EncryptionParmeters parms;
parms.load(a_string);

SEALContext is not serializable. Just exchange EncryptionParmeters and then construct the context.

fionser avatar Mar 02 '23 01:03 fionser

  • It seems you have misunderstood what sizeof(EncryptionParameters) means.
  • Instead using std::stringstream to de/serialize
    std::stringstream ss;
    parms.save(ss); 
    std::string parms_to_send  = ss.str();
    

Then on the other side, first recv a string and use std::stringstream to de-serialize

EncryptionParmeters parms;
parms.load(a_string);

SEALContext is not serializable. Just exchange EncryptionParmeters and then construct the context.

Well, I tried this method, I can get string data, however, parms.load can't load it and throw exception. For function load() just can support stream datatype, I convert string to stringstream. image For thinking about it, for get the parms, may use parms.save() and parms.load() to do this? When I use simply parms.save(ss) and parms.load(ss), it not work and throw logic_error. So I use "parms.save(reinterpret_cast<seal_byte*>(byte_buffer.data()), byte_buffer.size()); ", it works. However, when constract SEALContext, it throw std::invalid_argument error. I have no idea about it. Can you give me some advice? image image image

hui09-m avatar Mar 06 '23 07:03 hui09-m

The following code work fine for me

void test() {
  seal::EncryptionParameters parms(seal::scheme_type::ckks);
  size_t N = 8192;
  std::vector<int> modulus_bits = {51, 55, 55};
  auto modulus = seal::CoeffModulus::Create(N, modulus_bits);
  parms.set_poly_modulus_degree(N);
  parms.set_coeff_modulus(modulus);
  parms.set_random_generator(
      seal::UniformRandomGeneratorFactory::DefaultFactory());

  seal::SEALContext conetxt(parms);

  std::ostringstream outs;
  parms.save(outs);
  std::string parms_str = outs.str();
  printf("parms bytes %zd\n", parms_str.length());

  // Simulate: send string through socket
  std::vector<unsigned char> recv_bytes(parms_str.length());
  std::copy_n(parms_str.c_str(), recv_bytes.size(), recv_bytes.data());
  // wrap the bits as string
  std::string recv_string(recv_bytes.data(), recv_bytes.data() + recv_bytes.size());

  std::istringstream ins(recv_string);
  seal::EncryptionParameters other_parms;
  other_parms.load(ins);
  seal::SEALContext other_context(other_parms);
  printf("Is SEAL ok = %d\n", other_context.parameters_set());
}

fionser avatar Mar 06 '23 09:03 fionser

The following code work fine for me

void test() {
  seal::EncryptionParameters parms(seal::scheme_type::ckks);
  size_t N = 8192;
  std::vector<int> modulus_bits = {51, 55, 55};
  auto modulus = seal::CoeffModulus::Create(N, modulus_bits);
  parms.set_poly_modulus_degree(N);
  parms.set_coeff_modulus(modulus);
  parms.set_random_generator(
      seal::UniformRandomGeneratorFactory::DefaultFactory());

  seal::SEALContext conetxt(parms);

  std::ostringstream outs;
  parms.save(outs);
  std::string parms_str = outs.str();
  printf("parms bytes %zd\n", parms_str.length());

  // Simulate: send string through socket
  std::vector<unsigned char> recv_bytes(parms_str.length());
  std::copy_n(parms_str.c_str(), recv_bytes.size(), recv_bytes.data());
  // wrap the bits as string
  std::string recv_string(recv_bytes.data(), recv_bytes.data() + recv_bytes.size());

  std::istringstream ins(recv_string);
  seal::EncryptionParameters other_parms;
  other_parms.load(ins);
  seal::SEALContext other_context(other_parms);
  printf("Is SEAL ok = %d\n", other_context.parameters_set());
}

It seems you don't use socket to transmit data, you just use stringstream to do. Socket use send() and recv() to communicate. The fomat like: send( In SOCKET s, In_reads_bytes(len) const char FAR * buf, In int len, In int flags ); recv( In SOCKET s, Out_writes_bytes_to(len, return) __out_data_source(NETWORK) char FAR * buf, In int len, In int flags ); Always it make client and server be two projects like following picture (project Clients and Server_for_multi_clients), you should define apart.

image

hui09-m avatar Mar 06 '23 13:03 hui09-m

There is no difference between copy_n and send/recv pair. To make sure you are using the right length (but not just a MaxBufSize) and make sure your have initialized your byte vector properly.

fionser avatar Mar 07 '23 02:03 fionser

There is no difference between copy_n and send/recv pair. To make sure you are using the right length (but not just a MaxBufSize) and make sure your have initialized your byte vector properly.

I have try what you said. For me, I set client project and service project apart, when client.cpp use the following data to recv parms that works. std::vector recv_bytes(parms_str.length()); Thanks for answering me!!!

hui09-m avatar Mar 08 '23 07:03 hui09-m