jeremyvillalobos - 6 months ago 43

C++ Question

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.