HElib 1.0 Implementing Homomorphic Encryption

- Main Page
- Classes
- Files

- File List
- File Members

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
325 class EncryptedArray {
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>
342 const EncryptedArrayDerived<type>& getDerived(type) const
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
503 PlaintextArrayDerived(const EncryptedArray& _ea) :
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
721 class PlaintextArray {
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_ */