/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian * This file is part of XPIR. * * XPIR is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * XPIR is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with XPIR. If not, see . */ #include "PIRClient.hpp" //Use this to limit the upload speed to UPLOAD_LIMIT bits per second //#define UPLOAD_LIMIT 100000000UL PIRClientSimple::PIRClientSimple(boost::asio::io_service& ios, ClientParams params, FixedVars vars): socket_up(ios), replyWriter(pirParams, writeListeners, messageListeners), catalog(messageListeners), clientParams(params), fixedVars(vars), optimum(vars), no_pipeline_mode(false) { replyWriter.setdontWrite(params.dontwrite); //string lwe_params(crypto_params_const); //cryptoMethod.getPublicParameters().computeNewParameters(lwe_params); //pirParams.d = kDimensionNumber; } void PIRClientSimple::joinAllThreads() { replyExt->replyThread.join(); replyWriter.join(); } PIRClientSimple::~PIRClientSimple() { joinAllThreads(); delete cryptoMethod; } void PIRClientSimple::connect() { using namespace boost::asio::ip; try { socket_up.connect(tcp::endpoint(address::from_string(clientParams.server_ip), clientParams.port)); // Tell the server we are a client int is_client = 1; write(socket_up, boost::asio::buffer(&is_client, sizeof(int))); } catch (const std::exception& ex) { exitWithErrorMessage(__FUNCTION__, ex.what()); } } /** * Downloads the file catalog from the server. * Exception : * - Stop the programme if any network trouble. **/ void PIRClientSimple::downloadCatalog() { boost::uint64_t size = 1; try { read(socket_up, boost::asio::buffer(&size, sizeof(size))); std::cout<< "PIRClient: Catalog bytesize is "<getSerializedCryptoParams(!shortversion); size = crypto_params.length(); write(socket_up, boost::asio::buffer(&size, sizeof(size))); write(socket_up, boost::asio::buffer(crypto_params)); } size = ceil((double) cryptoMethod->getPublicParameters().getSerializedModulusBitsize() / GlobalConstant::kBitsPerByte); write(socket_up, boost::asio::buffer(&size, sizeof(size))); key = cryptoMethod->getPublicParameters().getByteModulus(); write(socket_up, boost::asio::buffer(key, size));//Send key delete[] key; } catch (const std::exception& ex) { exitWithErrorMessage(__FUNCTION__, ex.what()); } } void PIRClientSimple::rcvCryptoParams() { try { int crypto_params_size = 0; read(socket_up, boost::asio::buffer(&crypto_params_size, sizeof(crypto_params_size))); char crypto_params[crypto_params_size + 1]; int read_size = read(socket_up, boost::asio::buffer(crypto_params,crypto_params_size)); crypto_params[read_size] = '\0'; pirParams.crypto_params = string(crypto_params); std::cout << "PIRClient: Received crypto parameters " << crypto_params << std::endl; } catch (const std::exception& ex) { exitWithErrorMessage(__FUNCTION__, ex.what()); } } /** * Launches the choose File action to the recorded view. If autochoice is set, * the first file is chosen. **/ void PIRClientSimple::chooseFile() { chosenElement = 0; if(!clientParams.autochoice) { CatalogEvent catalogEvent(catalog.getFileList()); menuListeners(catalogEvent); // get user input and set chosenElement. } std::ostringstream oss; oss << "PIRClient: Retrieved file is nbr " + (chosenElement+1); oss << + ", \"" + catalog.getFileName(chosenElement) + "\""; MessageEvent messageEvent(oss.str()); messageListeners(messageEvent); } /** * Set the query generator and launch parallely query generation and query upload. **/ void PIRClientSimple::startProcessQuery() { PIRQueryGenerator_internal queryGen(pirParams, *cryptoMethod); queryGen.setChosenElement(chosenElement); if(no_pipeline_mode) { std::cout << "PIRClient: Calling query generation and upload without pipelining" << std::endl; gq_start = clock(); queryGen.generateQuery(); gq_stop = clock(); } else { queryGen.startGenerateQuery(); } uploadWorker(queryGen); } void sleepForBytes(unsigned int bytes) { #ifdef UPLOAD_LIMIT uint64_t seconds=(bytes*8)/UPLOAD_LIMIT; uint64_t nanoseconds=((((double)bytes*8.)/(double)UPLOAD_LIMIT)-(double)seconds)*1000000000UL; struct timespec req={0},rem={0}; req.tv_sec=seconds; req.tv_nsec=nanoseconds; double st=omp_get_wtime(); nanosleep(&req,&rem); #endif } /** * Upload query to the server et delete its parts from the shared query queue. * Exception : * - Stop the programme if any network trouble. **/ void PIRClientSimple::uploadWorker(PIRQueryGenerator_internal& queryGen) { unsigned int size = 0; char *tmp; try { for (unsigned int j = 1 ; j <= pirParams.d ; j++) { size = cryptoMethod->getPublicParameters().getQuerySizeFromRecLvl(j) / GlobalConstant::kBitsPerByte; for (unsigned int i = 0 ; i < pirParams.n[j - 1] ; i++) { tmp = queryGen.queryBuffer.pop_front(); write(socket_up, boost::asio::buffer(tmp, size)); free(tmp); #ifdef UPLOAD_LIMIT sleepForBytes(size); #endif } } } catch (const std::exception& ex) { exitWithErrorMessage(__FUNCTION__, ex.what()); } } /** * Sets reply extractpr and lauches parallely reply download and reply extraction. **/ void PIRClientSimple::startProcessResult() { replyExt = new PIRReplyExtraction_internal(pirParams,*cryptoMethod); replyExt->setFileParam(catalog.getFileName(chosenElement), catalog.getFileSize(chosenElement)); if(no_pipeline_mode) { std::cout << "PIRClient: Calling reply download, extraction and writting without pipelining" << std::endl; downloadWorker(*replyExt); er_start = clock(); replyExt->extractReply(catalog.getMaxFileSize()*pirParams.alpha, replyWriter.getClearDataQueue()); er_stop = clock(); tclock = gq_stop - gq_start; std::cout<<"GenQuery Time = %f ms"<< tclock/CLOCKS_PER_SEC <startExtractReply(catalog.getMaxFileSize()*pirParams.alpha, replyWriter.getClearDataQueue()); replyWriter.startFileWritting(chosenElement, catalog); downloadWorker(*replyExt); } } /** * Download reply from the server and stores it chunks in shared replies queue. * Exception : * - Stop the program if any network trouble. **/ void PIRClientSimple::downloadWorker(PIRReplyExtraction_internal& turlututu) { using namespace GlobalConstant; unsigned int i, ciph_siz = cryptoMethod->getPublicParameters().getCiphBitsizeFromRecLvl(pirParams.d)/kBitsPerByte; double paquet_nbr = ceil(static_cast(catalog.getMaxFileSize()*pirParams.alpha) / double(cryptoMethod->getPublicParameters().getAbsorptionBitsize(0)/kBitsPerByte)); #ifdef DEBUG cout << "PIRClient: First layer nbr of ciphertexts is " << paquet_nbr << endl; #endif for (unsigned int i = 1 ; i < pirParams.d; i++) paquet_nbr = ceil(paquet_nbr * double(cryptoMethod->getPublicParameters().getCiphBitsizeFromRecLvl(i)/kBitsPerByte) / double(cryptoMethod->getPublicParameters().getAbsorptionBitsize(i) / kBitsPerByte)); char* buf; #ifdef DEBUG cout << "PIRClient: getMaxFileSize=" << catalog.getMaxFileSize() << " alpha=" << pirParams.alpha << " getAbsorptionBitsize=" << double(cryptoMethod->getPublicParameters().getAbsorptionBitsize(0))/*kBitsPerByte);*/ << endl; cout << "PIRClient: Last layer nbr of ciphertexts is " << paquet_nbr << endl; cout << "PIRClient: File size of the chosen element is " << catalog.getFileSize(chosenElement) << endl; cout << "PIRClient: Ciphertext bytesize is " << ciph_siz << endl; #endif try { for (i = 0 ; i < paquet_nbr ; i++) { buf = (char*) malloc(ciph_siz * sizeof(char)); read(socket_up,boost::asio::buffer(buf, ciph_siz)); replyExt->repliesBuffer.push(buf); } } catch (const std::exception& ex) { #ifdef DEBUG cerr << "PIRReplyWriter: Number of downloaded chunks: " << i << "/" << paquet_nbr << endl; #endif exitWithErrorMessage(__FUNCTION__, ex.what()); return; } writeWarningMessage(__FUNCTION__, "done."); } /** * Sets the chosen element. **/ void PIRClientSimple::setChosenElement(uint64_t choice) { chosenElement = choice; } //void PIRClientSimple::setPIRParameters(PIRParameters& pirParameters) //{ // pirParams.alpha = pirParameters.alpha; // pirParams.d = pirParameters.d; // memcpy(pirParams.n, pirParameters.n, MAX_REC_LVL); // pirParams.r; //} /** * Add a new message listener. * Param : * - messageListener::slot_function_type subscriber, a message listener to add. **/ boost::signals2::connection PIRClientSimple::addMessageListener(messageListener::slot_function_type subscriber) { return messageListeners.connect(subscriber); } /** * Add a new menu listener. * Param : * - menuListener::slot_function_type subscriber, a menu listener to add. **/ boost::signals2::connection PIRClientSimple::addMenuListener(menuListener::slot_function_type subscriber) { return menuListeners.connect(subscriber); } /** * Add a new wite listener * Param : * - writeListener::slot_function_type subscriber, a write listener to add. **/ boost::signals2::connection PIRClientSimple::addWriteListener(writeListener::slot_function_type subscriber) { return writeListeners.connect(subscriber); } void PIRClientSimple::exitWithErrorMessage(string s1, string s2) { writeErrorMessage(s1 ,s2); socket_up.close(); exit(errno); } /** * Send ERROR message to listeners * Params : * - string funcName : usually the function name who throw the error message ; * - string message : message to show. **/ void PIRClientSimple::writeErrorMessage(string funcName, string message) { MessageEvent event(ERROR, message, funcName); messageListeners(event); } /** * Send WARNING message to listeners * Params : * - string funcName : usually the function name who throw the warning message ; * - string message : message to show. **/ void PIRClientSimple::writeWarningMessage(string funcName, string message) { MessageEvent event(WARNING, message, funcName); messageListeners(event); } void PIRClientSimple::no_pipeline(bool b) { no_pipeline_mode = b; }