int main(int argc, char *argv[]) {
    long m, p, r, L, R;
    ArgMapping argmap;
	MDL::Timer timer;
    argmap.arg("m", m, "m");
    argmap.arg("L", L, "L");
    argmap.arg("p", p, "p");
    argmap.arg("r", r, "r");
    argmap.arg("R", R, "R");
    argmap.parse(argc, argv);
	timer.start();
    FHEcontext context(m, p, r);
    buildModChain(context, L);
    FHESecKey sk(context);
    sk.GenSecKey(64);
    addSome1DMatrices(sk);
    FHEPubKey pk = sk;

    auto G       = context.alMod.getFactorsOverZZ()[0];
    EncryptedArray ea(context, G);
	timer.end();
    printf("slots %ld\n", ea.size());
	printf("Key Gen %f\n", timer.second());
    auto data = load_csv("adult.data", R);
    benchmark(ea, pk, sk, data);
}
Exemple #2
0
int main(int argc, char *argv[]) {
#ifdef USE_NETWORK
    ArgMapping mapping;
    long role = 0;
    std::string host = "127.0.0.1";
    mapping.arg("m", gM, "m");
    mapping.arg("p", gP, "p");
    mapping.arg("r", gR, "r");
    mapping.arg("L", gL, "L");
    mapping.arg("R", role, "role, 0:server, 1:client");
    mapping.arg("H", host, "host");
    mapping.arg("C", gC, "cipher to send");
    mapping.parse(argc, argv);

    if (role == 0) {
        int sock = nn_socket(AF_SP, NN_REP);
        if (nn_bind(sock, "tcp://*:12345") < 0) {
            printf("%s\n", nn_strerror(errno));
            return -1;
        }
        printf("SID %d\n", sock);
        act_server(sock);
    } else if (role == 1){
        int sock = nn_socket(AF_SP, NN_REQ);
        std::string h = "tcp://" + host + ":12345";
        if (nn_connect(sock, h.c_str()) < 0) {
            printf("%s\nn", nn_strerror(errno));
            return -1;
        }
        printf("SID %d\n", sock);
        act_client(sock);
    }
#endif
    return 0;
}
Exemple #3
0
int main(int argc, char *argv[]) 
{
  ArgMapping amap;

  long m=17;
  amap.arg("m", m, "cyclotomic index");
  amap.note("e.g., m=2047");

  long p=2;
  amap.arg("p", p, "plaintext base");

  long r=1;
  amap.arg("r", r,  "lifting");

  Vec<long> gens0;
  amap.arg("gens", gens0, "use specified vector of generators", NULL);
  amap.note("e.g., gens='[562 1871 751]'");

  Vec<long> ords0;
  amap.arg("ords", ords0, "use specified vector of orders", NULL);
  amap.note("e.g., ords='[4 2 -4]', negative means 'bad'");

  amap.parse(argc, argv);

  cout << "m = " << m << ", p = " << p <<  ", r = " << r << endl;

  vector<long> f;
  factorize(f,m);
  cout << "factoring "<<m<<" gives [";
  for (unsigned long i=0; i<f.size(); i++)
    cout << f[i] << " ";
  cout << "]\n";

  vector<long> gens1, ords1;
  convert(gens1, gens0);
  convert(ords1, ords0);

  PAlgebra al(m, p, gens1, ords1);
  al.printout();
  cout << "\n";

  PAlgebraMod almod(al, r);

  FHEcontext context(m, p, r);
  buildModChain(context, 5, 2);

  stringstream s1;
  writeContextBase(s1, context);
  s1 << context;

  string s2 = s1.str();

  cout << s2 << endl;

  stringstream s3(s2);

  unsigned long m1, p1, r1;
  vector<long> gens, ords;
  readContextBase(s3, m1, p1, r1, gens, ords);

  FHEcontext c1(m1, p1, r1, gens, ords);
  s3 >> c1;

  if (context == c1)
    cout << "equal\n";
  else
    cout << "not equal\n";

  return 0;
}
Exemple #4
0
int main(int argc, char *argv[]) 
{

  // Commandline setup

  ArgMapping amap;

  long m=16;
  long r=8;
  long L=0;
  double epsilon=0.01; // Accepted accuracy
  long R=1;
  long seed=0;
  bool debug = false;

  amap.arg("m", m, "Cyclotomic index");
  amap.note("e.g., m=1024, m=2047");
  amap.arg("r", r, "Bits of precision");
  amap.arg("R", R, "number of rounds");
  amap.arg("L", L, "Number of bits in modulus", "heuristic");
  amap.arg("ep", epsilon, "Accepted accuracy");
  amap.arg("seed", seed, "PRG seed");
  amap.arg("verbose", verbose, "more printouts");
  amap.arg("debug", debug, "for debugging");

  amap.parse(argc, argv);

  if (seed)
    NTL::SetSeed(ZZ(seed));

  if (R<=0) R=1;
  if (R<=2)
    L = 100*R;
  else
    L = 220*(R-1);

  if (verbose) {
    cout << "** m="<<m<<", #rounds="<<R<<", |q|="<<L
         << ", epsilon="<<epsilon<<endl;
  }
  epsilon /= R;
  try{

    // FHE setup keys, context, SKMs, etc

    FHEcontext context(m, /*p=*/-1, r);
    context.scale=4;
    buildModChain(context, L, /*c=*/2);

    FHESecKey secretKey(context);
    secretKey.GenSecKey(); // A +-1/0 secret key
    addSome1DMatrices(secretKey); // compute key-switching matrices

    const FHEPubKey publicKey = secretKey;
    const EncryptedArrayCx& ea = context.ea->getCx();

    if (verbose) {
      ea.getPAlgebra().printout();
      cout << "r = " << context.alMod.getR() << endl;
      cout << "ctxtPrimes="<<context.ctxtPrimes
           << ", specialPrimes="<<context.specialPrimes<<endl<<endl;
    }
    if (debug) {
        dbgKey = & secretKey;
        dbgEa = (EncryptedArray*) context.ea;
    }

    // Run the tests.
    testBasicArith(publicKey, secretKey, ea, epsilon);
    testComplexArith(publicKey, secretKey, ea, epsilon);
    testRotsNShifts(publicKey, secretKey, ea, epsilon);
    testGeneralOps(publicKey, secretKey, ea, epsilon*R, R);
  } 
  catch (exception& e) {
    cerr << e.what() << endl;
    cerr << "***Major FAIL***" << endl;  
  }

  return 0;
}
Exemple #5
0
// Testing the I/O of the important classes of the library
// (context, keys, ciphertexts).
int main(int argc, char *argv[])
{
  ArgMapping amap;

  long r=1;
  long p=2;
  long c = 2;
  long w = 64;
  long L = 5;
  long mm=0;
  amap.arg("p", p, "plaintext base");
  amap.arg("r", r,  "lifting");
  amap.arg("c", c, "number of columns in the key-switching matrices");
  amap.arg("m", mm, "cyclotomic index","{31,127,1023}");
  amap.parse(argc, argv);

  bool useTable = (mm==0 && p==2);
  long ptxtSpace = power_long(p,r);
  long numTests = useTable? N_TESTS : 1;

  std::unique_ptr<FHEcontext> contexts[numTests];
  std::unique_ptr<FHESecKey> sKeys[numTests];
  std::unique_ptr<Ctxt> ctxts[numTests];
  std::unique_ptr<EncryptedArray> eas[numTests];
  vector<ZZX> ptxts[numTests];

  // first loop: generate stuff and write it to cout

  // open file for writing
  {fstream keyFile("iotest.txt", fstream::out|fstream::trunc);
   assert(keyFile.is_open());
  for (long i=0; i<numTests; i++) {
    long m = (mm==0)? ms[i][1] : mm;

    cout << "Testing IO: m="<<m<<", p^r="<<p<<"^"<<r<<endl;

    Vec<long> mvec(INIT_SIZE,2);
    mvec[0] = ms[i][4];  mvec[1] = ms[i][5];
    vector<long> gens(2);
    gens[0] = ms[i][6];  gens[1] = ms[i][7];
    vector<long> ords(2);
    ords[0] = ms[i][8];  ords[1] = ms[i][9];

    if (useTable && gens[0]>0)
      contexts[i].reset(new FHEcontext(m, p, r, gens, ords));
    else
      contexts[i].reset(new FHEcontext(m, p, r));
    contexts[i]->zMStar.printout();

    buildModChain(*contexts[i], L, c);  // Set the modulus chain
    if (mm==0 && m==1023) contexts[i]->makeBootstrappable(mvec);

    // Output the FHEcontext to file
    writeContextBase(keyFile, *contexts[i]);
    writeContextBase(cout, *contexts[i]);
    keyFile << *contexts[i] << endl;

    sKeys[i].reset(new FHESecKey(*contexts[i]));
    const FHEPubKey& publicKey = *sKeys[i];
    sKeys[i]->GenSecKey(w,ptxtSpace); // A Hamming-weight-w secret key
    addSome1DMatrices(*sKeys[i]);// compute key-switching matrices that we need
    eas[i].reset(new EncryptedArray(*contexts[i]));

    long nslots = eas[i]->size();

    // Output the secret key to file, twice. Below we will have two copies
    // of most things.
    keyFile << *sKeys[i] << endl;;
    keyFile << *sKeys[i] << endl;;

    vector<ZZX> b;
    long p2r = eas[i]->getContext().alMod.getPPowR();
    ZZX poly = RandPoly(0,to_ZZ(p2r)); // choose a random constant polynomial
    eas[i]->decode(ptxts[i], poly);

    ctxts[i].reset(new Ctxt(publicKey));
    eas[i]->encrypt(*ctxts[i], publicKey, ptxts[i]);
    eas[i]->decrypt(*ctxts[i], *sKeys[i], b);
    assert(ptxts[i].size() == b.size());
    for (long j = 0; j < nslots; j++) assert (ptxts[i][j] == b[j]);

    // output the plaintext
    keyFile << "[ ";
    for (long j = 0; j < nslots; j++) keyFile << ptxts[i][j] << " ";
    keyFile << "]\n";

    eas[i]->encode(poly,ptxts[i]);
    keyFile << poly << endl;

    // Output the ciphertext to file
    keyFile << *ctxts[i] << endl;
    keyFile << *ctxts[i] << endl;
    cerr << "okay " << i << endl<< endl;
  }
  keyFile.close();}
  cerr << "so far, so good\n\n";

  // second loop: read from input and repeat the computation

  // open file for read
  {fstream keyFile("iotest.txt", fstream::in);
  for (long i=0; i<numTests; i++) {

    // Read context from file
    unsigned long m1, p1, r1;
    vector<long> gens, ords;
    readContextBase(keyFile, m1, p1, r1, gens, ords);
    FHEcontext tmpContext(m1, p1, r1, gens, ords);
    keyFile >> tmpContext;
    assert (*contexts[i] == tmpContext);
    cerr << i << ": context matches input\n";

    // We define some things below wrt *contexts[i], not tmpContext.
    // This is because the various operator== methods check equality of
    // references, not equality of the referenced FHEcontext objects.
    FHEcontext& context = *contexts[i];
    FHESecKey secretKey(context);
    FHESecKey secretKey2(tmpContext);
    const FHEPubKey& publicKey = secretKey;
    const FHEPubKey& publicKey2 = secretKey2;

    keyFile >> secretKey;
    keyFile >> secretKey2;
    assert(secretKey == *sKeys[i]);
    cerr << "   secret key matches input\n";

    EncryptedArray ea(context);
    EncryptedArray ea2(tmpContext);

    long nslots = ea.size();

    // Read the plaintext from file
    vector<ZZX> a;
    a.resize(nslots);
    assert(nslots == (long)ptxts[i].size());
    seekPastChar(keyFile, '['); // defined in NumbTh.cpp
    for (long j = 0; j < nslots; j++) {
      keyFile >> a[j];
      assert(a[j] == ptxts[i][j]);
    }
    seekPastChar(keyFile, ']');
    cerr << "   ptxt matches input\n";

    // Read the encoded plaintext from file
    ZZX poly1, poly2;
    keyFile >> poly1;
    eas[i]->encode(poly2,a);
    assert(poly1 == poly2);
    cerr << "   eas[i].encode(a)==poly1 okay\n";

    ea.encode(poly2,a);
    assert(poly1 == poly2);
    cerr << "   ea.encode(a)==poly1 okay\n";

    ea2.encode(poly2,a);
    assert(poly1 == poly2);
    cerr << "   ea2.encode(a)==poly1 okay\n";

    eas[i]->decode(a,poly1);
    assert(nslots == (long)a.size());
    for (long j = 0; j < nslots; j++) assert(a[j] == ptxts[i][j]);
    cerr << "   eas[i].decode(poly1)==ptxts[i] okay\n";

    ea.decode(a,poly1);
    assert(nslots == (long)a.size());
    for (long j = 0; j < nslots; j++) assert(a[j] == ptxts[i][j]);
    cerr << "   ea.decode(poly1)==ptxts[i] okay\n";

    ea2.decode(a,poly1);
    assert(nslots == (long)a.size());
    for (long j = 0; j < nslots; j++) assert(a[j] == ptxts[i][j]);
    cerr << "   ea2.decode(poly1)==ptxts[i] okay\n";

    // Read ciperhtext from file
    Ctxt ctxt(publicKey);
    Ctxt ctxt2(publicKey2);
    keyFile >> ctxt;
    keyFile >> ctxt2;
    assert(ctxts[i]->equalsTo(ctxt,/*comparePkeys=*/false));
    cerr << "   ctxt matches input\n";

    sKeys[i]->Decrypt(poly2,*ctxts[i]);
    assert(poly1 == poly2);
    cerr << "   sKeys[i]->decrypt(*ctxts[i]) == poly1 okay\n";

    secretKey.Decrypt(poly2,*ctxts[i]);
    assert(poly1 == poly2);
    cerr << "   secretKey.decrypt(*ctxts[i]) == poly1 okay\n";

    secretKey.Decrypt(poly2,ctxt);
    assert(poly1 == poly2);
    cerr << "   secretKey.decrypt(ctxt) == poly1 okay\n";

    secretKey2.Decrypt(poly2,ctxt2);
    assert(poly1 == poly2);
    cerr << "   secretKey2.decrypt(ctxt2) == poly1 okay\n";

    eas[i]->decrypt(ctxt, *sKeys[i], a);
    assert(nslots == (long)a.size());
    for (long j = 0; j < nslots; j++) assert(a[j] == ptxts[i][j]);
    cerr << "   eas[i].decrypt(ctxt, *sKeys[i])==ptxts[i] okay\n";

    ea.decrypt(ctxt, secretKey, a);
    assert(nslots == (long)a.size());
    for (long j = 0; j < nslots; j++) assert(a[j] == ptxts[i][j]);
    cerr << "   ea.decrypt(ctxt, secretKey)==ptxts[i] okay\n";

    ea2.decrypt(ctxt2, secretKey2, a);
    assert(nslots == (long)a.size());
    for (long j = 0; j < nslots; j++) assert(a[j] == ptxts[i][j]);
    cerr << "   ea2.decrypt(ctxt2, secretKey2)==ptxts[i] okay\n";

    cerr << "test "<<i<<" okay\n\n";
  }}
  unlink("iotest.txt"); // clean up before exiting
}
Exemple #6
0
/* Usage: Test_EvalMap_x.exe [ name=value ]...
 *  p       plaintext base  [ default=2 ]
 *  r       lifting  [ default=1 ]
 *  c       number of columns in the key-switching matrices  [ default=2 ]
 *  k       security parameter  [ default=80 ]
 *  L       # of bits in the modulus chain 
 *  s       minimum number of slots  [ default=0 ]
 *  seed    PRG seed  [ default=0 ]
 *  mvec    use specified factorization of m
 *             e.g., mvec='[5 3 187]'
 *  gens    use specified vector of generators
 *             e.g., gens='[562 1871 751]'
 *  ords    use specified vector of orders
 *             e.g., ords='[4 2 -4]', negative means 'bad'
 */
int main(int argc, char *argv[])
{
  ArgMapping amap;

  long p=2;
  amap.arg("p", p, "plaintext base");

  long r=1;
  amap.arg("r", r,  "lifting");

  long c=2;
  amap.arg("c", c, "number of columns in the key-switching matrices");
  
  long k=80;
  amap.arg("k", k, "security parameter");

  long L=300;
  amap.arg("L", L, "# of bits in the modulus chain");

  long s=0;
  amap.arg("s", s, "minimum number of slots");

  long seed=0;
  amap.arg("seed", seed, "PRG seed");

  Vec<long> mvec;
  amap.arg("mvec", mvec, "use specified factorization of m", NULL);
  amap.note("e.g., mvec='[7 3 221]'");

  Vec<long> gens;
  amap.arg("gens", gens, "use specified vector of generators", NULL);
  amap.note("e.g., gens='[3979 3095 3760]'");

  Vec<long> ords;
  amap.arg("ords", ords, "use specified vector of orders", NULL);
  amap.note("e.g., ords='[6 2 -8]', negative means 'bad'");

  amap.arg("dry", dry, "a dry-run flag to check the noise");

  long nthreads=1;
  amap.arg("nthreads", nthreads, "number of threads");

  amap.arg("noPrint", noPrint, "suppress printouts");

  long useCache=0;
  amap.arg("useCache", useCache, "0: zzX cache, 2: DCRT cache");

  amap.parse(argc, argv);

  SetNumThreads(nthreads);

  SetSeed(conv<ZZ>(seed));
  TestIt(p, r, c, k, L, mvec, gens, ords, useCache);
}
Exemple #7
0
NTL_CLIENT



//namespace NTL { extern double ip_time; }

int main(int argc, char **argv)
{
   ArgMapping amap;

   long n = 1024;
   amap.arg("n", n, "degree bound");

   long l = 1024;
   amap.arg("l", l, "coeff bound");

   long nt = 1;
   amap.arg("nt", nt, "num threads");

   amap.parse(argc, argv);

   cerr << "\n\n=============================\n\n";

   cerr << "n=" << n << "\n";
   cerr << "l=" << l << "\n";
   cerr << "nt=" << nt << "\n";

   SetSeed(ZZ(0));

   SetNumThreads(nt);

   ZZ p;

   RandomPrime(p, l);
   ZZ_p::init(p);


   ZZ_pX f;

   random(f, n);
   SetCoeff(f, n);

   Vec< Pair<ZZ_pX, long> > fac;


   double t;

   ZZ_pXFileThresh = 1e9;



   FILE *fp;
   unsigned long A[4], B[4];
   int loadavg;

   fp = fopen("/proc/stat","r");
   fscanf(fp,"cpu %lu %lu %lu %lu",&A[0],&A[1],&A[2],&A[3]);
   fclose(fp);
   
   
   t = GetTime();
   CanZass(fac, f, 1);
   t = GetTime()-t;
   double NTLTime = t;

   fp = fopen("/proc/stat","r");
   fscanf(fp,"cpu %lu %lu %lu %lu",&B[0],&B[1],&B[2],&B[3]);
   fclose(fp);
   
   // we multiply by 20 -- that's the total number of cores
   loadavg = int(100.0*20.0*double((B[0]+B[1]+B[2]) - (A[0]+A[1]+A[2])) / 
      double((B[0]+B[1]+B[2]+B[3]) - (A[0]+A[1]+A[2]+A[3])));
   fprintf(stderr, "CPU utilization: %d\%\n",loadavg);

   struct rusage rusage;
   getrusage( RUSAGE_SELF, &rusage );

   cerr << "MAX_RSS="<<rusage.ru_maxrss <<  "KB" << endl;
   cerr << "Fac: " << t << "\n";

   //cerr << "ip_time: " << ip_time << "\n";

   delete NTLThreadPool;
   NTLThreadPool = 0;


}
int main(int argc, char *argv[]) 
{
  ArgMapping amap;

  long p=2;
  long r=1;
  long c=3;
  long L=600;
  long N=0;
  long t=0;
  long nthreads=1;

  long seed=0;
  long useCache=1;

  amap.arg("p", p, "plaintext base");

  amap.arg("r", r,  "exponent");
  amap.note("p^r is the plaintext-space modulus");

  amap.arg("c", c, "number of columns in the key-switching matrices");
  amap.arg("L", L, "# of levels in the modulus chain");
  amap.arg("N", N, "lower-bound on phi(m)");
  amap.arg("t", t, "Hamming weight of recryption secret key", "heuristic");
  amap.arg("dry", dry, "dry=1 for a dry-run");
  amap.arg("nthreads", nthreads, "number of threads");
  amap.arg("seed", seed, "random number seed");
  amap.arg("noPrint", noPrint, "suppress printouts");
  amap.arg("useCache", useCache, "0: zzX cache, 1: DCRT cache");

  amap.arg("force_bsgs", fhe_test_force_bsgs);
  amap.arg("force_hoist", fhe_test_force_hoist);

  //  amap.arg("disable_intFactor", fhe_disable_intFactor);
  amap.arg("chen_han", fhe_force_chen_han);

  amap.arg("debug", debug, "generate debugging output");
  amap.arg("scale", scale, "scale parameter");


  amap.parse(argc, argv);

  if (seed) 
    SetSeed(ZZ(seed));

  SetNumThreads(nthreads);

  for (long i=0; i<(long)num_mValues; i++)
    if (mValues[i][0]==p && mValues[i][1]>=N) {
      TestIt(i,p,r,L,c,t,useCache);
      break;
    }

  return 0;
}
Exemple #9
0
int main(int argc, char *argv[]) 
{
  ArgMapping amap;

  bool dry=false;
  amap.arg("dry", dry, "dry=1 for a dry-run");

  long m=2047;
  amap.arg("m", m, "cyclotomic ring");

  long p=2;
  amap.arg("p", p, "plaintext base");

  long r=1;
  amap.arg("r", r,  "lifting");

  long d=1;
  amap.arg("d", d, "degree of the field extension");
  amap.note("d == 0 => factors[0] defines extension");

  long L=3;
  amap.arg("L", L, "# of levels in the modulus chain",  "heuristic");

  long bnd = 64;
  amap.arg("bnd", bnd, "recursion bound for replication");

  long B = 0;
  amap.arg("B", B, "bound for # of replications", "all");

  amap.parse(argc, argv);
  setDryRun(dry);

  TestIt(m, p, r, d, L, bnd, B);
  cout << endl;
}
Exemple #10
0
int main(int argc, char *argv[]) 
{
  ArgMapping amap;
  amap.arg("noPrint", noPrint, "suppress printouts");

  long m=16;
  amap.arg("m", m, "cyclotomic index");
  amap.note("e.g., m=1024, m=2047");

  long r=8;
  amap.arg("r", r, "bit of precision");
  amap.parse(argc, argv);

  if (!noPrint) {
    vector<long> f;
    factorize(f,m);
    cout << "r="<<r<<", factoring "<<m<<" gives [";
    for (unsigned long i=0; i<f.size(); i++)
      cout << f[i] << " ";
    cout << "]\n";
  }

  FHEcontext context(m, /*p=*/-1, r);
  buildModChain(context, 5, 2);

  const EncryptedArrayCx& ea = context.ea->getCx();
  if (!noPrint)
    ea.getPAlgebra().printout();

#ifdef DEBUG_PRINTOUT
  vector<cx_double> vc1;
  ea.random(vc1);
  cout << "random complex vc1=";
  printVec(cout,vc1,8)<<endl;

  vector<double> vd;
  ea.random(vd);
  cout << "random real vd=";
  printVec(cout,vd,8)<<endl;
#endif

  vector<double> vl;
  ea.random(vl);
  vl[1] = -1; // ensure that this is not the zero vector
#ifdef DEBUG_PRINTOUT
  cout << "random int v=";
  printVec(cout,vl,8)<<endl;
#endif

  zzX poly;
  double factor = ea.encode(poly, vl, 1.0);
  if (!noPrint) {
    ZZX poly2;
    convert(poly2, poly);
    cout << "  encoded into a degree-"<<NTL::deg(poly2)<<" polynomial\n";
  }

  vector<double> vd2;
  ea.decode(vd2, poly, factor);
#ifdef DEBUG_PRINTOUT
  cout << "  decoded into vd2=";
  printVec(cout,vd2,8)<<endl;
#endif
  assert(lsize(vl)==lsize(vd2));

  double maxDiff = 0.0;
  for (long i=0; i<lsize(vl); i++) {
    double diffAbs = std::abs(vl[i]-vd2[i]);
    if (diffAbs > maxDiff)
      maxDiff = diffAbs;
  }
  cout << ((maxDiff>0.1)? "BAD?" : "GOOD?")
       << "  max |v-vd2|_{infty}="<<maxDiff
       << endl;
  return 0;
}
Exemple #11
0
int main(int argc, char *argv[]) 
{
  ArgMapping amap;

  long m=53;
  amap.arg("m", m, "use specified value as modulus");

  long p=17;
  amap.arg("p", p, "plaintext base");

  long r=1;
  amap.arg("r", r,  "lifting");

  long levels=5;
  amap.arg("L", levels,  "levels");

  long nb_coeffs=5;
  amap.arg("n", nb_coeffs,  "nb coefficients to extract");

  amap.parse(argc, argv);

  cout << "\n\n******** generate parameters"
       << " m=" << m 
       << ", p=" << p
       << ", r=" << r
       << ", n=" << nb_coeffs
       << endl;

  setTimersOn();

  FHEcontext context(m, p, r);
  buildModChain(context, /*L=*/levels);
  // cout << context << endl;
  // context.zMStar.printout();
  // cout << endl;

  cout << "Generating keys and key-switching matrices... " << std::flush;
  FHESecKey secretKey(context);
  secretKey.GenSecKey(/*w=*/64);// A Hamming-weight-w secret key
  addFrbMatrices(secretKey); // compute key-switching matrices that we need
  add1DMatrices(secretKey); // compute key-switching matrices that we need
  const FHEPubKey& publicKey = secretKey;
  cout << "done\n";

  resetAllTimers();

  EncryptedArray ea = *(context.ea);
  ea.buildLinPolyMat(false);

  Ctxt ctxt(publicKey);
  NewPlaintextArray ptxt(ea);
  random(ea, ptxt);
  // ea.encrypt(ctxt, publicKey, ptxt);
  ea.skEncrypt(ctxt, secretKey, ptxt);


  cout << "Extracting " << nb_coeffs << " coefficients...";
  vector<Ctxt> coeffs;
  extractCoeffs(ea, coeffs, ctxt, nb_coeffs);
  cout << "done\n";

  vector<ZZX> ptxtDec;
  ea.decrypt(ctxt, secretKey, ptxtDec);

  for (long i=0; i<(long)coeffs.size(); i++) {
    if (!coeffs[i].isCorrect()) {
      cerr << " potential decryption error for "<<i<<"th coeffs " << endl;
      CheckCtxt(coeffs[i], "");
      exit(0);
    }
    vector<ZZX> pCoeffs;
    ea.decrypt(coeffs[i], secretKey, pCoeffs);

    assert(pCoeffs.size() == ptxtDec.size());

    for (int j = 0; j < pCoeffs.size(); ++j) {
      if (coeff(pCoeffs[j], 0) != coeff(ptxtDec[j], i)) {
        cerr << "error: extracted coefficient " << i << " from " 
          "slot " << j << " is " << coeff(pCoeffs[j], 0) << " instead of " << 
          coeff(ptxtDec[j], i) << endl;
        exit(0);
      }
    }

  }  
  cerr << "Extracted coefficient successfully verified!\n";
}