20 using ::std::shared_ptr;
43 "Attempted to create gadget with uninitialized Protoboard.");
49 "Attempted to generate witness for an incomplete Gadget type.");
55 pb_->addUnaryConstraint(a, name);
62 const ::std::string &name)
64 pb_->addRank1Constraint(a, b, c, name);
78 pb_->addRank1Constraint(a, b, c, name);
92 AND_GadgetBase::~AND_GadgetBase(){};
98 BinaryAND_Gadget::BinaryAND_Gadget(
100 const LinearCombination &input1,
101 const LinearCombination &input2,
102 const Variable &result)
111 void BinaryAND_Gadget::init() {}
113 void BinaryAND_Gadget::generateConstraints()
116 input1_, input2_, result_,
"result = AND(input1, input2)");
119 void BinaryAND_Gadget::generateWitness()
121 if (val(input1_) == 1 && val(input2_) == 1) {
139 R1P_AND_Gadget::R1P_AND_Gadget(
140 ProtoboardPtr pb,
const VariableArray &input,
const Variable &result)
146 , sumInverse_(
"sumInverse")
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!");
157 void R1P_AND_Gadget::init()
159 const int numInputs = input_.size();
160 sum_ =
sum(input_) - numInputs;
166 sum_, result_, 0,
"sum * result = 0 | sum == sum(input[i]) - n");
171 "sumInverse * sum = 1-result | sum == sum(input[i]) - n");
177 for (
size_t i = 0; i < input_.size(); ++i) {
180 sum -= input_.size();
182 val(sumInverse_) = 0;
194 if (pb->fieldType_ ==
R1P) {
198 "Attempted to create gadget of undefined Protoboard type.");
226 OR_GadgetBase::~OR_GadgetBase(){};
233 BinaryOR_Gadget::BinaryOR_Gadget(
235 const LinearCombination &input1,
236 const LinearCombination &input2,
237 const Variable &result)
246 void BinaryOR_Gadget::init() {}
248 void BinaryOR_Gadget::generateConstraints()
253 input1_ + input2_ - result_,
254 "result = OR(input1, input2)");
257 void BinaryOR_Gadget::generateWitness()
259 if (val(input1_) == 1 || val(input2_) == 1) {
277 R1P_OR_Gadget::R1P_OR_Gadget(
278 ProtoboardPtr pb,
const VariableArray &input,
const Variable &result)
282 , sumInverse_(
"sumInverse")
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!");
295 void R1P_OR_Gadget::init() { sum_ =
sum(
input_); }
300 sum_, 1 -
result_, 0,
"sum * (1 - result) = 0 | sum == sum(input[i])");
305 "sum * sumInverse = result | sum == sum(input[i])");
311 for (
size_t i = 0; i <
input_.size(); ++i) {
315 val(sumInverse_) = 0;
327 if (pb->fieldType_ ==
R1P) {
331 "Attempted to create gadget of undefined Protoboard type.");
359 InnerProduct_GadgetBase::~InnerProduct_GadgetBase(){};
372 R1P_InnerProduct_Gadget::R1P_InnerProduct_Gadget(
374 const VariableArray &A,
375 const VariableArray &B,
376 const Variable &result)
378 , InnerProduct_GadgetBase(pb)
380 , partialSums_(A.size(),
"partialSums")
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",
397 void R1P_InnerProduct_Gadget::init() {}
401 const int n =
A_.size();
408 A_[0],
B_[0], partialSums_[0],
"A[0] * B[0] = partialSums[0]");
409 for (
int i = 1; i <= n - 2; ++i) {
413 partialSums_[i] - partialSums_[i - 1],
415 "A[%u] * B[%u] = partialSums[%u] - partialSums[%u]",
425 "A[n-1] * B[n-1] = result - partialSums[n-2]");
430 const int n =
A_.size();
437 for (
int i = 1; i <= n - 2; ++i) {
438 val(partialSums_[i]) =
467 R1P_LooseMUX_Gadget::R1P_LooseMUX_Gadget(
476 , indicators_(inputs.size(),
"indicators")
477 , inputs_(inputs.size())
480 , successFlag_(successFlag)
483 inputs.size() <=
Fp(-1).as_ulong(),
484 "Attempted to create R1P_LooseMUX_Gadget "
485 "with too many inputs. May cause overflow!");
487 for (
size_t i = 0; i < inputs.size(); ++i) {
489 inputs[i].size() == output.size(),
490 "Input VariableArray is of incorrect size.");
498 void R1P_LooseMUX_Gadget::init()
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]);
508 computeResult_.push_back(InnerProduct_Gadget::create(
515 const size_t n =
inputs_.size();
516 for (
size_t i = 0; i < n; ++i) {
524 sum(indicators_), 1,
successFlag_,
"sum(indicators) * 1 = successFlag");
526 for (
auto &curGadget : computeResult_) {
527 curGadget->generateConstraints();
533 const size_t n =
inputs_.size();
536 const FElem arraySize = n;
537 for (
size_t i = 0; i < n; ++i) {
538 val(indicators_[i]) = 0;
543 val(indicators_[index]) = 1;
546 for (
auto &curGadget : computeResult_) {
547 curGadget->generateWitness();
564 if (pb->fieldType_ ==
R1P) {
569 "Attempted to create gadget of undefined Protoboard type.");
587 for (
size_t i = 0; i < inputs.size(); ++i) {
589 cur.push_back(inputs[i]);
590 inpVec.push_back(cur);
593 outVec.push_back(output);
622 CompressionPacking_GadgetBase::~CompressionPacking_GadgetBase(){};
631 R1P_CompressionPacking_Gadget::R1P_CompressionPacking_Gadget(
633 const VariableArray &unpacked,
634 const VariableArray &packed,
637 , CompressionPacking_GadgetBase(pb)
639 , packingMode_(packingMode)
640 , unpacked_(unpacked)
643 const int n = unpacked.size();
647 "Attempted to pack into more than 1 Variable in "
648 "R1P_CompressionPacking_Gadget.")
652 void R1P_CompressionPacking_Gadget::init() {}
656 const int n = unpacked_.size();
659 for (
int i = 0; i < n; ++i) {
660 packed += unpacked_[i] * two_i;
663 enforceBooleanity(unpacked_[i]);
667 packed_[0], 1, packed,
"packed[0] = sum(2^i * unpacked[i])");
672 const int n = unpacked_.size();
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.",
683 val(unpacked_[i]).asLong()));
684 packedVal += two_i * val(unpacked_[i]).
asLong();
687 val(packed_[0]) = packedVal;
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);
721 IntegerPacking_GadgetBase::~IntegerPacking_GadgetBase(){};
730 R1P_IntegerPacking_Gadget::R1P_IntegerPacking_Gadget(
732 const VariableArray &unpacked,
733 const VariableArray &packed,
736 , IntegerPacking_GadgetBase(pb)
738 , packingMode_(packingMode)
739 , unpacked_(unpacked)
742 const int n = unpacked.size();
746 "Attempted to pack into more than 1 Variable in "
747 "R1P_IntegerPacking_Gadget.")
750 void R1P_IntegerPacking_Gadget::init()
752 compressionPackingGadget_ = CompressionPacking_Gadget::create(
758 compressionPackingGadget_->generateConstraints();
763 compressionPackingGadget_->generateWitness();
777 EqualsConst_GadgetBase::~EqualsConst_GadgetBase(){};
789 R1P_EqualsConst_Gadget::R1P_EqualsConst_Gadget(
792 const LinearCombination &input,
793 const Variable &result)
795 , EqualsConst_GadgetBase(pb)
798 , aux_(
"aux (R1P_EqualsConst_Gadget)")
804 void R1P_EqualsConst_Gadget::init() {}
810 input_ - n_, aux_, 1 -
result_,
"(input - n) * aux = 1 - result");
830 DualWord_Gadget::DualWord_Gadget(
832 :
Gadget(pb), var_(var), packingMode_(packingMode), packingGadget_()
836 void DualWord_Gadget::init()
838 packingGadget_ = CompressionPacking_Gadget::create(
852 packingGadget_->generateConstraints();
868 DualWordArray_Gadget::DualWordArray_Gadget(
870 :
Gadget(pb), vars_(vars), packingMode_(packingMode), packingGadgets_()
874 void DualWordArray_Gadget::init()
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);
895 for (
auto &gadget : packingGadgets_) {
896 gadget->generateConstraints();
902 for (
auto &gadget : packingGadgets_) {
903 gadget->generateWitness();
927 Toggle_Gadget::Toggle_Gadget(
935 , zeroValue_(zeroValue)
936 , oneValue_(oneValue)
956 pb_->addRank1Constraint(
958 oneValue_ - zeroValue_,
959 result_ - zeroValue_,
960 "result = (1 - toggle) * zeroValue + toggle * oneValue");
965 if (
val(toggle_) == 0) {
966 val(result_) =
val(zeroValue_);
967 }
else if (
val(toggle_) == 1) {
968 val(result_) =
val(oneValue_);
997 ConditionalFlag_Gadget::ConditionalFlag_Gadget(
1003 , condition_(condition)
1004 , auxConditionInverse_(
"ConditionalFlag_Gadget::auxConditionInverse_")
1020 pb_->addRank1Constraint(
1021 condition_,
negate(flag_), 0,
"condition * not(flag) = 0");
1022 pb_->addRank1Constraint(
1024 auxConditionInverse_,
1026 "condition * auxConditionInverse = flag");
1031 if (
val(condition_) == 0) {
1033 val(auxConditionInverse_) = 0;
1061 LogicImplication_Gadget::LogicImplication_Gadget(
1065 :
Gadget(pb), flag_(flag), condition_(condition)
1081 pb_->addRank1Constraint(
1082 condition_,
negate(flag_), 0,
"condition * not(flag) = 0");
1087 if (
val(condition_) == 1) {
1104 Comparison_GadgetBase::~Comparison_GadgetBase() {}
1106 R1P_Comparison_Gadget::R1P_Comparison_Gadget(
1108 const size_t &wordBitSize,
1114 , Comparison_GadgetBase(pb)
1116 , wordBitSize_(wordBitSize)
1120 , lessOrEqual_(lessOrEqual)
1121 , alpha_u_(wordBitSize,
"alpha")
1122 , notAllZeroes_(
"notAllZeroes")
1126 void R1P_Comparison_Gadget::init()
1129 alpha_u_.emplace_back(lessOrEqual_);
1130 alphaDualVariablePacker_ = CompressionPacking_Gadget::create(
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_],
1171 "alpha[n] * notAllZeroes = less");
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_);