HElib  1.0
Implementing Homomorphic Encryption
 All Classes Files Functions Variables Friends Pages
EncryptedArray.h
Go to the documentation of this file.
1 /* Copyright (C) 2012,2013 IBM Corp.
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10  * See the GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License along
13  * with this program; if not, write to the Free Software Foundation, Inc.,
14  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15  */
16 #ifndef _EncryptedArray_H_
17 #define _EncryptedArray_H_
18 
22 #include "FHE.h"
23 #include <NTL/ZZ_pX.h>
24 #include <NTL/GF2X.h>
25 #include <NTL/ZZX.h>
26 
27 class PlaintextArray; // forward reference
28 
62 class EncryptedArrayBase { // purely abstract interface
63 public:
64  virtual ~EncryptedArrayBase() {}
65 
66  virtual EncryptedArrayBase* clone() const = 0;
67  // makes this usable with cloned_ptr
68 
69  virtual const FHEcontext& getContext() const = 0;
70  virtual const long getDegree() const = 0;
71 
73  virtual void rotate(Ctxt& ctxt, long k) const = 0;
74 
76  virtual void shift(Ctxt& ctxt, long k) const = 0;
77 
82  virtual void rotate1D(Ctxt& ctxt, long i, long k, bool dc=false) const = 0;
83 
85  virtual void shift1D(Ctxt& ctxt, long i, long k) const = 0;
86 
89  // encode/decode arrays into plaintext polynomials
90  virtual void encode(ZZX& ptxt, const vector< long >& array) const = 0;
91  virtual void encode(ZZX& ptxt, const vector< ZZX >& array) const = 0;
92  virtual void encode(ZZX& ptxt, const PlaintextArray& array) const = 0;
93  virtual void decode(vector< long >& array, const ZZX& ptxt) const = 0;
94  virtual void decode(vector< ZZX >& array, const ZZX& ptxt) const = 0;
95  virtual void decode(PlaintextArray& array, const ZZX& ptxt) const = 0;
96 
98  virtual void encodeUnitSelector(ZZX& ptxt, long i) const = 0;
100 
103  virtual void encrypt(Ctxt& ctxt, const FHEPubKey& pKey, const vector< long >& ptxt) const = 0;
104  virtual void encrypt(Ctxt& ctxt, const FHEPubKey& pKey, const vector< ZZX >& ptxt) const = 0;
105  virtual void encrypt(Ctxt& ctxt, const FHEPubKey& pKey, const PlaintextArray& ptxt) const = 0;
106  virtual void decrypt(const Ctxt& ctxt, const FHESecKey& sKey, vector< long >& ptxt) const = 0;
107  virtual void decrypt(const Ctxt& ctxt, const FHESecKey& sKey, vector< ZZX >& ptxt) const = 0;
108  virtual void decrypt(const Ctxt& ctxt, const FHESecKey& sKey, PlaintextArray& ptxt) const = 0;
110 
112 
113  virtual void select(Ctxt& ctxt1, const Ctxt& ctxt2, const vector< long >& selector) const = 0;
114  virtual void select(Ctxt& ctxt1, const Ctxt& ctxt2, const vector< ZZX >& selector) const = 0;
115  virtual void select(Ctxt& ctxt1, const Ctxt& ctxt2, const PlaintextArray& selector) const = 0;
117 
125  virtual void buildLinPolyCoeffs(vector<ZZX>& C, const vector<ZZX>& L) const=0;
126 
127  /* some non-virtual convenience functions */
128 
130  long size() const { return getContext().zMStar.getNSlots(); }
131 
133  long dimension() const { return getContext().zMStar.numOfGens(); }
134 
136  long sizeOfDimension(long i) const {return getContext().zMStar.OrderOf(i);}
137 
139  long nativeDimension(long i) const {return getContext().zMStar.SameOrd(i);}
140 
142  long coordinate(long i, long k) const {return getContext().zMStar.coordinate(i, k); }
143 };
144 
149 template<class type> class EncryptedArrayDerived : public EncryptedArrayBase {
150 public:
151  PA_INJECT(type)
152 
153 private:
154  const FHEcontext& context;
155  MappingData<type> mappingData;
156 
157 public:
158  explicit
159  EncryptedArrayDerived(const FHEcontext& _context, const RX& _G = RX(1, 1));
160 
161  EncryptedArrayDerived(const EncryptedArrayDerived& other) // copy constructor
162  : context(other.context)
163  {
164  RBak bak; bak.save(); context.alMod.restoreContext();
165  mappingData = other.mappingData;
166  }
167 
168  EncryptedArrayDerived& operator=(const EncryptedArrayDerived& other) // assignment
169  {
170  if (this == &other) return *this;
171  assert(&context == &other.context);
172 
173  RBak bak; bak.save(); context.alMod.restoreContext();
174  mappingData = other.mappingData;
175  return *this;
176  }
177 
178  virtual EncryptedArrayBase* clone() const { return new EncryptedArrayDerived(*this); }
179 
180  const RX& getG() const { return mappingData.getG(); }
181 
182  virtual const FHEcontext& getContext() const { return context; }
183  virtual const long getDegree() const { return mappingData.getDegG(); }
184 
185 
186 
187  virtual void rotate(Ctxt& ctxt, long k) const;
188  virtual void shift(Ctxt& ctxt, long k) const;
189  virtual void rotate1D(Ctxt& ctxt, long i, long k, bool dc=false) const;
190  virtual void shift1D(Ctxt& ctxt, long i, long k) const;
191 
192  virtual void encode(ZZX& ptxt, const vector< long >& array) const
193  { genericEncode(ptxt, array); }
194 
195  virtual void encode(ZZX& ptxt, const vector< ZZX >& array) const
196  { genericEncode(ptxt, array); }
197 
198  virtual void encode(ZZX& ptxt, const PlaintextArray& array) const;
199 
200  virtual void encodeUnitSelector(ZZX& ptxt, long i) const;
201 
202  virtual void decode(vector< long >& array, const ZZX& ptxt) const
203  { genericDecode(array, ptxt); }
204 
205  virtual void decode(vector< ZZX >& array, const ZZX& ptxt) const
206  { genericDecode(array, ptxt); }
207 
208  virtual void decode(PlaintextArray& array, const ZZX& ptxt) const;
209 
210  virtual void encrypt(Ctxt& ctxt, const FHEPubKey& pKey, const vector< long >& ptxt) const
211  { genericEncrypt(ctxt, pKey, ptxt); }
212 
213  virtual void encrypt(Ctxt& ctxt, const FHEPubKey& pKey, const vector< ZZX >& ptxt) const
214  { genericEncrypt(ctxt, pKey, ptxt); }
215 
216  virtual void encrypt(Ctxt& ctxt, const FHEPubKey& pKey, const PlaintextArray& ptxt) const
217  { genericEncrypt(ctxt, pKey, ptxt); }
218 
219  virtual void decrypt(const Ctxt& ctxt, const FHESecKey& sKey, vector< long >& ptxt) const
220  { genericDecrypt(ctxt, sKey, ptxt); }
221 
222  virtual void decrypt(const Ctxt& ctxt, const FHESecKey& sKey, vector< ZZX >& ptxt) const
223  { genericDecrypt(ctxt, sKey, ptxt); }
224 
225  virtual void decrypt(const Ctxt& ctxt, const FHESecKey& sKey, PlaintextArray& ptxt) const
226  { genericDecrypt(ctxt, sKey, ptxt); }
227 
228  virtual void select(Ctxt& ctxt1, const Ctxt& ctxt2, const vector< long >& selector) const
229  { genericSelect(ctxt1, ctxt2, selector); }
230 
231  virtual void select(Ctxt& ctxt1, const Ctxt& ctxt2, const vector< ZZX >& selector) const
232  { genericSelect(ctxt1, ctxt2, selector); }
233 
234  virtual void select(Ctxt& ctxt1, const Ctxt& ctxt2, const PlaintextArray& selector) const
235  { genericSelect(ctxt1, ctxt2, selector); }
236 
237  /* the following are specialized methods, used to work over extension fields...they assume
238  the modulus context is already set
239  */
240 
241  void encode(ZZX& ptxt, const vector< RX >& array) const;
242  void decode(vector< RX >& array, const ZZX& ptxt) const;
243 
244  void encrypt(Ctxt& ctxt, const FHEPubKey& pKey, const vector< RX >& ptxt) const
245  { genericEncrypt(ctxt, pKey, ptxt); }
246 
247  void decrypt(const Ctxt& ctxt, const FHESecKey& sKey, vector< RX >& ptxt) const
248  { genericDecrypt(ctxt, sKey, ptxt); }
249 
250  void buildLinPolyCoeffs(vector<ZZX>& C, const vector<ZZX>& L) const;
251 
252 
253 private:
254 
255  /* helper template methods, to avoid repetitive code */
256 
257  template<class T>
258  void genericEncode(ZZX& ptxt, const T& array) const
259  {
260  RBak bak; bak.save(); context.alMod.restoreContext();
261 
262  vector< RX > array1;
263  convert(array1, array);
264  encode(ptxt, array1);
265  }
266 
267  template<class T>
268  void genericDecode(T& array, const ZZX& ptxt) const
269  {
270  RBak bak; bak.save(); context.alMod.restoreContext();
271 
272  vector< RX > array1;
273  decode(array1, ptxt);
274  convert(array, array1);
275  }
276 
277  template<class T>
278  void genericEncrypt(Ctxt& ctxt, const FHEPubKey& pKey,
279  const T& array) const
280  {
281  assert(&context == &ctxt.getContext());
282  ZZX pp;
283  encode(pp, array); // Convert the array of slots into a plaintext polynomial
284  pKey.Encrypt(ctxt, pp); // encrypt the plaintext polynomial
285  }
286 
287  template<class T>
288  void genericDecrypt(const Ctxt& ctxt, const FHESecKey& sKey,
289  T& array) const
290  {
291  assert(&context == &ctxt.getContext());
292  ZZX pp;
293  sKey.Decrypt(pp, ctxt);
294  decode(array, pp);
295  }
296 
297  template<class T>
298  void genericSelect(Ctxt& ctxt1, const Ctxt& ctxt2,
299  const T& selector) const
300  {
301  if (&ctxt1 == &ctxt2) return; // nothing to do
302 
303  assert(&context == &ctxt1.getContext() && &context == &ctxt2.getContext());
304  ZZX poly;
305  encode(poly,selector); // encode as polynomial
306  DoubleCRT dcrt(poly, context, ctxt1.getPrimeSet());// convert to DoubleCRT
307 
308  ctxt1.multByConstant(dcrt); // keep only the slots with 1's
309 
310  dcrt -= 1; // convert 1 => 0, 0 => -1
311  Ctxt tmp=ctxt2; // a copy of ctxt2
312  tmp.multByConstant(dcrt);// keep (but negate) only the slots with 0's
313  ctxt1 -= tmp;
314  }
315 };
316 
318 EncryptedArrayBase* buildEncryptedArray(const FHEcontext& context, const ZZX& G);
319 
320 
321 
326 private:
327  cloned_ptr<EncryptedArrayBase> rep;
328 
329 public:
330 
332  EncryptedArray(const FHEcontext& context, const ZZX& G = ZZX(1, 1))
333  : rep(buildEncryptedArray(context, G))
334  { }
335 
336  // copy constructor: default
337  // assignment: default
338 
341  template<class type>
343  { return dynamic_cast< const EncryptedArrayDerived<type>& >( *rep ); }
344 
345 
348 
349  const FHEcontext& getContext() const { return rep->getContext(); }
350  const long getDegree() const { return rep->getDegree(); }
351  void rotate(Ctxt& ctxt, long k) const { rep->rotate(ctxt, k); }
352  void shift(Ctxt& ctxt, long k) const { rep->shift(ctxt, k); }
353  void rotate1D(Ctxt& ctxt, long i, long k, bool dc=false) const { rep->rotate1D(ctxt, i, k, dc); }
354  void shift1D(Ctxt& ctxt, long i, long k) const { rep->shift1D(ctxt, i, k); }
355 
356 
357  void encode(ZZX& ptxt, const vector< long >& array) const
358  { rep->encode(ptxt, array); }
359  void encode(ZZX& ptxt, const vector< ZZX >& array) const
360  { rep->encode(ptxt, array); }
361  void encode(ZZX& ptxt, const PlaintextArray& array) const
362  { rep->encode(ptxt, array); }
363 
364  void encodeUnitSelector(ZZX& ptxt, long i) const
365  { rep->encodeUnitSelector(ptxt, i); }
366 
367  void decode(vector< long >& array, const ZZX& ptxt) const
368  { rep->decode(array, ptxt); }
369  void decode(vector< ZZX >& array, const ZZX& ptxt) const
370  { rep->decode(array, ptxt); }
371  void decode(PlaintextArray& array, const ZZX& ptxt) const
372  { rep->decode(array, ptxt); }
373 
374  void encrypt(Ctxt& ctxt, const FHEPubKey& pKey, const vector< long >& ptxt) const
375  { rep->encrypt(ctxt, pKey, ptxt); }
376  void encrypt(Ctxt& ctxt, const FHEPubKey& pKey, const vector< ZZX >& ptxt) const
377  { rep->encrypt(ctxt, pKey, ptxt); }
378  void encrypt(Ctxt& ctxt, const FHEPubKey& pKey, const PlaintextArray& ptxt) const
379  { rep->encrypt(ctxt, pKey, ptxt); }
380 
381 
382  void decrypt(const Ctxt& ctxt, const FHESecKey& sKey, vector< long >& ptxt) const
383  { rep->decrypt(ctxt, sKey, ptxt); }
384  void decrypt(const Ctxt& ctxt, const FHESecKey& sKey, vector< ZZX >& ptxt) const
385  { rep->decrypt(ctxt, sKey, ptxt); }
386  void decrypt(const Ctxt& ctxt, const FHESecKey& sKey, PlaintextArray& ptxt) const
387  { rep->decrypt(ctxt, sKey, ptxt); }
388 
389 
390  void select(Ctxt& ctxt1, const Ctxt& ctxt2, const vector< long >& selector) const
391  { rep->select(ctxt1, ctxt2, selector); }
392  void select(Ctxt& ctxt1, const Ctxt& ctxt2, const vector< ZZX >& selector) const
393  { rep->select(ctxt1, ctxt2, selector); }
394  void select(Ctxt& ctxt1, const Ctxt& ctxt2, const PlaintextArray& selector) const
395  { rep->select(ctxt1, ctxt2, selector); }
396 
397  void buildLinPolyCoeffs(vector<ZZX>& C, const vector<ZZX>& L) const
398  { rep->buildLinPolyCoeffs(C, L); }
399 
400  long size() const { return rep->size(); }
401  long dimension() const { return rep->dimension(); }
402  long sizeOfDimension(long i) const { return rep->sizeOfDimension(i); }
403  long nativeDimension(long i) const {return rep->nativeDimension(i); }
404  long coordinate(long i, long k) const { return rep->coordinate(i, k); }
406 };
407 
408 
409 
410 
431 class PlaintextArrayBase { // purely abstract interface
432 
433 public:
434  virtual ~PlaintextArrayBase() {}
435 
436  virtual PlaintextArrayBase* clone() const = 0;
437  // makes this usable with cloned_ptr
438 
440  virtual const EncryptedArray& getEA() const = 0;
441 
443  virtual void rotate(long k) = 0;
444 
446  virtual void shift(long k) = 0;
447 
449  virtual void encode(const vector< long >& array) = 0;
450  virtual void encode(const vector< ZZX >& array) = 0;
451  virtual void decode(vector< long >& array) const = 0;
452  virtual void decode(vector< ZZX >& array) const = 0;
453 
455  virtual void encode(long val) = 0;
456  virtual void encode(const ZZX& val) = 0;
457 
459  virtual void random() = 0;
460 
462  virtual bool equals(const PlaintextArrayBase& other) const = 0;
463  virtual bool equals(const vector<long>& other) const = 0;
464  virtual bool equals(const vector<ZZX>& other) const = 0;
465 
466  // arithmetic
467  virtual void add(const PlaintextArrayBase& other) = 0;
468  virtual void sub(const PlaintextArrayBase& other) = 0;
469  virtual void mul(const PlaintextArrayBase& other) = 0;
470  virtual void negate() = 0;
471 
473  virtual void replicate(long i) = 0;
474 
475  // output
476  virtual void print(ostream& s) const = 0;
477 };
478 
479 
484 template<class type> class PlaintextArrayDerived : public PlaintextArrayBase {
485 public:
486  PA_INJECT(type)
487 
488 private:
489  const EncryptedArray& ea;
490  vector< RX > data;
491 
492  /* the following are just for convenience */
493  const PAlgebraModDerived<type>& tab;
494  const RX& G;
495  long degG;
496  long n;
497 
498 public:
499 
500  virtual PlaintextArrayBase* clone() const { return new PlaintextArrayDerived(*this); }
501  virtual const EncryptedArray& getEA() const { return ea; }
502 
504  ea(_ea),
505  tab( ea.getContext().alMod.getDerived(type()) ),
506  G( ea.getDerived(type()).getG() )
507  {
508  RBak bak; bak.save(); tab.restoreContext();
509 
510  degG = deg(G);
511  n = ea.size();
512  data.resize(n);
513  }
514 
515  PlaintextArrayDerived(const PlaintextArrayDerived& other) // copy constructor
516  : ea(other.ea), tab(other.tab), G(other.G), degG(other.degG), n(other.n)
517  {
518  RBak bak; bak.save(); tab.restoreContext();
519  data = other.data;
520  }
521 
522 
523  PlaintextArrayDerived& operator=(const PlaintextArrayDerived& other) // assignment
524  {
525  if (this == &other) return *this;
526  assert(&ea == &other.ea);
527  RBak bak; bak.save(); tab.restoreContext();
528  data = other.data;
529  return *this;
530  }
531 
532  virtual void rotate(long k)
533  {
534  RBak bak; bak.save(); tab.restoreContext();
535 
536  vector<RX> tmp(n);
537 
538  for (long i = 0; i < n; i++)
539  tmp[((i+k)%n + n)%n] = data[i];
540 
541  data = tmp;
542  }
543 
544  virtual void shift(long k)
545  {
546  RBak bak; bak.save(); tab.restoreContext();
547 
548  for (long i = 0; i < n; i++)
549  if (i + k >= n || i + k < 0)
550  clear(data[i]);
551 
552  rotate(k);
553  }
554 
555  virtual void encode(const vector< long >& array)
556  {
557  assert(lsize(array) == n);
558  RBak bak; bak.save(); tab.restoreContext();
559  convert(data, array);
560  }
561 
562  virtual void encode(const vector< ZZX >& array)
563  {
564  assert(lsize(array) == n);
565  RBak bak; bak.save(); tab.restoreContext();
566  convert(data, array);
567  for (long i = 0; i < lsize(array); i++) assert(deg(data[i]) < degG);
568  }
569 
570  virtual void decode(vector< long >& array) const
571  {
572  RBak bak; bak.save(); tab.restoreContext();
573  convert(array, data);
574  }
575 
576  virtual void decode(vector< ZZX >& array) const
577  {
578  RBak bak; bak.save(); tab.restoreContext();
579  convert(array, data);
580  }
581 
582  virtual void encode(long val)
583  {
584  vector<long> array;
585  array.resize(n);
586  for (long i = 0; i < n; i++) array[i] = val;
587  encode(array);
588  }
589 
590  virtual void encode(const ZZX& val)
591  {
592  vector<ZZX> array;
593  array.resize(n);
594  for (long i = 0; i < n; i++) array[i] = val;
595  encode(array);
596  }
597 
598  virtual void random()
599  {
600  RBak bak; bak.save(); tab.restoreContext();
601  for (long i = 0; i < n; i++)
602  NTL::random(data[i], degG);
603  }
604 
605  virtual bool equals(const PlaintextArrayBase& other) const
606  {
607  RBak bak; bak.save(); tab.restoreContext();
608  const PlaintextArrayDerived<type>& other1 = dynamic_cast< const PlaintextArrayDerived<type>& >( other );
609 
610  assert(&ea == &other1.ea);
611 
612  return data == other1.data;
613  }
614 
615  virtual bool equals(const vector<long>& other) const
616  {
617  RBak bak; bak.save(); tab.restoreContext();
618  vector<RX> tmp;
619  convert(tmp, other);
620  return data == tmp;
621  }
622 
623  virtual bool equals(const vector<ZZX>& other) const
624  {
625  RBak bak; bak.save(); tab.restoreContext();
626  vector<RX> tmp;
627  convert(tmp, other);
628  return data == tmp;
629  }
630 
631  virtual void add(const PlaintextArrayBase& other)
632  {
633  RBak bak; bak.save(); tab.restoreContext();
634  const PlaintextArrayDerived<type>& other1 =
635  dynamic_cast< const PlaintextArrayDerived<type>& >( other );
636 
637  assert(&ea == &other1.ea);
638 
639  for (long i = 0; i < n; i++)
640  data[i] += other1.data[i];
641  }
642 
643  virtual void sub(const PlaintextArrayBase& other)
644  {
645  RBak bak; bak.save(); tab.restoreContext();
646  const PlaintextArrayDerived<type>& other1 =
647  dynamic_cast< const PlaintextArrayDerived<type>& >( other );
648 
649  assert(&ea == &other1.ea);
650 
651  for (long i = 0; i < n; i++)
652  data[i] -= other1.data[i];
653  }
654 
655 
656  virtual void mul(const PlaintextArrayBase& other)
657  {
658  RBak bak; bak.save(); tab.restoreContext();
659  const PlaintextArrayDerived<type>& other1 =
660  dynamic_cast< const PlaintextArrayDerived<type>& >( other );
661 
662  assert(&ea == &other1.ea);
663 
664  for (long i = 0; i < n; i++)
665  MulMod(data[i], data[i], other1.data[i], G);
666  }
667 
668 
669  virtual void negate()
670  {
671  RBak bak; bak.save(); tab.restoreContext();
672  for (long i = 0; i < n; i++)
673  NTL::negate(data[i], data[i]);
674  }
675 
676  virtual void replicate(long i)
677  {
678  RBak bak; bak.save(); tab.restoreContext();
679 
680  assert(i >= 0 && i < n);
681  for (long j = 0; j < n; j++) {
682  if (j != i) data[j] = data[i];
683  }
684  }
685 
686  virtual void print(ostream& s) const
687  {
688  if (n == 0)
689  s << "[]";
690  else {
691  s << "[" << data[0];
692  for (long i = 1; i < lsize(data); i++)
693  s << " " << data[i];
694  s << "]";
695  }
696  }
697 
698 
699 
700  /* The follwing two methods assume that the modulus context is already set */
701 
702  const vector<RX>& getData() const { return data; }
703 
704  void setData(const vector<RX>& _data)
705  {
706  assert(lsize(_data) == n);
707  data = _data;
708  }
709 
710 
711 };
712 
713 
715 PlaintextArrayBase* buildPlaintextArray(const EncryptedArray& ea);
716 
717 
722 private:
723  cloned_ptr<PlaintextArrayBase> rep;
724 
725 public:
726 
727  PlaintextArray(const EncryptedArray& ea)
728  : rep(buildPlaintextArray(ea))
729  { }
730  // constructor
731 
732  // copy constructor: default
733  // assignment: default
734 
735 
736  template<class type>
737  const PlaintextArrayDerived<type>& getDerived(type) const
738  { return dynamic_cast< const PlaintextArrayDerived<type>& >( *rep ); }
739 
740  template<class type>
741  PlaintextArrayDerived<type>& getDerived(type)
742  { return dynamic_cast< PlaintextArrayDerived<type>& >( *rep ); }
743 
744  // downcast operators (differeing only by const)
745  // example: const PlaintextArrayDerived<PA_GF2>& rep = pa.getDerived(PA_GF2());
746 
747 
748  /* direct access to PlaintextArrayBase methods */
749 
751  const EncryptedArray& getEA() const { return rep->getEA(); }
752 
754  void rotate(long k) { rep->rotate(k); }
755 
757  void shift(long k) { rep->shift(k); }
758 
760  void encode(const vector< long >& array) { rep->encode(array); }
761  void encode(const vector< ZZX >& array) { rep->encode(array); }
762  void decode(vector< long >& array) { rep->decode(array); }
763  void decode(vector< ZZX >& array) { rep->decode(array); }
764 
766  void encode(long val) { rep->encode(val); }
767  void encode(const ZZX& val) { rep->encode(val); }
768 
770  void random() { rep->random(); }
771 
773  bool equals(const PlaintextArray& other) const { return rep->equals(*other.rep); }
774  bool equals(const vector<long>& other) const { return rep->equals(other); }
775  bool equals(const vector<ZZX>& other) const { return rep->equals(other); }
776 
777  void add(const PlaintextArray& other) { rep->add(*other.rep); }
778  void sub(const PlaintextArray& other) { rep->sub(*other.rep); }
779  void mul(const PlaintextArray& other) { rep->mul(*other.rep); }
780  void negate() { rep->negate(); }
781 
783  void replicate(long i) { rep->replicate(i); }
784 
785  void print(ostream& s) const { rep->print(s); }
786 };
787 
788 #endif /* ifdef _EncryptedArray_H_ */