jeremyvillalobos jeremyvillalobos - 27 days ago 9
C++ Question

Running a hello world HElib program

After going over this tutorial

http://tommd.github.io/

which uses the HElib library:
https://github.com/shaih/HElib

I get the following output:

The output is getting corrupted. Given that the example has Level 16, there should be plenty of room to perform these operations.

Is there a problem with the parameters ?

Code:

#include "FHE.h"
#include "EncryptedArray.h"
#include <NTL/lzz_pXFactoring.h>
#include <fstream>
#include <sstream>
#include <sys/time.h>

using namespace std;
/**
*
*/
int main(int argc, char** argv) {

/* On our trusted system we generate a new key
* (or read one in) and encrypt the secret data set.
*/

long m=0, p=2, r=1; // Native plaintext space
// Computations will be 'modulo p'
long L=16; // Levels
long c=3; // Columns in key switching matrix
long w=64; // Hamming weight of secret key
long d=0;
long security = 128;
ZZX G;
m = FindM(security,L,c,p, d, 0, 0);

FHEcontext context(m, p, r);
// initialize context
buildModChain(context, L, c);
// modify the context, adding primes to the modulus chain
FHESecKey secretKey(context);
// construct a secret key structure
const FHEPubKey& publicKey = secretKey;
// an "upcast": FHESecKey is a subclass of FHEPubKey

//if(0 == d)
G = context.alMod.getFactorsOverZZ()[0];

secretKey.GenSecKey(w);
// actually generate a secret key with Hamming weight w

addSome1DMatrices(secretKey);
cout << "Generated key" << endl;


EncryptedArray ea(context, G);
// constuct an Encrypted array object ea that is
// associated with the given context and the polynomial G

long nslots = ea.size();

vector<long> v1;
for(int i = 0 ; i < nslots; i++) {
v1.push_back(i*2);
}
Ctxt ct1(publicKey);
ea.encrypt(ct1, publicKey, v1);

vector<long> v2;
Ctxt ct2(publicKey);
for(int i = 0 ; i < nslots; i++) {
v2.push_back(i*3);
}
ea.encrypt(ct2, publicKey, v2);

// On the public (untrusted) system we
// can now perform our computation

Ctxt ctSum = ct1;
Ctxt ctProd = ct1;

ctSum += ct2;
ctProd *= ct2;


vector<long> res;
ea.decrypt(ctSum, secretKey, res);

cout << "All computations are modulo " << p << "." << endl;
for(int i = 0; i < res.size(); i ++) {
cout << v1[i] << " + " << v2[i] << " = " << res[i] << endl;
}

ea.decrypt(ctProd, secretKey, res);
for(int i = 0; i < res.size(); i ++) {
cout << v1[i] << " * " << v2[i] << " = " << res[i] << endl;
}

return 0;
}


Generated key

All computations are modulo 2.

0 + 0 = 0

2 + 3 = 1

4 + 6 = 0

6 + 9 = 1

8 + 12 = 0

10 + 15 = 1

12 + 18 = 0

14 + 21 = 1

16 + 24 = 0

18 + 27 = 1

20 + 30 = 0

22 + 33 = 1

24 + 36 = 0

26 + 39 = 1

28 + 42 = 0

30 + 45 = 1

32 + 48 = 0

34 + 51 = 1

36 + 54 = 0

38 + 57 = 1

40 + 60 = 0

42 + 63 = 1

44 + 66 = 0

46 + 69 = 1

48 + 72 = 0

50 + 75 = 1

52 + 78 = 0

54 + 81 = 1

56 + 84 = 0

58 + 87 = 1

60 + 90 = 0

... Some sum output omitted

0 * 0 = 0
2 * 3 = 0
4 * 6 = 0
6 * 9 = 0
8 * 12 = 0
10 * 15 = 0
12 * 18 = 0
14 * 21 = 0
16 * 24 = 0
18 * 27 = 0
20 * 30 = 0
22 * 33 = 0
24 * 36 = 0
26 * 39 = 0
28 * 42 = 0
30 * 45 = 0
32 * 48 = 0
34 * 51 = 0
36 * 54 = 0
38 * 57 = 0
40 * 60 = 0
42 * 63 = 0
44 * 66 = 0
46 * 69 = 0
48 * 72 = 0
50 * 75 = 0
52 * 78 = 0
54 * 81 = 0
56 * 84 = 0
58 * 87 = 0
60 * 90 = 0
62 * 93 = 0
64 * 96 = 0
66 * 99 = 0
68 * 102 = 0
70 * 105 = 0
72 * 108 = 0
74 * 111 = 0
76 * 114 = 0
78 * 117 = 0
80 * 120 = 0
82 * 123 = 0
84 * 126 = 0
86 * 129 = 0

....

Answer

Ah, so this is a misunderstanding of the operations being performed. Notice the constant p=2. I have the text All computations are modulo 2.. Perhaps also stating All inputs are modulo 2 would help hammer the point home. Lets look at some of our computations:

0 + 0 mod 2 = 0
2 + 3 mod 2 = 1
4 + 6 mod 2 = 0
6 + 9 mod 2 = 1

All looks good - addition ring 2 is just exclusive OR. How about multiplication? In ring 2 (binary) that's just AND:

0 * 0 = 0
2 * 3 = 6 mod 2 = 0
4 * 6 = 24 mod 2 = 0
6 * 9 = 54 mod 2 = 0

So that all checks out as well. Finally, look back at the blog and see that I called this out again and give you a way to operate on something you might consider more pleasing:

In this case, I am building for GF(2) - so my homormorphic addition is XOR and multiplication is AND. Changing this is as easy as changing the value of p. Folks wanting to see 2+2=4 should set p to something that matches their desired domain, such as 257 to obtain 8 bit Ints.

However, HELib has regressed in this aspect - setting p equal to anything larger than 2 did not work last time I tried it. Shai confirmed this is a known regression.