Clearmatics Libsnark  0.1
C++ library for zkSNARK proofs
gadget.cpp
Go to the documentation of this file.
1 
13 #include <cmath>
15 #include <memory>
16 
17 using ::std::cerr;
18 using ::std::cout;
19 using ::std::endl;
20 using ::std::shared_ptr;
21 using ::std::string;
22 using ::std::vector;
23 
24 namespace gadgetlib2
25 {
26 
27 /*************************************************************************************************/
28 /*************************************************************************************************/
29 /******************* ******************/
30 /******************* Gadget Interfaces ******************/
31 /******************* ******************/
32 /*************************************************************************************************/
33 /*************************************************************************************************/
34 
35 /***********************************/
36 /*** Gadget ***/
37 /***********************************/
38 
40 {
42  pb != NULL,
43  "Attempted to create gadget with uninitialized Protoboard.");
44 }
45 
47 {
49  "Attempted to generate witness for an incomplete Gadget type.");
50 }
51 
53  const LinearCombination &a, const ::std::string &name)
54 {
55  pb_->addUnaryConstraint(a, name);
56 }
57 
59  const LinearCombination &a,
60  const LinearCombination &b,
61  const LinearCombination &c,
62  const ::std::string &name)
63 {
64  pb_->addRank1Constraint(a, b, c, name);
65 }
66 
67 /***********************************/
68 /*** R1P_Gadget ***/
69 /***********************************/
71 
73  const LinearCombination &a,
74  const LinearCombination &b,
75  const LinearCombination &c,
76  const string &name)
77 {
78  pb_->addRank1Constraint(a, b, c, name);
79 }
80 
81 /***********************************/
82 /*** End of Gadget Interfaces ***/
83 /***********************************/
84 
85 /*************************************************************************************************/
86 /*************************************************************************************************/
87 /******************* ******************/
88 /******************* AND Gadgets ******************/
89 /******************* ******************/
90 /*************************************************************************************************/
91 /*************************************************************************************************/
92 AND_GadgetBase::~AND_GadgetBase(){};
93 
94 /*
95  Constraint breakdown:
96  (1) input1 * input2 = result
97 */
98 BinaryAND_Gadget::BinaryAND_Gadget(
99  ProtoboardPtr pb,
100  const LinearCombination &input1,
101  const LinearCombination &input2,
102  const Variable &result)
103  : Gadget(pb)
104  , AND_GadgetBase(pb)
105  , input1_(input1)
106  , input2_(input2)
107  , result_(result)
108 {
109 }
110 
111 void BinaryAND_Gadget::init() {}
112 
113 void BinaryAND_Gadget::generateConstraints()
114 {
115  addRank1Constraint(
116  input1_, input2_, result_, "result = AND(input1, input2)");
117 }
118 
119 void BinaryAND_Gadget::generateWitness()
120 {
121  if (val(input1_) == 1 && val(input2_) == 1) {
122  val(result_) = 1;
123  } else {
124  val(result_) = 0;
125  }
126 }
127 
128 /*
129  Constraint breakdown:
130 
131  (*) sum = sum(input[i]) - n
132  (1) sum * result = 0
133  (2) sum * sumInverse = 1 - result
134 
135  [ AND(inputs) == 1 ] (*)==> [sum == 0] (2)==> [result == 1]
136  [ AND(inputs) == 0 ] (*)==> [sum != 0] (1)==> [result == 0]
137 */
138 
139 R1P_AND_Gadget::R1P_AND_Gadget(
140  ProtoboardPtr pb, const VariableArray &input, const Variable &result)
141  : Gadget(pb)
142  , AND_GadgetBase(pb)
143  , R1P_Gadget(pb)
144  , input_(input)
145  , result_(result)
146  , sumInverse_("sumInverse")
147 {
149  input.size() > 0,
150  "Attempted to create an R1P_AND_Gadget with 0 inputs.");
152  input.size() <= Fp(-1).as_ulong(),
153  "Attempted to create R1P_AND_Gadget with too "
154  "many inputs. Will cause overflow!");
155 }
156 
157 void R1P_AND_Gadget::init()
158 {
159  const int numInputs = input_.size();
160  sum_ = sum(input_) - numInputs;
161 }
162 
164 {
166  sum_, result_, 0, "sum * result = 0 | sum == sum(input[i]) - n");
168  sumInverse_,
169  sum_,
170  1 - result_,
171  "sumInverse * sum = 1-result | sum == sum(input[i]) - n");
172 }
173 
175 {
176  FElem sum = 0;
177  for (size_t i = 0; i < input_.size(); ++i) {
178  sum += val(input_[i]);
179  }
180  sum -= input_.size(); // sum(input[i]) - n ==> sum
181  if (sum == 0) { // AND(input[0], input[1], ...) == 1
182  val(sumInverse_) = 0;
183  val(result_) = 1;
184  } else { // AND(input[0], input[1], ...) == 0
185  val(sumInverse_) = sum.inverse(R1P);
186  val(result_) = 0;
187  }
188 }
189 
191  ProtoboardPtr pb, const VariableArray &input, const Variable &result)
192 {
193  GadgetPtr pGadget;
194  if (pb->fieldType_ == R1P) {
195  pGadget.reset(new R1P_AND_Gadget(pb, input, result));
196  } else {
198  "Attempted to create gadget of undefined Protoboard type.");
199  }
200  pGadget->init();
201  return pGadget;
202 }
203 
205  ProtoboardPtr pb,
206  const LinearCombination &input1,
207  const LinearCombination &input2,
208  const Variable &result)
209 {
210  GadgetPtr pGadget(new BinaryAND_Gadget(pb, input1, input2, result));
211  pGadget->init();
212  return pGadget;
213 }
214 
215 /***********************************/
216 /*** End of AND Gadgets ***/
217 /***********************************/
218 
219 /*************************************************************************************************/
220 /*************************************************************************************************/
221 /******************* ******************/
222 /******************* OR Gadgets ******************/
223 /******************* ******************/
224 /*************************************************************************************************/
225 /*************************************************************************************************/
226 OR_GadgetBase::~OR_GadgetBase(){};
227 
228 /*
229  Constraint breakdown:
230  (1) result = input1 + input2 - input1 * input2
231  input1 * input2 = input1 + input2 - result
232 */
233 BinaryOR_Gadget::BinaryOR_Gadget(
234  ProtoboardPtr pb,
235  const LinearCombination &input1,
236  const LinearCombination &input2,
237  const Variable &result)
238  : Gadget(pb)
239  , OR_GadgetBase(pb)
240  , input1_(input1)
241  , input2_(input2)
242  , result_(result)
243 {
244 }
245 
246 void BinaryOR_Gadget::init() {}
247 
248 void BinaryOR_Gadget::generateConstraints()
249 {
250  addRank1Constraint(
251  input1_,
252  input2_,
253  input1_ + input2_ - result_,
254  "result = OR(input1, input2)");
255 }
256 
257 void BinaryOR_Gadget::generateWitness()
258 {
259  if (val(input1_) == 1 || val(input2_) == 1) {
260  val(result_) = 1;
261  } else {
262  val(result_) = 0;
263  }
264 }
265 
266 /*
267  Constraint breakdown:
268 
269  (*) sum = sum(input[i])
270  (1) sum * (1 - result) = 0
271  (2) sum * sumInverse = result
272 
273  [ OR(inputs) == 1 ] (*)==> [sum != 0] (1)==> [result == 1]
274  [ OR(inputs) == 0 ] (*)==> [sum == 0] (2)==> [result == 0]
275 */
276 
277 R1P_OR_Gadget::R1P_OR_Gadget(
278  ProtoboardPtr pb, const VariableArray &input, const Variable &result)
279  : Gadget(pb)
280  , OR_GadgetBase(pb)
281  , R1P_Gadget(pb)
282  , sumInverse_("sumInverse")
283  , input_(input)
284  , result_(result)
285 {
287  input.size() > 0,
288  "Attempted to create an R1P_OR_Gadget with 0 inputs.");
290  input.size() <= Fp(-1).as_ulong(),
291  "Attempted to create R1P_OR_Gadget with too "
292  "many inputs. Will cause overflow!");
293 }
294 
295 void R1P_OR_Gadget::init() { sum_ = sum(input_); }
296 
298 {
300  sum_, 1 - result_, 0, "sum * (1 - result) = 0 | sum == sum(input[i])");
302  sumInverse_,
303  sum_,
304  result_,
305  "sum * sumInverse = result | sum == sum(input[i])");
306 }
307 
309 {
310  FElem sum = 0;
311  for (size_t i = 0; i < input_.size(); ++i) { // sum(input[i]) ==> sum
312  sum += val(input_[i]);
313  }
314  if (sum == 0) { // OR(input[0], input[1], ...) == 0
315  val(sumInverse_) = 0;
316  val(result_) = 0;
317  } else { // OR(input[0], input[1], ...) == 1
318  val(sumInverse_) = sum.inverse(R1P);
319  val(result_) = 1;
320  }
321 }
322 
324  ProtoboardPtr pb, const VariableArray &input, const Variable &result)
325 {
326  GadgetPtr pGadget;
327  if (pb->fieldType_ == R1P) {
328  pGadget.reset(new R1P_OR_Gadget(pb, input, result));
329  } else {
331  "Attempted to create gadget of undefined Protoboard type.");
332  }
333  pGadget->init();
334  return pGadget;
335 }
336 
338  ProtoboardPtr pb,
339  const LinearCombination &input1,
340  const LinearCombination &input2,
341  const Variable &result)
342 {
343  GadgetPtr pGadget(new BinaryOR_Gadget(pb, input1, input2, result));
344  pGadget->init();
345  return pGadget;
346 }
347 
348 /***********************************/
349 /*** End of OR Gadgets ***/
350 /***********************************/
351 
352 /*************************************************************************************************/
353 /*************************************************************************************************/
354 /******************* ******************/
355 /******************* InnerProduct Gadgets ******************/
356 /******************* ******************/
357 /*************************************************************************************************/
358 /*************************************************************************************************/
359 InnerProduct_GadgetBase::~InnerProduct_GadgetBase(){};
360 
361 /*
362  Constraint breakdown:
363 
364  (1) partialSums[0] = A[0] * B[0]
365  (2) partialSums[i] = partialSums[i-1] + A[0] * B[0] ==> i = 1..n-2
366  partialSums[i] - partialSums[i-1] = A[i] * B[i]
367  (3) result = partialSums[n-1] = partialSums[n-2] + A[n-1] * B[n-1] ==>
368  result - partialSums[n-2] = A[n-1] * B[n-1]
369 
370 */
371 
372 R1P_InnerProduct_Gadget::R1P_InnerProduct_Gadget(
373  ProtoboardPtr pb,
374  const VariableArray &A,
375  const VariableArray &B,
376  const Variable &result)
377  : Gadget(pb)
378  , InnerProduct_GadgetBase(pb)
379  , R1P_Gadget(pb)
380  , partialSums_(A.size(), "partialSums")
381  , A_(A)
382  , B_(B)
383  , result_(result)
384 {
386  A.size() > 0,
387  "Attempted to create an R1P_InnerProduct_Gadget with 0 inputs.");
389  A.size() == B.size(),
391  "Inner product vector sizes not equal. Sizes are: "
392  "(A) - %u, (B) - %u",
393  A.size(),
394  B.size()));
395 }
396 
397 void R1P_InnerProduct_Gadget::init() {}
398 
400 {
401  const int n = A_.size();
402  if (n == 1) {
403  addRank1Constraint(A_[0], B_[0], result_, "A[0] * B[0] = result");
404  return;
405  }
406  // else (n > 1)
408  A_[0], B_[0], partialSums_[0], "A[0] * B[0] = partialSums[0]");
409  for (int i = 1; i <= n - 2; ++i) {
411  A_[i],
412  B_[i],
413  partialSums_[i] - partialSums_[i - 1],
415  "A[%u] * B[%u] = partialSums[%u] - partialSums[%u]",
416  i,
417  i,
418  i,
419  i - 1));
420  }
422  A_[n - 1],
423  B_[n - 1],
424  result_ - partialSums_[n - 2],
425  "A[n-1] * B[n-1] = result - partialSums[n-2]");
426 }
427 
429 {
430  const int n = A_.size();
431  if (n == 1) {
432  val(result_) = val(A_[0]) * val(B_[0]);
433  return;
434  }
435  // else (n > 1)
436  val(partialSums_[0]) = val(A_[0]) * val(B_[0]);
437  for (int i = 1; i <= n - 2; ++i) {
438  val(partialSums_[i]) =
439  val(partialSums_[i - 1]) + val(A_[i]) * val(B_[i]);
440  }
441  val(result_) = val(partialSums_[n - 2]) + val(A_[n - 1]) * val(B_[n - 1]);
442 }
443 
444 /***********************************/
445 /*** End of InnerProduct Gadgets ***/
446 /***********************************/
447 
448 /*************************************************************************************************/
449 /*************************************************************************************************/
450 /******************* ******************/
451 /******************* LooseMUX Gadgets ******************/
452 /******************* ******************/
453 /*************************************************************************************************/
454 /*************************************************************************************************/
456 
457 /*
458  Constraint breakdown:
459  (1) indicators[i] * (index - i) = 0 | i = 0..n-1 ==> only indicators[index]
460  will be non-zero (2) sum(indicators[i]) = successFlag ==> successFlag =
461  indicators[index] (3) successFlag is boolean (4) result[j] = <indicators> *
462  <inputs[index][j]> | j = 1..output.size() ==> result[j] =
463  inputs[index][j]
464 
465 */
466 
467 R1P_LooseMUX_Gadget::R1P_LooseMUX_Gadget(
468  ProtoboardPtr pb,
469  const MultiPackedWordArray &inputs,
470  const Variable &index,
471  const VariableArray &output,
472  const Variable &successFlag)
473  : Gadget(pb)
474  , LooseMUX_GadgetBase(pb)
475  , R1P_Gadget(pb)
476  , indicators_(inputs.size(), "indicators")
477  , inputs_(inputs.size())
478  , index_(index)
479  , output_(output)
480  , successFlag_(successFlag)
481 {
483  inputs.size() <= Fp(-1).as_ulong(),
484  "Attempted to create R1P_LooseMUX_Gadget "
485  "with too many inputs. May cause overflow!");
486  // for(const VariableArray& inpArr : inputs) {
487  for (size_t i = 0; i < inputs.size(); ++i) {
489  inputs[i].size() == output.size(),
490  "Input VariableArray is of incorrect size.");
491  }
492  ::std::copy(
493  inputs.begin(),
494  inputs.end(),
495  inputs_.begin()); // change type to R1P_VariableArray
496 }
497 
498 void R1P_LooseMUX_Gadget::init()
499 {
500  // create inputs for the inner products and initialize them. Each iteration
501  // creates a VariableArray for the i'th elements from each of the vector's
502  // VariableArrays.
503  for (size_t i = 0; i < output_.size(); ++i) {
504  VariableArray curInput;
505  for (size_t j = 0; j < inputs_.size(); ++j) {
506  curInput.push_back(inputs_[j][i]);
507  }
508  computeResult_.push_back(InnerProduct_Gadget::create(
509  pb_, indicators_, curInput, output_[i]));
510  }
511 }
512 
514 {
515  const size_t n = inputs_.size();
516  for (size_t i = 0; i < n; ++i) {
518  indicators_[i],
519  (index_ - i),
520  0,
521  GADGETLIB2_FMT("indicators[%u] * (index - %u) = 0", i, i));
522  }
524  sum(indicators_), 1, successFlag_, "sum(indicators) * 1 = successFlag");
526  for (auto &curGadget : computeResult_) {
527  curGadget->generateConstraints();
528  }
529 }
530 
532 {
533  const size_t n = inputs_.size();
534  /* assumes that idx can be fit in ulong; true for our purposes for now */
535  const size_t index = val(index_).asLong();
536  const FElem arraySize = n;
537  for (size_t i = 0; i < n; ++i) {
538  val(indicators_[i]) = 0; // Redundant, but just in case.
539  }
540  if (index >= n) { // || index < 0
541  val(successFlag_) = 0;
542  } else { // index in bounds
543  val(indicators_[index]) = 1;
544  val(successFlag_) = 1;
545  }
546  for (auto &curGadget : computeResult_) {
547  curGadget->generateWitness();
548  }
549 }
550 
552 {
553  return indicators_;
554 }
555 
557  ProtoboardPtr pb,
558  const MultiPackedWordArray &inputs,
559  const Variable &index,
560  const VariableArray &output,
561  const Variable &successFlag)
562 {
563  GadgetPtr pGadget;
564  if (pb->fieldType_ == R1P) {
565  pGadget.reset(
566  new R1P_LooseMUX_Gadget(pb, inputs, index, output, successFlag));
567  } else {
569  "Attempted to create gadget of undefined Protoboard type.");
570  }
571  pGadget->init();
572  return pGadget;
573 }
574 
580  ProtoboardPtr pb,
581  const VariableArray &inputs,
582  const Variable &index,
583  const Variable &output,
584  const Variable &successFlag)
585 {
586  MultiPackedWordArray inpVec;
587  for (size_t i = 0; i < inputs.size(); ++i) {
588  MultiPackedWord cur(pb->fieldType_);
589  cur.push_back(inputs[i]);
590  inpVec.push_back(cur);
591  }
592  VariableArray outVec;
593  outVec.push_back(output);
594  auto result =
595  LooseMUX_Gadget::create(pb, inpVec, index, outVec, successFlag);
596  return result;
597 }
598 
599 /***********************************/
600 /*** End of LooseMUX Gadgets ***/
601 /***********************************/
602 
603 /*************************************************************************************************/
604 /*************************************************************************************************/
605 /******************* ******************/
606 /******************* CompressionPacking Gadgets
607  * ******************/
608 /******************* ******************/
609 /*************************************************************************************************/
610 /*************************************************************************************************/
611 
612 /*
613  Compression Packing gadgets have two modes, which differ in the way the
614  witness and constraints are created. In PACK mode gerateWitness() will take
615  the bits and create a packed element (or number of elements) while
616  generateConstraints() will not enforce that bits are indeed Boolean. In
617  UNPACK mode generateWitness() will take the packed representation and unpack
618  it to bits while generateConstraints will in addition enforce that unpacked
619  bits are indeed Boolean.
620 */
621 
622 CompressionPacking_GadgetBase::~CompressionPacking_GadgetBase(){};
623 
624 /*
625  Constraint breakdown:
626 
627  (1) packed = sum(unpacked[i] * 2^i)
628  (2) (UNPACK only) unpacked[i] is Boolean.
629 */
630 
631 R1P_CompressionPacking_Gadget::R1P_CompressionPacking_Gadget(
632  ProtoboardPtr pb,
633  const VariableArray &unpacked,
634  const VariableArray &packed,
635  PackingMode packingMode)
636  : Gadget(pb)
637  , CompressionPacking_GadgetBase(pb)
638  , R1P_Gadget(pb)
639  , packingMode_(packingMode)
640  , unpacked_(unpacked)
641  , packed_(packed)
642 {
643  const int n = unpacked.size();
644  GADGETLIB_ASSERT(n > 0, "Attempted to pack 0 bits in R1P.")
646  packed.size() == 1,
647  "Attempted to pack into more than 1 Variable in "
648  "R1P_CompressionPacking_Gadget.")
649  // TODO add assertion that 'n' bits can fit in the field characteristic
650 }
651 
652 void R1P_CompressionPacking_Gadget::init() {}
653 
655 {
656  const int n = unpacked_.size();
657  LinearCombination packed;
658  FElem two_i(R1P_Elem(1)); // Will hold 2^i
659  for (int i = 0; i < n; ++i) {
660  packed += unpacked_[i] * two_i;
661  two_i += two_i;
662  if (packingMode_ == PackingMode::UNPACK) {
663  enforceBooleanity(unpacked_[i]);
664  }
665  }
666  addRank1Constraint(
667  packed_[0], 1, packed, "packed[0] = sum(2^i * unpacked[i])");
668 }
669 
671 {
672  const int n = unpacked_.size();
673  if (packingMode_ == PackingMode::PACK) {
674  FElem packedVal = 0;
675  FElem two_i(R1P_Elem(1)); // will hold 2^i
676  for (int i = 0; i < n; ++i) {
678  val(unpacked_[i]).asLong() == 0 ||
679  val(unpacked_[i]).asLong() == 1,
681  "unpacked[%u] = %u. Expected a Boolean value.",
682  i,
683  val(unpacked_[i]).asLong()));
684  packedVal += two_i * val(unpacked_[i]).asLong();
685  two_i += two_i;
686  }
687  val(packed_[0]) = packedVal;
688  return;
689  }
690  // else (UNPACK)
692  packingMode_ == PackingMode::UNPACK,
693  "Packing gadget created with unknown packing mode.");
694  for (int i = 0; i < n; ++i) {
695  val(unpacked_[i]) = val(packed_[0]).getBit(i, R1P);
696  }
697 }
698 
699 /*****************************************/
700 /*** End of CompressionPacking Gadgets ***/
701 /*****************************************/
702 
703 /*************************************************************************************************/
704 /*************************************************************************************************/
705 /******************* ******************/
706 /******************* IntegerPacking Gadgets ******************/
707 /******************* ******************/
708 /*************************************************************************************************/
709 /*************************************************************************************************/
710 
711 /*
712  Arithmetic Packing gadgets have two modes, which differ in the way the
713  witness and constraints are created. In PACK mode gerateWitness() will take
714  the bits and create a packed element (or number of elements) while
715  generateConstraints() will not enforce that bits are indeed Boolean. In
716  UNPACK mode generateWitness() will take the packed representation and unpack
717  it to bits while generateConstraints will in addition enforce that unpacked
718  bits are indeed Boolean.
719 */
720 
721 IntegerPacking_GadgetBase::~IntegerPacking_GadgetBase(){};
722 
723 /*
724  Constraint breakdown:
725 
726  (1) packed = sum(unpacked[i] * 2^i)
727  (2) (UNPACK only) unpacked[i] is Boolean.
728 */
729 
730 R1P_IntegerPacking_Gadget::R1P_IntegerPacking_Gadget(
731  ProtoboardPtr pb,
732  const VariableArray &unpacked,
733  const VariableArray &packed,
734  PackingMode packingMode)
735  : Gadget(pb)
736  , IntegerPacking_GadgetBase(pb)
737  , R1P_Gadget(pb)
738  , packingMode_(packingMode)
739  , unpacked_(unpacked)
740  , packed_(packed)
741 {
742  const int n = unpacked.size();
743  GADGETLIB_ASSERT(n > 0, "Attempted to pack 0 bits in R1P.")
745  packed.size() == 1,
746  "Attempted to pack into more than 1 Variable in "
747  "R1P_IntegerPacking_Gadget.")
748 }
749 
750 void R1P_IntegerPacking_Gadget::init()
751 {
752  compressionPackingGadget_ = CompressionPacking_Gadget::create(
753  pb_, unpacked_, packed_, packingMode_);
754 }
755 
757 {
758  compressionPackingGadget_->generateConstraints();
759 }
760 
762 {
763  compressionPackingGadget_->generateWitness();
764 }
765 
766 /*****************************************/
767 /*** End of IntegerPacking Gadgets ***/
768 /*****************************************/
769 
770 /*************************************************************************************************/
771 /*************************************************************************************************/
772 /******************* ******************/
773 /******************* EqualsConst Gadgets ******************/
774 /******************* ******************/
775 /*************************************************************************************************/
776 /*************************************************************************************************/
777 EqualsConst_GadgetBase::~EqualsConst_GadgetBase(){};
778 
779 /*
780  Constraint breakdown:
781 
782  (1) (input - n) * result = 0
783  (2) (input - n) * aux = 1 - result
784 
785  [ input == n ] (2)==> [result == 1] (aux can ake any value)
786  [ input != n ] (1)==> [result == 0] (aux == inverse(input - n))
787 */
788 
789 R1P_EqualsConst_Gadget::R1P_EqualsConst_Gadget(
790  ProtoboardPtr pb,
791  const FElem &n,
792  const LinearCombination &input,
793  const Variable &result)
794  : Gadget(pb)
795  , EqualsConst_GadgetBase(pb)
796  , R1P_Gadget(pb)
797  , n_(n)
798  , aux_("aux (R1P_EqualsConst_Gadget)")
799  , input_(input)
800  , result_(result)
801 {
802 }
803 
804 void R1P_EqualsConst_Gadget::init() {}
805 
807 {
808  addRank1Constraint(input_ - n_, result_, 0, "(input - n) * result = 0");
810  input_ - n_, aux_, 1 - result_, "(input - n) * aux = 1 - result");
811 }
812 
814 {
815  val(aux_) = val(input_) == n_ ? 0 : (val(input_) - n_).inverse(R1P);
816  val(result_) = val(input_) == n_ ? 1 : 0;
817 }
818 
819 /***********************************/
820 /*** End of EqualsConst Gadgets ***/
821 /***********************************/
822 
823 /*************************************************************************************************/
824 /*************************************************************************************************/
825 /******************* ******************/
826 /******************* DualWord_Gadget ******************/
827 /******************* ******************/
828 /*************************************************************************************************/
829 /*************************************************************************************************/
830 DualWord_Gadget::DualWord_Gadget(
831  ProtoboardPtr pb, const DualWord &var, PackingMode packingMode)
832  : Gadget(pb), var_(var), packingMode_(packingMode), packingGadget_()
833 {
834 }
835 
836 void DualWord_Gadget::init()
837 {
838  packingGadget_ = CompressionPacking_Gadget::create(
839  pb_, var_.unpacked(), var_.multipacked(), packingMode_);
840 }
841 
843  ProtoboardPtr pb, const DualWord &var, PackingMode packingMode)
844 {
845  GadgetPtr pGadget(new DualWord_Gadget(pb, var, packingMode));
846  pGadget->init();
847  return pGadget;
848 }
849 
851 {
852  packingGadget_->generateConstraints();
853 }
854 
855 void DualWord_Gadget::generateWitness() { packingGadget_->generateWitness(); }
856 
857 /*********************************/
858 /*** END OF Gadget ***/
859 /*********************************/
860 
861 /*************************************************************************************************/
862 /*************************************************************************************************/
863 /******************* ******************/
864 /******************* DualWordArray_Gadget ******************/
865 /******************* ******************/
866 /*************************************************************************************************/
867 /*************************************************************************************************/
868 DualWordArray_Gadget::DualWordArray_Gadget(
869  ProtoboardPtr pb, const DualWordArray &vars, PackingMode packingMode)
870  : Gadget(pb), vars_(vars), packingMode_(packingMode), packingGadgets_()
871 {
872 }
873 
874 void DualWordArray_Gadget::init()
875 {
876  const UnpackedWordArray unpacked = vars_.unpacked();
877  const MultiPackedWordArray packed = vars_.multipacked();
878  for (size_t i = 0; i < vars_.size(); ++i) {
879  const auto curGadget = CompressionPacking_Gadget::create(
880  pb_, unpacked[i], packed[i], packingMode_);
881  packingGadgets_.push_back(curGadget);
882  }
883 }
884 
886  ProtoboardPtr pb, const DualWordArray &vars, PackingMode packingMode)
887 {
888  GadgetPtr pGadget(new DualWordArray_Gadget(pb, vars, packingMode));
889  pGadget->init();
890  return pGadget;
891 }
892 
894 {
895  for (auto &gadget : packingGadgets_) {
896  gadget->generateConstraints();
897  }
898 }
899 
901 {
902  for (auto &gadget : packingGadgets_) {
903  gadget->generateWitness();
904  }
905 }
906 
907 /*********************************/
908 /*** END OF Gadget ***/
909 /*********************************/
910 
911 /*************************************************************************************************/
912 /*************************************************************************************************/
913 /******************* ******************/
914 /******************* Toggle_Gadget ******************/
915 /******************* ******************/
916 /*************************************************************************************************/
917 /*************************************************************************************************/
918 
919 /*
920  Constraint breakdown:
921 
922  (1) result = (1 - toggle) * zeroValue + toggle * oneValue
923  (rank 1 format) ==> toggle * (oneValue - zeroValue) = result - zeroValue
924 
925 */
926 
927 Toggle_Gadget::Toggle_Gadget(
928  ProtoboardPtr pb,
929  const FlagVariable &toggle,
930  const LinearCombination &zeroValue,
931  const LinearCombination &oneValue,
932  const Variable &result)
933  : Gadget(pb)
934  , toggle_(toggle)
935  , zeroValue_(zeroValue)
936  , oneValue_(oneValue)
937  , result_(result)
938 {
939 }
940 
942  ProtoboardPtr pb,
943  const FlagVariable &toggle,
944  const LinearCombination &zeroValue,
945  const LinearCombination &oneValue,
946  const Variable &result)
947 {
948  GadgetPtr pGadget(
949  new Toggle_Gadget(pb, toggle, zeroValue, oneValue, result));
950  pGadget->init();
951  return pGadget;
952 }
953 
955 {
956  pb_->addRank1Constraint(
957  toggle_,
958  oneValue_ - zeroValue_,
959  result_ - zeroValue_,
960  "result = (1 - toggle) * zeroValue + toggle * oneValue");
961 }
962 
964 {
965  if (val(toggle_) == 0) {
966  val(result_) = val(zeroValue_);
967  } else if (val(toggle_) == 1) {
968  val(result_) = val(oneValue_);
969  } else {
970  GADGETLIB_FATAL("Toggle value must be Boolean.");
971  }
972 }
973 
974 /*********************************/
975 /*** END OF Gadget ***/
976 /*********************************/
977 
978 /*************************************************************************************************/
979 /*************************************************************************************************/
980 /******************* ******************/
981 /******************* ConditionalFlag_Gadget
982  * ******************/
983 /******************* ******************/
984 /*************************************************************************************************/
985 /*************************************************************************************************/
986 
987 /*
988  semantics: condition != 0 --> flag = 1
989  condition == 0 --> flag = 0
990 
991  Constraint breakdown:
992  (1) condition * not(flag) = 0
993  (2) condition * auxConditionInverse = flag
994 
995  */
996 
997 ConditionalFlag_Gadget::ConditionalFlag_Gadget(
998  ProtoboardPtr pb,
999  const LinearCombination &condition,
1000  const FlagVariable &flag)
1001  : Gadget(pb)
1002  , flag_(flag)
1003  , condition_(condition)
1004  , auxConditionInverse_("ConditionalFlag_Gadget::auxConditionInverse_")
1005 {
1006 }
1007 
1009  ProtoboardPtr pb,
1010  const LinearCombination &condition,
1011  const FlagVariable &flag)
1012 {
1013  GadgetPtr pGadget(new ConditionalFlag_Gadget(pb, condition, flag));
1014  pGadget->init();
1015  return pGadget;
1016 }
1017 
1019 {
1020  pb_->addRank1Constraint(
1021  condition_, negate(flag_), 0, "condition * not(flag) = 0");
1022  pb_->addRank1Constraint(
1023  condition_,
1024  auxConditionInverse_,
1025  flag_,
1026  "condition * auxConditionInverse = flag");
1027 }
1028 
1030 {
1031  if (val(condition_) == 0) {
1032  val(flag_) = 0;
1033  val(auxConditionInverse_) = 0;
1034  } else {
1035  val(flag_) = 1;
1036  val(auxConditionInverse_) = val(condition_).inverse(fieldType());
1037  }
1038 }
1039 
1040 /*********************************/
1041 /*** END OF Gadget ***/
1042 /*********************************/
1043 
1044 /*************************************************************************************************/
1045 /*************************************************************************************************/
1046 /******************* ******************/
1047 /******************* LogicImplication_Gadget
1048  * ******************/
1049 /******************* ******************/
1050 /*************************************************************************************************/
1051 /*************************************************************************************************/
1052 
1053 /*
1054  semantics: condition == 1 --> flag = 1
1055 
1056  Constraint breakdown:
1057  (1) condition * (1 - flag) = 0
1058 
1059  */
1060 
1061 LogicImplication_Gadget::LogicImplication_Gadget(
1062  ProtoboardPtr pb,
1063  const LinearCombination &condition,
1064  const FlagVariable &flag)
1065  : Gadget(pb), flag_(flag), condition_(condition)
1066 {
1067 }
1068 
1070  ProtoboardPtr pb,
1071  const LinearCombination &condition,
1072  const FlagVariable &flag)
1073 {
1074  GadgetPtr pGadget(new LogicImplication_Gadget(pb, condition, flag));
1075  pGadget->init();
1076  return pGadget;
1077 }
1078 
1080 {
1081  pb_->addRank1Constraint(
1082  condition_, negate(flag_), 0, "condition * not(flag) = 0");
1083 }
1084 
1086 {
1087  if (val(condition_) == 1) {
1088  val(flag_) = 1;
1089  }
1090 }
1091 
1092 /*********************************/
1093 /*** END OF Gadget ***/
1094 /*********************************/
1095 
1096 /*************************************************************************************************/
1097 /*************************************************************************************************/
1098 /******************* ******************/
1099 /******************* Compare_Gadget ******************/
1100 /******************* ******************/
1101 /*************************************************************************************************/
1102 /*************************************************************************************************/
1103 
1104 Comparison_GadgetBase::~Comparison_GadgetBase() {}
1105 
1106 R1P_Comparison_Gadget::R1P_Comparison_Gadget(
1107  ProtoboardPtr pb,
1108  const size_t &wordBitSize,
1109  const PackedWord &lhs,
1110  const PackedWord &rhs,
1111  const FlagVariable &less,
1112  const FlagVariable &lessOrEqual)
1113  : Gadget(pb)
1114  , Comparison_GadgetBase(pb)
1115  , R1P_Gadget(pb)
1116  , wordBitSize_(wordBitSize)
1117  , lhs_(lhs)
1118  , rhs_(rhs)
1119  , less_(less)
1120  , lessOrEqual_(lessOrEqual)
1121  , alpha_u_(wordBitSize, "alpha")
1122  , notAllZeroes_("notAllZeroes")
1123 {
1124 }
1125 
1126 void R1P_Comparison_Gadget::init()
1127 {
1128  allZeroesTest_ = OR_Gadget::create(pb_, alpha_u_, notAllZeroes_);
1129  alpha_u_.emplace_back(lessOrEqual_);
1130  alphaDualVariablePacker_ = CompressionPacking_Gadget::create(
1131  pb_, alpha_u_, VariableArray(1, alpha_p_), PackingMode::UNPACK);
1132 }
1133 /*
1134  Constraint breakdown:
1135 
1136  for succinctness we shall define:
1137  (1) wordBitSize == n
1138  (2) lhs == A
1139  (3) rhs == B
1140 
1141  packed(alpha) = 2^n + B - A
1142  not_all_zeros = OR(alpha.unpacked)
1143 
1144  if B - A > 0, then: alpha > 2^n,
1145  so alpha[n] = 1 and notAllZeroes = 1
1146  if B - A = 0, then: alpha = 2^n,
1147  so alpha[n] = 1 and notAllZeroes = 0
1148  if B - A < 0, then: 0 <= alpha <= 2^n-1
1149  so alpha[n] = 0
1150 
1151  therefore:
1152  (1) alpha[n] = lessOrEqual
1153  (2) alpha[n] * notAllZeroes = less
1154 
1155 
1156 */
1158 {
1159  enforceBooleanity(notAllZeroes_);
1160  const FElem two_n = long(POW2(wordBitSize_));
1162  1, alpha_p_, two_n + rhs_ - lhs_, "packed(alpha) = 2^n + B - A");
1163  alphaDualVariablePacker_->generateConstraints();
1164  allZeroesTest_->generateConstraints();
1166  1, alpha_u_[wordBitSize_], lessOrEqual_, "alpha[n] = lessOrEqual");
1168  alpha_u_[wordBitSize_],
1169  notAllZeroes_,
1170  less_,
1171  "alpha[n] * notAllZeroes = less");
1172 }
1173 
1175 {
1176  const FElem two_n = long(POW2(wordBitSize_));
1177  val(alpha_p_) = two_n + val(rhs_) - val(lhs_);
1178  alphaDualVariablePacker_->generateWitness();
1179  allZeroesTest_->generateWitness();
1180  val(lessOrEqual_) = val(alpha_u_[wordBitSize_]);
1181  val(less_) = val(lessOrEqual_) * val(notAllZeroes_);
1182 }
1183 
1184 /*********************************/
1185 /*** END OF Gadget ***/
1186 /*********************************/
1187 
1188 } // namespace gadgetlib2
gadgetlib2::DualWord
Holds both representations of a word, both multipacked and unpacked.
Definition: variable.hpp:424
gadgetlib2::R1P_Gadget
Definition: gadget.hpp:146
gadgetlib2::LooseMUX_GadgetBase
Definition: gadget.hpp:380
gadgetlib2::OR_Gadget::create
static GadgetPtr create(ProtoboardPtr pb, const VariableArray &input, const Variable &result)
Definition: gadget.cpp:323
gadgetlib2::R1P_OR_Gadget::input_
const VariableArray input_
Definition: gadget.hpp:291
gadgetlib2::Toggle_Gadget::generateWitness
void generateWitness()
Definition: gadget.cpp:963
gadgetlib2::BinaryAND_Gadget
Specific case for and AND with two inputs. Field agnostic.
Definition: gadget.hpp:175
gadgetlib2::R1P_AND_Gadget::generateConstraints
void generateConstraints()
Definition: gadget.cpp:163
gadgetlib2::Gadget::generateWitness
virtual void generateWitness()
Definition: gadget.cpp:46
gadgetlib2::R1P_AND_Gadget
Definition: gadget.hpp:199
gadgetlib2::GADGETLIB2_FMT
::std::string GADGETLIB2_FMT(const char *format,...)
Definition: infrastructure.cpp:49
gadgetlib2::R1P_CompressionPacking_Gadget::packed_
const VariableArray packed_
Definition: gadget.hpp:476
gadgetlib2::POW2
int64_t POW2(int exponent)
Definition: infrastructure.hpp:118
gadgetlib2::LooseMUX_GadgetBase::~LooseMUX_GadgetBase
virtual ~LooseMUX_GadgetBase()=0
Definition: gadget.cpp:455
gadgetlib2::DualWord_Gadget::generateConstraints
void generateConstraints()
Definition: gadget.cpp:850
gadgetlib2::R1P_IntegerPacking_Gadget::generateWitness
void generateWitness()
Definition: gadget.cpp:761
gadgetlib2::DualWordArray_Gadget::generateWitness
void generateWitness()
Definition: gadget.cpp:900
gadgetlib2::PackingMode::UNPACK
@ UNPACK
gadgetlib2::DualWordArray_Gadget::generateConstraints
void generateConstraints()
Definition: gadget.cpp:893
gadgetlib2::R1P_OR_Gadget::generateWitness
void generateWitness()
Definition: gadget.cpp:308
gadgetlib2::R1P_EqualsConst_Gadget::result_
const Variable result_
Definition: gadget.hpp:583
gadgetlib2::LogicImplication_Gadget::generateWitness
void generateWitness()
Definition: gadget.cpp:1085
gadgetlib2::MultiPackedWordArray
::std::vector< MultiPackedWord > MultiPackedWordArray
Definition: variable.hpp:421
gadgetlib2::FlagVariable
Variable FlagVariable
Definition: variable.hpp:378
gadgetlib2::R1P_CompressionPacking_Gadget::unpacked_
const VariableArray unpacked_
Definition: gadget.hpp:475
gadgetlib2::R1P_LooseMUX_Gadget::successFlag_
const Variable successFlag_
Definition: gadget.hpp:413
gadgetlib2::R1P_OR_Gadget
Definition: gadget.hpp:279
gadgetlib2::R1P_CompressionPacking_Gadget::generateConstraints
void generateConstraints()
Definition: gadget.cpp:654
gadgetlib2::Toggle_Gadget::generateConstraints
void generateConstraints()
Definition: gadget.cpp:954
gadgetlib2::R1P_Gadget::addRank1Constraint
virtual void addRank1Constraint(const LinearCombination &a, const LinearCombination &b, const LinearCombination &c, const ::std::string &name)
Definition: gadget.cpp:72
gadgetlib2::negate
LinearCombination negate(const LinearCombination &lc)
Definition: variable.cpp:625
gadgetlib2::ConditionalFlag_Gadget::create
static GadgetPtr create(ProtoboardPtr pb, const LinearCombination &condition, const FlagVariable &flag)
Definition: gadget.cpp:1008
gadgetlib2::Gadget::addRank1Constraint
void addRank1Constraint(const LinearCombination &a, const LinearCombination &b, const LinearCombination &c, const ::std::string &name)
Definition: gadget.cpp:58
gadgetlib2::DualWordArray::multipacked
MultiPackedWordArray multipacked() const
Definition: variable.cpp:457
gadgetlib2::BinaryOR_Gadget
Specific case for and OR with two inputs. Field agnostic.
Definition: gadget.hpp:255
gadgetlib2::LooseMUX_Gadget::create
static GadgetPtr create(ProtoboardPtr pb, const MultiPackedWordArray &inputs, const Variable &index, const VariableArray &output, const Variable &successFlag)
Definition: gadget.cpp:556
gadgetlib2::LogicImplication_Gadget
Definition: gadget.hpp:772
gadgetlib2::R1P_LooseMUX_Gadget::indicatorVariables
virtual VariableArray indicatorVariables() const
Definition: gadget.cpp:551
gadgetlib2::VariableArray
VariableArray.
Definition: variable.hpp:353
gadgetlib2::MultiPackedWord
Definition: variable.hpp:404
gadgetlib2::Gadget::val
FElem & val(const Variable &var)
Definition: gadget.hpp:109
gadgetlib2::R1P_LooseMUX_Gadget
Definition: gadget.hpp:394
gadgetlib2::Gadget
Definition: gadget.hpp:81
gadgetlib2::FElem::asLong
long asLong() const
Definition: variable.hpp:140
gadgetlib2::R1P_LooseMUX_Gadget::index_
const Variable index_
Definition: gadget.hpp:411
GADGETLIB_FATAL
#define GADGETLIB_FATAL(msg)
Definition: infrastructure.hpp:85
gadgetlib2::UnpackedWordArray
::std::vector< UnpackedWord > UnpackedWordArray
Definition: variable.hpp:399
gadgetlib2::DualWordArray_Gadget
Definition: gadget.hpp:642
gadgetlib2::R1P_Comparison_Gadget::generateConstraints
void generateConstraints()
Definition: gadget.cpp:1157
gadgetlib2::R1P_OR_Gadget::generateConstraints
void generateConstraints()
Definition: gadget.cpp:297
gadgetlib2::R1P_CompressionPacking_Gadget::generateWitness
void generateWitness()
Definition: gadget.cpp:670
gadget.hpp
gadgetlib2::R1P_LooseMUX_Gadget::inputs_
MultiPackedWordArray inputs_
Definition: gadget.hpp:410
gadgetlib2::PackedWord
Variable PackedWord
Definition: variable.hpp:384
gadgetlib2::ConditionalFlag_Gadget
Definition: gadget.hpp:730
gadgetlib2::FElem
Definition: variable.hpp:101
gadgetlib2::Toggle_Gadget
Definition: gadget.hpp:682
gadgetlib2::Toggle_Gadget::create
static GadgetPtr create(ProtoboardPtr pb, const FlagVariable &toggle, const LinearCombination &zeroValue, const LinearCombination &oneValue, const Variable &result)
Definition: gadget.cpp:941
gadgetlib2::Gadget::Gadget
Gadget(ProtoboardPtr pb)
Definition: gadget.cpp:39
gadgetlib2::R1P_AND_Gadget::generateWitness
void generateWitness()
Definition: gadget.cpp:174
gadgetlib2::DualWord_Gadget::create
static GadgetPtr create(ProtoboardPtr pb, const DualWord &var, PackingMode packingMode)
Definition: gadget.cpp:842
gadgetlib2::GadgetPtr
::std::shared_ptr< Gadget > GadgetPtr
Definition: gadget.hpp:119
gadgetlib2::R1P_InnerProduct_Gadget::A_
const VariableArray A_
Definition: gadget.hpp:346
gadgetlib2::DualWord_Gadget::generateWitness
void generateWitness()
Definition: gadget.cpp:855
gadgetlib2::DualWordArray_Gadget::create
static GadgetPtr create(ProtoboardPtr pb, const DualWordArray &vars, PackingMode packingMode)
Definition: gadget.cpp:885
gadgetlib2::PackingMode
PackingMode
Definition: gadget.hpp:457
gadgetlib2::LogicImplication_Gadget::generateConstraints
void generateConstraints()
Definition: gadget.cpp:1079
gadgetlib2::R1P_EqualsConst_Gadget::generateWitness
void generateWitness()
Definition: gadget.cpp:813
gadgetlib2::R1P_Comparison_Gadget::generateWitness
void generateWitness()
Definition: gadget.cpp:1174
gadgetlib2::Gadget::enforceBooleanity
void enforceBooleanity(const Variable &var)
Definition: gadget.hpp:108
gadgetlib2::ConditionalFlag_Gadget::generateConstraints
void generateConstraints()
Definition: gadget.cpp:1018
gadgetlib2::R1P_OR_Gadget::result_
const Variable result_
Definition: gadget.hpp:292
gadgetlib2::R1P_Gadget::R1P_Gadget
R1P_Gadget(ProtoboardPtr pb)
Definition: gadget.hpp:149
gadgetlib2::R1P_InnerProduct_Gadget::generateWitness
void generateWitness()
Definition: gadget.cpp:428
gadgetlib2::ConditionalFlag_Gadget::generateWitness
void generateWitness()
Definition: gadget.cpp:1029
gadgetlib2::R1P_IntegerPacking_Gadget::generateConstraints
void generateConstraints()
Definition: gadget.cpp:756
gadgetlib2::PackingMode::PACK
@ PACK
gadgetlib2::Gadget::addUnaryConstraint
void addUnaryConstraint(const LinearCombination &a, const ::std::string &name)
Definition: gadget.cpp:52
gadgetlib2::R1P_EqualsConst_Gadget::input_
const LinearCombination input_
Definition: gadget.hpp:582
gadgetlib2::R1P_InnerProduct_Gadget::result_
const Variable result_
Definition: gadget.hpp:347
gadgetlib2::R1P_LooseMUX_Gadget::output_
const VariableArray output_
Definition: gadget.hpp:412
gadgetlib2::R1P_InnerProduct_Gadget::B_
const VariableArray B_
Definition: gadget.hpp:346
gadgetlib2::DualWord::multipacked
MultiPackedWord multipacked() const
Definition: variable.hpp:439
gadgetlib2::Variable
A formal variable, field agnostic.
Definition: variable.hpp:306
gadgetlib2::DualWordArray
Definition: variable.hpp:449
GADGETLIB_ASSERT
#define GADGETLIB_ASSERT(predicate, msg)
Definition: infrastructure.hpp:94
gadgetlib2::LogicImplication_Gadget::create
static GadgetPtr create(ProtoboardPtr pb, const LinearCombination &condition, const FlagVariable &flag)
Definition: gadget.cpp:1069
gadgetlib2::FElem::inverse
FElem inverse(const FieldType &fieldType)
Definition: variable.cpp:122
gadgetlib2::DualWord::unpacked
UnpackedWord unpacked() const
Definition: variable.hpp:440
gadgetlib2::DualWord_Gadget
Definition: gadget.hpp:608
gadgetlib2::sum
LinearCombination sum(const VariableArray &inputs)
Definition: variable.cpp:616
gadgetlib2::R1P_LooseMUX_Gadget::generateWitness
void generateWitness()
Definition: gadget.cpp:531
gadgetlib2::Gadget::pb_
ProtoboardPtr pb_
Definition: gadget.hpp:87
gadgetlib2::LinearCombination
LinearCombination.
Definition: variable.hpp:503
gadgetlib2::ProtoboardPtr
::std::shared_ptr< Protoboard > ProtoboardPtr
Definition: variable.hpp:42
gadgetlib2::R1P_EqualsConst_Gadget::generateConstraints
void generateConstraints()
Definition: gadget.cpp:806
gadgetlib2::DualWordArray::size
size_t size() const
Definition: variable.cpp:493
gadgetlib2::R1P_LooseMUX_Gadget::generateConstraints
void generateConstraints()
Definition: gadget.cpp:513
gadgetlib2::Gadget::fieldType
FieldType fieldType() const
Definition: gadget.hpp:111
gadgetlib2::AND_Gadget::create
static GadgetPtr create(ProtoboardPtr pb, const VariableArray &input, const Variable &result)
Definition: gadget.cpp:190
gadgetlib2::R1P_InnerProduct_Gadget::generateConstraints
void generateConstraints()
Definition: gadget.cpp:399
gadgetlib2
Definition: adapters.cpp:15
gadgetlib2::R1P_Gadget::~R1P_Gadget
virtual ~R1P_Gadget()=0
Definition: gadget.cpp:70
gadgetlib2::R1P
@ R1P
Definition: variable.hpp:37
gadgetlib2::DualWordArray::unpacked
UnpackedWordArray unpacked() const
Definition: variable.cpp:461
gadgetlib2::Fp
libff::Fr< libff::default_ec_pp > Fp
Definition: pp.hpp:29
gadgetlib2::R1P_Elem
Definition: variable.hpp:245