homenc / HElib

HElib is an open-source software library that implements homomorphic encryption. It supports the BGV scheme with bootstrapping and the Approximate Number CKKS scheme. HElib also includes optimizations for efficient homomorphic evaluation, focusing on effective use of ciphertext packing techniques and on the Gentry-Halevi-Smart optimizations.
https://homenc.github.io/HElib
Other
3.14k stars 765 forks source link

Question about set Residual Ring for HElib and inner product #329

Open kenmaro3 opened 4 years ago

kenmaro3 commented 4 years ago

miha.ken.19@gmail.com Your environment (OS/HW): OS ubuntu 18.04

Hello, I am new to HElib and sorry if I am missing very basic of implementation in HELib.

I would like to basically set coefficient on plaintext polynomial and take an inner product by Forward Backward packing. As is done in method2 in (https://mshcruz.wordpress.com/2016/09/27/scalar-product-using-helib/). I put my entire code below which I am trying to work on , so please take a look, description is as follows.

If let u1 and u2 be encryptedarray, u1 = [0,1] = 0 + 1x u2 = [0,0,....,1] = 0 + 0x + ..... + 0x^2378 + 1*x^2379 under m found to be 2381 by findM method in HElib.

then if I multiply u1 and u2, I expected u3 = u1*u2 = x^2380 = -1, so, u3 = [-1 0 0 .... 0]

however, I got instead u3 = [-1 -1 -1 .... -1]

This means Ring is set as Z[x]/(1x^2379 + 1x^2378 + .... + 1) instead of Z[x]/(1 + x^2380).

Is there any way to set the ring as Z[x]/(1 + x^2380) instead of Z[x]/(1x^2379 + 1x^2378 + .... + 1) ?

or should I dive into NTL library for this??

If you could any comment or suggestion, I would appreciate it. Thank you in advance,

Sincerely to HElib developpers.

#include <iostream>
#include <cstddef>
#include <tuple>
#include <sys/time.h>
#include "FHE.h"
#include "EncryptedArray.h"
#include <NTL/ZZX.h>
#include <NTL/ZZ.h>
#include <vector>

using namespace std;
using namespace NTL;

int main(){

//==========================================================================
//==========================================================================
// Encryption Parameters
// Finding m... Found m = 2381
// in this setting, -1 is mapped to 100002
// -2 is 100001, -3 is 100000 etc

    long p = 100003;                   // Plaintext base [default=2], should be a prime number
    long r = 1;                  // L = 60;
    long L = 60;
    long c = 2;                   // Number of columns in key-switching matrix [default=2]
    long w = 64;                  // Hamming weight of secret key
    long d = 1;                   // Degree of the field extension [default=1]
    long k = 80;                  // Security parameter [default=80]
    long s = 0;

  cout << "Finding m... " << flush;
  long m = FindM(k, L, c, p, d, s, 0);
  cout << "Found m = " << m << endl;   

  cout << "Initializing context... " << std::flush;
    FHEcontext* context = new FHEcontext(m,p,r);                      // Initialize context
    buildModChain(*context, L, c);                      // Modify the context, adding primes to the modulus chain
    cout << "OK!" << endl;

  cout << "Generating keys... " << flush;
    FHESecKey* sk = new FHESecKey(*context);
    FHEPubKey* pk = sk;

    sk->GenSecKey(w);                                   // Actually generate a secret key with Hamming weight
    addSome1DMatrices(*sk);                             // Extra information for relinearization
    cout << "OK!" << endl;     

//==========================================================================
//==========================================================================
// Prepare encrypted array for FB packing 
// number of slots = 2380

  // Get the number of slot (phi(m))
  const EncryptedArray& ea = *(context->ea);
  long nslots = ea.size();
  std::cout << "Number of slots: " << nslots << std::endl;

  ZZX u1, u2;
    u1.SetLength(nslots);
    u2.SetLength(nslots);
    cout << "something" << endl;

//==========================================================================
//==========================================================================
// Set coefficient of plaintext polynomial
// for example, u1 = [0,1] = 0 + 1x
//              u2 = [0,0,....,1] = 0 + 0x + ..... + 0x^2378 + 1*x^2379

// so basically we want when we multiply u1 and u2
// u1*u2 = x^2380 = -1, then I can use hayashi special
// however, actually this gives me u1*u2 = -1x^2379 -1x^2378 - ... - -1
// this means HELib uses the ring which is 
// Z[x]/(1x^2379 + 1x^2378 + .... + 1) instead of 
// Z[x]/(1 + x^2380)

// do you have any opinion or comment on this???

    SetCoeff(u1,0, 0);
    SetCoeff(u1,1, 1);

    SetCoeff(u2,nslots-1, 1);

    cout << u1 << endl;
    cout << u2 << endl;

    Ctxt c1(*pk);
    Ctxt c2(*pk);

    pk->Encrypt(c1, u1);    
    pk->Encrypt(c2, u2);

    cout << "============================================" << endl;
    cout << "============================================" << endl;
    cout << "c1 and c2 before multiplication"   << endl;
    ZZX dec1, dec2, dec3;
    sk->Decrypt(dec1, c1);
    sk->Decrypt(dec2, c2);

//==========================================================================
//==========================================================================
// dec1 = [0 1 0 ...... 0]
// dec2 = [0 0 0 ...... 1]
// so, we want 
// u1*u2 = [-1 0 ...... 0]
// however, we instead get
// u1*u2 = [-1 -1 ...... -1]

    cout << dec1 << endl;  
    cout << dec2 << endl;  

    cout << "============================================" << endl;
    cout << "============================================" << endl;
    cout << "c1 and c2 after multiplication"   << endl;
    c1*=c2;
    sk->Decrypt(dec3, c1);
    cout << dec3 << endl;

}