Skip to content

Instantly share code, notes, and snippets.

@Ang3er
Last active August 1, 2018 01:40
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Ang3er/58472b6e6b1916da852caffe8be3a1fe to your computer and use it in GitHub Desktop.
Save Ang3er/58472b6e6b1916da852caffe8be3a1fe to your computer and use it in GitHub Desktop.
Commandline interface C++ for HElib
/* Copyright (C) 2016 Dominik Fischer
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* A commandline interface to interact with HElib. Each command awaits different parameters, the result is always a writing of files to given pathes for each differnet task. The code is following the approach of CPS to devide different stages (keyGen, calculation, encrypt, decrypt) on differnet devices. Therefore I used files to transmit those between the different devices.
Scenario:
-A owner generated the keys: public, private and context
-A CPD (Cyper-Physical device) can read from the publickey and is able to encrypt sensor data with the context
-A second server in the cloud is allowed to calculate given encrypted numbers(vectors) with the public key and context
-The enduser is able to decrypt the calculated number in the cloud on his server by using the the known secretkey and context
*/
#include "FHE.h"
#include "EncryptedArray.h"
#include <NTL/lzz_pXFactoring.h>
#include <fstream>
#include <sstream>
#include <iostream>
#include <stdlib.h>
using namespace std;
//compile command: g++ -g -O2 -std=c++11 -o Test_Modular Test_Modular.cpp fhe.a -L/usr/local/lib -lntl -lgmp -lm
//Constant values for selected parameter
const long c = 3;
const long w = 64;
const long k = 128;
const long s = 0;
bool DEBUG = false;
/*
* Debugger Function to print out information during run
*/
void myLogger(string msg) {
if (DEBUG) {
printf("%s \n", msg.c_str());
}
}
/*
* Add method
* Parameters:
* string ctxPath: Path to context file
* string pubPath: Path to publicKey file
* string encNumberPath: Path to encryptedNumber value 1
* string addEncNumberPath: Path to encryptedNumber value 2 which will be added
* string resultNumberPath: Path to resultNumber to be stored in
*/
void heAdd(string ctxPath, string pubPath, string encNumberPath,
string addEncNumberPath, string resultNumberPath) {
// ----- Blog to read in Context ----- See readContext
vector<long> gens, ords;
unsigned long m, p, r;
std::ifstream ctxFile(ctxPath, std::ios::binary);
readContextBase(ctxFile, m, p, r, gens, ords);
FHEcontext context(m, p, r, gens, ords);
ctxFile >> context;
myLogger("context read");
ctxFile.close();
// -------End Blog to read in Context -----
//read file
std::ifstream pubFile(pubPath, std::ios::binary);
FHEPubKey pubKey(context);
pubFile >> pubKey;
pubFile.close();
myLogger("pubKey read");
//build cypertext holders
Ctxt ct1(pubKey);
Ctxt ct2(pubKey);
myLogger("cypertxt build");
//fill cypertext1
std::ifstream encFileA(encNumberPath, std::ios::binary);
encFileA >> ct1;
encFileA.close();
myLogger("ct1 read");
//fill cypertext2
std::ifstream encFileB(addEncNumberPath, std::ios::binary);
encFileB >> ct2;
encFileB.close();
myLogger("ct2 read");
//calculate
ct1 += ct2;
myLogger("added");
//write encNumber
std::ofstream encFile(resultNumberPath, std::ios::binary);
encFile << ct1;
encFile.close();
myLogger("written to file");
}
/*
* Multiplication method
* Parameters:
* string ctxPath: Path to context file
* string pubPath: Path to publicKey file
* string encNumberPath: Path to encryptedNumber value 1
* string mulEncNumberPath: Path to encryptedNumber value 2 which will be multiplied res = v1 * v2
* string resultNumberPath: Path to resultNumber to be stored in
*/
void heMul(string ctxPath, string pubPath, string encNumberPath,
string mulEncNumberPath, string resultNumberPath) {
// ----- Blog to read in Context ----- See readContext
vector<long> gens, ords;
unsigned long m, p, r;
std::ifstream ctxFile(ctxPath, std::ios::binary);
readContextBase(ctxFile, m, p, r, gens, ords);
FHEcontext context(m, p, r, gens, ords);
ctxFile >> context;
myLogger("context read");
ctxFile.close();
// -------End Blog to read in Context -----
//read pubKey
std::ifstream pubFile(pubPath, std::ios::binary);
FHEPubKey pubKey(context);
pubFile >> pubKey;
pubFile.close();
myLogger("pubKey read");
//build cypertxt holders
Ctxt ct1(pubKey);
Ctxt ct2(pubKey);
//fill cypertext1
std::ifstream encFileA(encNumberPath, std::ios::binary);
encFileA >> ct1;
encFileA.close();
myLogger("ct1 read");
//fill cypertext2
std::ifstream encFileB(mulEncNumberPath, std::ios::binary);
encFileB >> ct2;
encFileB.close();
myLogger("ct2 read");
//multiply
ct1 *= ct2;
myLogger("multiplied");
//write encNumber
std::ofstream encFile(resultNumberPath, std::ios::binary);
encFile << ct1;
encFile.close();
myLogger("written to file");
}
/*
* KeyGeneration, generated Public and Secret key by using given context. The context + the keys will be saved in the given locations
* Parameters
* FHEcontext context: context object generated in main by given variables
* long L: Level of ??? see main parameter description
* string pubPath: Path to publicKey
* string secPath: Path to secretKey
* string ctxPath: Path to save the context in context file
*/
void keyGen(FHEcontext context, long L, string pubPath, string secPath,
string ctxPath) {
// modify the context, adding primes to the modulus chain
//Following original description WIP: buildModChain(context, L, c);
buildModChain(context, L);
//create SecretKey
FHESecKey secretKey(context);
secretKey.GenSecKey(w);
//Build placeholder for publicKey
FHEPubKey publicKey = secretKey;
//Read PublicKey
std::ofstream pubFile(pubPath, std::ios::binary);
pubFile << publicKey;
myLogger("pubKey written");
pubFile.close();
// write Cyptertext
std::ofstream ctxFile(ctxPath, std::ios::binary);
writeContextBase(ctxFile, context);
ctxFile << context;
myLogger("context written");
ctxFile.close();
// write SecretKey
std::ofstream secFile(secPath, std::ios::binary);
// actually generate a secret key with Hamming weight w
//Following original description WIP: addSome1DMatrices(secretKey);
secFile << secretKey;
secFile.close();
myLogger("privKey written");
}
/*
* encrypt function
* Parameter
* string ctxPath Path to context file
* string pubPath Path to PublicKey File
* string encNumberPath Path to encryptedNumber file
* long value Value to be encrypted
*/
void encrypt(string ctxPath, string pubPath, string encNumberPath, long value) {
// ----- Blog to read in Context ----- See readContext
vector<long> gens, ords;
unsigned long m, p, r;
std::ifstream ctxFile(ctxPath, std::ios::binary);
readContextBase(ctxFile, m, p, r, gens, ords);
FHEcontext context(m, p, r, gens, ords);
ctxFile >> context;
myLogger("context read");
ctxFile.close();
// -------End Blog to read in Context -----
//read file
std::ifstream pubFile(pubPath, std::ios::binary);
FHEPubKey pubKey(context);
pubFile >> pubKey;
pubFile.close();
myLogger("pubKey read");
// construct an Encrypted array object ea that is associated with the given context and the polynomial G
//Following original description WIP: ZZX G = context.alMod.getFactorsOverZZ()[0];
//Following original description WIP: EncryptedArray ea(context, G);
EncryptedArray ea(context);
myLogger("ea generated");
//creating cyphertext for each vector
Ctxt ct(pubKey);
myLogger("ct generated");
//creating & filling vectors with values
vector<long> v;
v.push_back(value);
myLogger("vector generated");
//Encrypt vectors with cyphertext, pukey and vector
//Following original description WIP: ea.encrypt(ct, pubKey, v);
pubKey.Encrypt(ct, NTL::to_ZZX(value));
myLogger("encrypted");
//write encNumber
std::ofstream encFile(encNumberPath, std::ios::binary);
encFile << ct;
encFile.close();
myLogger("written to file");
}
/*
* decrypt method
* Parameters:
* string ctxPath Path to context file
* string secPath Path to secretKey file
* string encNumberPath Path to encryptedNumber file
*/
void decrypt(string ctxPath, string secPath, string encNumberPath) {
// ----- Blog to read in Context ----- See readContext
vector<long> gens, ords;
unsigned long m, p, r;
std::ifstream ctxFile(ctxPath, std::ios::binary);
readContextBase(ctxFile, m, p, r, gens, ords);
FHEcontext context(m, p, r, gens, ords);
ctxFile >> context;
myLogger("context read");
ctxFile.close();
// -------End Blog to read in Context -----
//read secretKey
std::ifstream secFile(secPath, std::ios::binary);
FHESecKey secretKey(context);
secFile >> secretKey;
secFile.close();
myLogger("secKey read");
//build cypertext holder
Ctxt ct(secretKey);
//populate cypertxt
std::ifstream encFile(encNumberPath, std::ios::binary);
encFile >> ct;
encFile.close();
myLogger("ct read");
//decrypt cypertxt
NTL::ZZX poly;
secretKey.Decrypt(poly, ct);
myLogger("cyptertext encrypted");
//printout
std::cout << poly << "\n";
}
/*
* main reacts on input parameters: --> WIP still not clear about the correct description!
* Parameter description:
* m: unknown, but can be calculated by the function FindM() --> initally = 0
* p: max value of calculation, next prime number --> 257
* d: Count of inputvalues = Count(p) -->2
* r: Length of inputvalues in bit = Length (p) -->1
* L: Level parameter or Circuit depth --> should be as low as possible -->16
* c: Columns in key switching matrix --> recommended to be between 2/3 = 3
* w: Heming weight of keysize --> = 64
* k: security level parameter in bitsize =128
* s: bounds from below the number of plaintext slots that we want to support --> minimum(p)
* chosen_m: value for m to be checked if possible
* verbose: output true/false
*
* Nest if-else to handel different function callings
* function-command is always the first parameter: keyGen, encrypt, decrypt, mul, add, help or test
* Each function needs different parameters, to define patches to files or parameters. Following each function call is described in detail, which can also be called from the commandline using "help"
* keyGen: [publicKeyPath, secretKeyPath, contextPath, parameter p, parameter r, parameter L, parameter m] , if m=0 (unknown) parameter d is required to calculate it --> add parameter d
* encrypt: [publicKeyPath, contextPath, encryptedNumberPath, value]
* decrypt: [secretKeyPath, contextPath, encryptedNumberPath]
* mul: [publicKeyPath, contextPath, encryptedNumberPath, encryptedNumberPathtoBeMultiplyied, resultNumberPath]
* add: [publicKeyPath, contextPath, encryptedNumberPath, encryptedNumberPathtoBeAdded, resultNumberPath]
* test: [parameter p, parameter r, parameter L, parameter m, value A, value B]
* help: print out information
*/
int main(int argc, char **argv) {
typedef vector<string> CommandLineStringArgs;
CommandLineStringArgs cmdlineStringArgs(&argv[0], &argv[0 + argc]);
string function = cmdlineStringArgs[1];
if (DEBUG) {
myLogger("Start Function: " + function);
}
if (function == "keyGen") {
long p, r, L, m;
string pubPath = cmdlineStringArgs[2];
string secPath = cmdlineStringArgs[3];
string ctxPath = cmdlineStringArgs[4];
p = atol(cmdlineStringArgs[5].c_str());
r = atol(cmdlineStringArgs[6].c_str());
L = atol(cmdlineStringArgs[7].c_str());
m = atol(cmdlineStringArgs[8].c_str());
if (m == 0) {
//if m is not clear, calculate m with function FindM, therefore d is needed
long d;
d = atol(cmdlineStringArgs[9].c_str());
FHEcontext context(FindM(k, L, c, p, d, s, 0, false), p, r);
keyGen(context, L, pubPath, secPath, ctxPath);
} else {
//if m is set, directly use for context
FHEcontext context(m, p, r);
keyGen(context, L, pubPath, secPath, ctxPath);
}
} else if (function == "encrypt") {
string pubPath = cmdlineStringArgs[2];
string ctxPath = cmdlineStringArgs[3];
string encNumberPath = cmdlineStringArgs[4];
long value = atol(cmdlineStringArgs[5].c_str());
encrypt(ctxPath, pubPath, encNumberPath, value);
} else if (function == "decrypt") {
string secPath = cmdlineStringArgs[2];
string ctxPath = cmdlineStringArgs[3];
string encNumberPath = cmdlineStringArgs[4];
decrypt(ctxPath, secPath, encNumberPath);
} else if (function == "mul") {
string pubPath = cmdlineStringArgs[2];
string ctxPath = cmdlineStringArgs[3];
string encNumberPath1 = cmdlineStringArgs[4];
string encNumberPath2 = cmdlineStringArgs[5];
string resNumberPath = cmdlineStringArgs[6];
heMul(ctxPath, pubPath, encNumberPath1, encNumberPath2, resNumberPath);
} else if (function == "add") {
string pubPath = cmdlineStringArgs[2];
string ctxPath = cmdlineStringArgs[3];
string encNumberPath1 = cmdlineStringArgs[4];
string encNumberPath2 = cmdlineStringArgs[5];
string resNumberPath = cmdlineStringArgs[6];
heAdd(ctxPath, pubPath, encNumberPath1, encNumberPath2, resNumberPath);
} else if (function == "test") {
long p, r, L, m;
p = atol(cmdlineStringArgs[2].c_str());
r = atol(cmdlineStringArgs[3].c_str());
L = atol(cmdlineStringArgs[4].c_str());
m = atol(cmdlineStringArgs[5].c_str());
long valueA = atol(cmdlineStringArgs[6].c_str());
long valueB = atol(cmdlineStringArgs[7].c_str());
FHEcontext context(m, p, r);
if (DEBUG) {
myLogger("Entering keyGen ");
}
keyGen(context, L, "pub.key", "sec.key", "ctx.ctx");
if (DEBUG) {
myLogger("Entering encrypt ");
}
encrypt("ctx.ctx", "pub.key", "val1.ct", valueA);
if (DEBUG) {
myLogger("Entering encrypt ");
}
encrypt("ctx.ctx", "pub.key", "val2.ct", valueB);
if (DEBUG) {
myLogger("Entering add ");
}
heAdd("ctx.ctx", "pub.key", "val1.ct", "val2.ct", "res1.ct");
if (DEBUG) {
myLogger("Entering mul ");
}
heMul("ctx.ctx", "pub.key", "val1.ct", "val2.ct", "res2.ct");
if (DEBUG) {
myLogger("Entering decrypt (add) ");
}
decrypt("ctx.ctx", "sec.key", "res1.ct");
if (DEBUG) {
myLogger("Entering decrypt (mul) ");
}
decrypt("ctx.ctx", "sec.key", "res2.ct");
} else if (function == "help") {
printf( "function-command is always the first parameter: keyGen, encrypt, decrypt, mul, add, help or test \n");
printf( "Each function needs different parameters, to define patches to files or parameters. Following each function call is described in detail, which can also be called from the commandline using help \n");
printf( "- keyGen: [publicKeyPath, secretKeyPath, contextPath, parameter p, parameter r, parameter L, parameter m], if m=0 (unknown) parameter d is required to calculate it --> add parameter d \n");
printf( "- encrypt: [publicKeyPath, contextPath, encryptedNumberPath, value] \n");
printf( "- decrypt: [secretKeyPath, contextPath, encryptedNumberPath] \n");
printf( "- mul: [publicKeyPath, contextPath, encryptedNumberPath, encryptedNumberPathtoBeMultiplyied, resultNumberPath] \n");
printf( "- add: [publicKeyPath, contextPath, encryptedNumberPath, encryptedNumberPathtoBeAdded, resultNumberPath] \n");
printf( "- test: [parameter p, parameter r, parameter L, parameter m, value A, value B] \n");
} else {
printf("Command not found \n");
}
}
@Ang3er
Copy link
Author

Ang3er commented Jul 11, 2016

A commandline interface to interact with HElib. Each command awaits differnet parameters, the result ist always a writing of files to given pathes for each differnet task. The code is following the approach of CPS to devide different stages (keyGen, calculation, encrypt, decrypt) on differnet devices. Therefore I used files to transmit those between the different devices.
Szenario:
-A owner generated the keys: public, private and context
-A CPD (Cyper-Physical device) can read from the publickey and is able to encrypt sensor data with the context
-A second server in the cloud is allowed to calculate given encrypted numbers(vectors) with the public key and context
-The enduser is able to decrypt the calculated number in the cloud on his server by using the the known secretkey and context

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment