diff --git a/privacy/zsl/zsl/Makefile b/privacy/zsl/zsl/Makefile new file mode 100644 index 0000000..a27a9da --- /dev/null +++ b/privacy/zsl/zsl/Makefile @@ -0,0 +1,21 @@ +OPTFLAGS = -march=native -mtune=native -O2 +CXXFLAGS += -g -Wall -Wextra -Wno-unused-parameter -std=c++11 -fPIC -Wno-unused-variable +CXXFLAGS += -I./ -DCURVE_ALT_BN128 -DBINARY_OUTPUT -DMONTGOMERY_OUTPUT -DNO_PT_COMPRESSION=1 -DMULTICORE -fopenmp -DNO_PROCPS +CXXFLAGS += $(OPTFLAGS) +LDFLAGS += -flto + +LDLIBS += -lgmpxx -lgmp -lboost_system -fopenmp + +all: + $(CXX) -o zsl.o -x c++ impl.tcc -c $(CXXFLAGS) + $(CXX) -o alt_bn128_g1.o algebra/curves/alt_bn128/alt_bn128_g1.cpp -c $(CXXFLAGS) + $(CXX) -o alt_bn128_g2.o algebra/curves/alt_bn128/alt_bn128_g2.cpp -c $(CXXFLAGS) + $(CXX) -o alt_bn128_init.o algebra/curves/alt_bn128/alt_bn128_init.cpp -c $(CXXFLAGS) + $(CXX) -o alt_bn128_pairing.o algebra/curves/alt_bn128/alt_bn128_pairing.cpp -c $(CXXFLAGS) + $(CXX) -o alt_bn128_pp.o algebra/curves/alt_bn128/alt_bn128_pp.cpp -c $(CXXFLAGS) + $(CXX) -o libsnark_utils.o common/utils.cpp -c $(CXXFLAGS) + $(CXX) -o libsnark_profiling.o common/profiling.cpp -c $(CXXFLAGS) + ar -rcs libzsl.a zsl.o alt_bn128_g1.o alt_bn128_g2.o alt_bn128_init.o alt_bn128_pairing.o alt_bn128_pp.o libsnark_utils.o libsnark_profiling.o + +clean: + $(RM) libzsl.a zsl.o libsnark_profiling.o libsnark_utils.o alt_bn128_pp.o alt_bn128_g1.o alt_bn128_g2.o alt_bn128_init.o alt_bn128_pairing.o diff --git a/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_g1.cpp b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_g1.cpp new file mode 100644 index 0000000..bf7f43d --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_g1.cpp @@ -0,0 +1,524 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/alt_bn128/alt_bn128_g1.hpp" + +namespace libsnark { + +#ifdef PROFILE_OP_COUNTS +long long alt_bn128_G1::add_cnt = 0; +long long alt_bn128_G1::dbl_cnt = 0; +#endif + +std::vector alt_bn128_G1::wnaf_window_table; +std::vector alt_bn128_G1::fixed_base_exp_window_table; +alt_bn128_G1 alt_bn128_G1::G1_zero; +alt_bn128_G1 alt_bn128_G1::G1_one; + +alt_bn128_G1::alt_bn128_G1() +{ + this->X = G1_zero.X; + this->Y = G1_zero.Y; + this->Z = G1_zero.Z; +} + +void alt_bn128_G1::print() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + alt_bn128_G1 copy(*this); + copy.to_affine_coordinates(); + gmp_printf("(%Nd , %Nd)\n", + copy.X.as_bigint().data, alt_bn128_Fq::num_limbs, + copy.Y.as_bigint().data, alt_bn128_Fq::num_limbs); + } +} + +void alt_bn128_G1::print_coordinates() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + gmp_printf("(%Nd : %Nd : %Nd)\n", + this->X.as_bigint().data, alt_bn128_Fq::num_limbs, + this->Y.as_bigint().data, alt_bn128_Fq::num_limbs, + this->Z.as_bigint().data, alt_bn128_Fq::num_limbs); + } +} + +void alt_bn128_G1::to_affine_coordinates() +{ + if (this->is_zero()) + { + this->X = alt_bn128_Fq::zero(); + this->Y = alt_bn128_Fq::one(); + this->Z = alt_bn128_Fq::zero(); + } + else + { + alt_bn128_Fq Z_inv = Z.inverse(); + alt_bn128_Fq Z2_inv = Z_inv.squared(); + alt_bn128_Fq Z3_inv = Z2_inv * Z_inv; + this->X = this->X * Z2_inv; + this->Y = this->Y * Z3_inv; + this->Z = alt_bn128_Fq::one(); + } +} + +void alt_bn128_G1::to_special() +{ + this->to_affine_coordinates(); +} + +bool alt_bn128_G1::is_special() const +{ + return (this->is_zero() || this->Z == alt_bn128_Fq::one()); +} + +bool alt_bn128_G1::is_zero() const +{ + return (this->Z.is_zero()); +} + +bool alt_bn128_G1::operator==(const alt_bn128_G1 &other) const +{ + if (this->is_zero()) + { + return other.is_zero(); + } + + if (other.is_zero()) + { + return false; + } + + /* now neither is O */ + + // using Jacobian coordinates so: + // (X1:Y1:Z1) = (X2:Y2:Z2) + // iff + // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 + // iff + // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 + + alt_bn128_Fq Z1_squared = (this->Z).squared(); + alt_bn128_Fq Z2_squared = (other.Z).squared(); + + if ((this->X * Z2_squared) != (other.X * Z1_squared)) + { + return false; + } + + alt_bn128_Fq Z1_cubed = (this->Z) * Z1_squared; + alt_bn128_Fq Z2_cubed = (other.Z) * Z2_squared; + + if ((this->Y * Z2_cubed) != (other.Y * Z1_cubed)) + { + return false; + } + + return true; +} + +bool alt_bn128_G1::operator!=(const alt_bn128_G1& other) const +{ + return !(operator==(other)); +} + +alt_bn128_G1 alt_bn128_G1::operator+(const alt_bn128_G1 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // check for doubling case + + // using Jacobian coordinates so: + // (X1:Y1:Z1) = (X2:Y2:Z2) + // iff + // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 + // iff + // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 + + alt_bn128_Fq Z1Z1 = (this->Z).squared(); + alt_bn128_Fq Z2Z2 = (other.Z).squared(); + + alt_bn128_Fq U1 = this->X * Z2Z2; + alt_bn128_Fq U2 = other.X * Z1Z1; + + alt_bn128_Fq Z1_cubed = (this->Z) * Z1Z1; + alt_bn128_Fq Z2_cubed = (other.Z) * Z2Z2; + + alt_bn128_Fq S1 = (this->Y) * Z2_cubed; // S1 = Y1 * Z2 * Z2Z2 + alt_bn128_Fq S2 = (other.Y) * Z1_cubed; // S2 = Y2 * Z1 * Z1Z1 + + if (U1 == U2 && S1 == S2) + { + // dbl case; nothing of above can be reused + return this->dbl(); + } + + // rest of add case + alt_bn128_Fq H = U2 - U1; // H = U2-U1 + alt_bn128_Fq S2_minus_S1 = S2-S1; + alt_bn128_Fq I = (H+H).squared(); // I = (2 * H)^2 + alt_bn128_Fq J = H * I; // J = H * I + alt_bn128_Fq r = S2_minus_S1 + S2_minus_S1; // r = 2 * (S2-S1) + alt_bn128_Fq V = U1 * I; // V = U1 * I + alt_bn128_Fq X3 = r.squared() - J - (V+V); // X3 = r^2 - J - 2 * V + alt_bn128_Fq S1_J = S1 * J; + alt_bn128_Fq Y3 = r * (V-X3) - (S1_J+S1_J); // Y3 = r * (V-X3)-2 S1 J + alt_bn128_Fq Z3 = ((this->Z+other.Z).squared()-Z1Z1-Z2Z2) * H; // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H + + return alt_bn128_G1(X3, Y3, Z3); +} + +alt_bn128_G1 alt_bn128_G1::operator-() const +{ + return alt_bn128_G1(this->X, -(this->Y), this->Z); +} + + +alt_bn128_G1 alt_bn128_G1::operator-(const alt_bn128_G1 &other) const +{ + return (*this) + (-other); +} + +alt_bn128_G1 alt_bn128_G1::add(const alt_bn128_G1 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case + if (this->operator==(other)) + { + return this->dbl(); + } + +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl + + alt_bn128_Fq Z1Z1 = (this->Z).squared(); // Z1Z1 = Z1^2 + alt_bn128_Fq Z2Z2 = (other.Z).squared(); // Z2Z2 = Z2^2 + alt_bn128_Fq U1 = (this->X) * Z2Z2; // U1 = X1 * Z2Z2 + alt_bn128_Fq U2 = (other.X) * Z1Z1; // U2 = X2 * Z1Z1 + alt_bn128_Fq S1 = (this->Y) * (other.Z) * Z2Z2; // S1 = Y1 * Z2 * Z2Z2 + alt_bn128_Fq S2 = (other.Y) * (this->Z) * Z1Z1; // S2 = Y2 * Z1 * Z1Z1 + alt_bn128_Fq H = U2 - U1; // H = U2-U1 + alt_bn128_Fq S2_minus_S1 = S2-S1; + alt_bn128_Fq I = (H+H).squared(); // I = (2 * H)^2 + alt_bn128_Fq J = H * I; // J = H * I + alt_bn128_Fq r = S2_minus_S1 + S2_minus_S1; // r = 2 * (S2-S1) + alt_bn128_Fq V = U1 * I; // V = U1 * I + alt_bn128_Fq X3 = r.squared() - J - (V+V); // X3 = r^2 - J - 2 * V + alt_bn128_Fq S1_J = S1 * J; + alt_bn128_Fq Y3 = r * (V-X3) - (S1_J+S1_J); // Y3 = r * (V-X3)-2 S1 J + alt_bn128_Fq Z3 = ((this->Z+other.Z).squared()-Z1Z1-Z2Z2) * H; // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H + + return alt_bn128_G1(X3, Y3, Z3); +} + +alt_bn128_G1 alt_bn128_G1::mixed_add(const alt_bn128_G1 &other) const +{ +#ifdef DEBUG + assert(other.is_special()); +#endif + + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // check for doubling case + + // using Jacobian coordinates so: + // (X1:Y1:Z1) = (X2:Y2:Z2) + // iff + // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 + // iff + // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 + + // we know that Z2 = 1 + + const alt_bn128_Fq Z1Z1 = (this->Z).squared(); + + const alt_bn128_Fq &U1 = this->X; + const alt_bn128_Fq U2 = other.X * Z1Z1; + + const alt_bn128_Fq Z1_cubed = (this->Z) * Z1Z1; + + const alt_bn128_Fq &S1 = (this->Y); // S1 = Y1 * Z2 * Z2Z2 + const alt_bn128_Fq S2 = (other.Y) * Z1_cubed; // S2 = Y2 * Z1 * Z1Z1 + + if (U1 == U2 && S1 == S2) + { + // dbl case; nothing of above can be reused + return this->dbl(); + } + +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl + alt_bn128_Fq H = U2-(this->X); // H = U2-X1 + alt_bn128_Fq HH = H.squared() ; // HH = H&2 + alt_bn128_Fq I = HH+HH; // I = 4*HH + I = I + I; + alt_bn128_Fq J = H*I; // J = H*I + alt_bn128_Fq r = S2-(this->Y); // r = 2*(S2-Y1) + r = r + r; + alt_bn128_Fq V = (this->X) * I ; // V = X1*I + alt_bn128_Fq X3 = r.squared()-J-V-V; // X3 = r^2-J-2*V + alt_bn128_Fq Y3 = (this->Y)*J; // Y3 = r*(V-X3)-2*Y1*J + Y3 = r*(V-X3) - Y3 - Y3; + alt_bn128_Fq Z3 = ((this->Z)+H).squared() - Z1Z1 - HH; // Z3 = (Z1+H)^2-Z1Z1-HH + + return alt_bn128_G1(X3, Y3, Z3); +} + +alt_bn128_G1 alt_bn128_G1::dbl() const +{ +#ifdef PROFILE_OP_COUNTS + this->dbl_cnt++; +#endif + // handle point at infinity + if (this->is_zero()) + { + return (*this); + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l + + alt_bn128_Fq A = (this->X).squared(); // A = X1^2 + alt_bn128_Fq B = (this->Y).squared(); // B = Y1^2 + alt_bn128_Fq C = B.squared(); // C = B^2 + alt_bn128_Fq D = (this->X + B).squared() - A - C; + D = D+D; // D = 2 * ((X1 + B)^2 - A - C) + alt_bn128_Fq E = A + A + A; // E = 3 * A + alt_bn128_Fq F = E.squared(); // F = E^2 + alt_bn128_Fq X3 = F - (D+D); // X3 = F - 2 D + alt_bn128_Fq eightC = C+C; + eightC = eightC + eightC; + eightC = eightC + eightC; + alt_bn128_Fq Y3 = E * (D - X3) - eightC; // Y3 = E * (D - X3) - 8 * C + alt_bn128_Fq Y1Z1 = (this->Y)*(this->Z); + alt_bn128_Fq Z3 = Y1Z1 + Y1Z1; // Z3 = 2 * Y1 * Z1 + + return alt_bn128_G1(X3, Y3, Z3); +} + +bool alt_bn128_G1::is_well_formed() const +{ + if (this->is_zero()) + { + return true; + } + else + { + /* + y^2 = x^3 + b + + We are using Jacobian coordinates, so equation we need to check is actually + + (y/z^3)^2 = (x/z^2)^3 + b + y^2 / z^6 = x^3 / z^6 + b + y^2 = x^3 + b z^6 + */ + alt_bn128_Fq X2 = this->X.squared(); + alt_bn128_Fq Y2 = this->Y.squared(); + alt_bn128_Fq Z2 = this->Z.squared(); + + alt_bn128_Fq X3 = this->X * X2; + alt_bn128_Fq Z3 = this->Z * Z2; + alt_bn128_Fq Z6 = Z3.squared(); + + return (Y2 == X3 + alt_bn128_coeff_b * Z6); + } +} + +alt_bn128_G1 alt_bn128_G1::zero() +{ + return G1_zero; +} + +alt_bn128_G1 alt_bn128_G1::one() +{ + return G1_one; +} + +alt_bn128_G1 alt_bn128_G1::random_element() +{ + return (scalar_field::random_element().as_bigint()) * G1_one; +} + +std::ostream& operator<<(std::ostream &out, const alt_bn128_G1 &g) +{ + alt_bn128_G1 copy(g); + copy.to_affine_coordinates(); + + out << (copy.is_zero() ? 1 : 0) << OUTPUT_SEPARATOR; +#ifdef NO_PT_COMPRESSION + out << copy.X << OUTPUT_SEPARATOR << copy.Y; +#else + /* storing LSB of Y */ + out << copy.X << OUTPUT_SEPARATOR << (copy.Y.as_bigint().data[0] & 1); +#endif + + return out; +} + +std::istream& operator>>(std::istream &in, alt_bn128_G1 &g) +{ + char is_zero; + alt_bn128_Fq tX, tY; + +#ifdef NO_PT_COMPRESSION + in >> is_zero >> tX >> tY; + is_zero -= '0'; +#else + in.read((char*)&is_zero, 1); // this reads is_zero; + is_zero -= '0'; + consume_OUTPUT_SEPARATOR(in); + + unsigned char Y_lsb; + in >> tX; + consume_OUTPUT_SEPARATOR(in); + in.read((char*)&Y_lsb, 1); + Y_lsb -= '0'; + + // y = +/- sqrt(x^3 + b) + if (!is_zero) + { + alt_bn128_Fq tX2 = tX.squared(); + alt_bn128_Fq tY2 = tX2*tX + alt_bn128_coeff_b; + tY = tY2.sqrt(); + + if ((tY.as_bigint().data[0] & 1) != Y_lsb) + { + tY = -tY; + } + } +#endif + // using Jacobian coordinates + if (!is_zero) + { + g.X = tX; + g.Y = tY; + g.Z = alt_bn128_Fq::one(); + } + else + { + g = alt_bn128_G1::zero(); + } + + return in; +} + +std::ostream& operator<<(std::ostream& out, const std::vector &v) +{ + out << v.size() << "\n"; + for (const alt_bn128_G1& t : v) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +std::istream& operator>>(std::istream& in, std::vector &v) +{ + v.clear(); + + size_t s; + in >> s; + consume_newline(in); + + v.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + alt_bn128_G1 g; + in >> g; + consume_OUTPUT_NEWLINE(in); + v.emplace_back(g); + } + + return in; +} + +template<> +void batch_to_special_all_non_zeros(std::vector &vec) +{ + std::vector Z_vec; + Z_vec.reserve(vec.size()); + + for (auto &el: vec) + { + Z_vec.emplace_back(el.Z); + } + batch_invert(Z_vec); + + const alt_bn128_Fq one = alt_bn128_Fq::one(); + + for (size_t i = 0; i < vec.size(); ++i) + { + alt_bn128_Fq Z2 = Z_vec[i].squared(); + alt_bn128_Fq Z3 = Z_vec[i] * Z2; + + vec[i].X = vec[i].X * Z2; + vec[i].Y = vec[i].Y * Z3; + vec[i].Z = one; + } +} + +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_g1.d b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_g1.d new file mode 100644 index 0000000..bac3253 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_g1.d @@ -0,0 +1,17 @@ +src/algebra/curves/alt_bn128/alt_bn128_g1.o: \ + src/algebra/curves/alt_bn128/alt_bn128_g1.cpp \ + src/algebra/curves/alt_bn128/alt_bn128_g1.hpp \ + src/algebra/curves/alt_bn128/alt_bn128_init.hpp \ + src/algebra/curves/public_params.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc src/algebra/fields/fp2.hpp \ + src/algebra/fields/fp2.tcc src/algebra/fields/fp6_3over2.hpp \ + src/algebra/fields/fp6_3over2.tcc \ + src/algebra/fields/fp12_2over3over2.hpp \ + src/algebra/fields/fp12_2over3over2.tcc \ + src/algebra/curves/curve_utils.hpp src/algebra/curves/curve_utils.tcc diff --git a/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_g1.hpp b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_g1.hpp new file mode 100644 index 0000000..da11a2e --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_g1.hpp @@ -0,0 +1,95 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALT_BN128_G1_HPP_ +#define ALT_BN128_G1_HPP_ +#include +#include "algebra/curves/alt_bn128/alt_bn128_init.hpp" +#include "algebra/curves/curve_utils.hpp" + +namespace libsnark { + +class alt_bn128_G1; +std::ostream& operator<<(std::ostream &, const alt_bn128_G1&); +std::istream& operator>>(std::istream &, alt_bn128_G1&); + +class alt_bn128_G1 { +public: +#ifdef PROFILE_OP_COUNTS + static long long add_cnt; + static long long dbl_cnt; +#endif + static std::vector wnaf_window_table; + static std::vector fixed_base_exp_window_table; + static alt_bn128_G1 G1_zero; + static alt_bn128_G1 G1_one; + + typedef alt_bn128_Fq base_field; + typedef alt_bn128_Fr scalar_field; + + alt_bn128_Fq X, Y, Z; + + // using Jacobian coordinates + alt_bn128_G1(); + alt_bn128_G1(const alt_bn128_Fq& X, const alt_bn128_Fq& Y, const alt_bn128_Fq& Z) : X(X), Y(Y), Z(Z) {}; + + void print() const; + void print_coordinates() const; + + void to_affine_coordinates(); + void to_special(); + bool is_special() const; + + bool is_zero() const; + + bool operator==(const alt_bn128_G1 &other) const; + bool operator!=(const alt_bn128_G1 &other) const; + + alt_bn128_G1 operator+(const alt_bn128_G1 &other) const; + alt_bn128_G1 operator-() const; + alt_bn128_G1 operator-(const alt_bn128_G1 &other) const; + + alt_bn128_G1 add(const alt_bn128_G1 &other) const; + alt_bn128_G1 mixed_add(const alt_bn128_G1 &other) const; + alt_bn128_G1 dbl() const; + + bool is_well_formed() const; + + static alt_bn128_G1 zero(); + static alt_bn128_G1 one(); + static alt_bn128_G1 random_element(); + + static size_t size_in_bits() { return base_field::size_in_bits() + 1; } + static bigint base_field_char() { return base_field::field_char(); } + static bigint order() { return scalar_field::field_char(); } + + friend std::ostream& operator<<(std::ostream &out, const alt_bn128_G1 &g); + friend std::istream& operator>>(std::istream &in, alt_bn128_G1 &g); +}; + +template +alt_bn128_G1 operator*(const bigint &lhs, const alt_bn128_G1 &rhs) +{ + return scalar_mul(rhs, lhs); +} + +template& modulus_p> +alt_bn128_G1 operator*(const Fp_model &lhs, const alt_bn128_G1 &rhs) +{ + return scalar_mul(rhs, lhs.as_bigint()); +} + +std::ostream& operator<<(std::ostream& out, const std::vector &v); +std::istream& operator>>(std::istream& in, std::vector &v); + +template +void batch_to_special_all_non_zeros(std::vector &vec); +template<> +void batch_to_special_all_non_zeros(std::vector &vec); + +} // libsnark +#endif // ALT_BN128_G1_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_g2.cpp b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_g2.cpp new file mode 100644 index 0000000..c4152e4 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_g2.cpp @@ -0,0 +1,505 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/alt_bn128/alt_bn128_g2.hpp" + +namespace libsnark { + +#ifdef PROFILE_OP_COUNTS +long long alt_bn128_G2::add_cnt = 0; +long long alt_bn128_G2::dbl_cnt = 0; +#endif + +std::vector alt_bn128_G2::wnaf_window_table; +std::vector alt_bn128_G2::fixed_base_exp_window_table; +alt_bn128_G2 alt_bn128_G2::G2_zero; +alt_bn128_G2 alt_bn128_G2::G2_one; + +alt_bn128_G2::alt_bn128_G2() +{ + this->X = G2_zero.X; + this->Y = G2_zero.Y; + this->Z = G2_zero.Z; +} + +alt_bn128_Fq2 alt_bn128_G2::mul_by_b(const alt_bn128_Fq2 &elt) +{ + return alt_bn128_Fq2(alt_bn128_twist_mul_by_b_c0 * elt.c0, alt_bn128_twist_mul_by_b_c1 * elt.c1); +} + +void alt_bn128_G2::print() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + alt_bn128_G2 copy(*this); + copy.to_affine_coordinates(); + gmp_printf("(%Nd*z + %Nd , %Nd*z + %Nd)\n", + copy.X.c1.as_bigint().data, alt_bn128_Fq::num_limbs, + copy.X.c0.as_bigint().data, alt_bn128_Fq::num_limbs, + copy.Y.c1.as_bigint().data, alt_bn128_Fq::num_limbs, + copy.Y.c0.as_bigint().data, alt_bn128_Fq::num_limbs); + } +} + +void alt_bn128_G2::print_coordinates() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + gmp_printf("(%Nd*z + %Nd : %Nd*z + %Nd : %Nd*z + %Nd)\n", + this->X.c1.as_bigint().data, alt_bn128_Fq::num_limbs, + this->X.c0.as_bigint().data, alt_bn128_Fq::num_limbs, + this->Y.c1.as_bigint().data, alt_bn128_Fq::num_limbs, + this->Y.c0.as_bigint().data, alt_bn128_Fq::num_limbs, + this->Z.c1.as_bigint().data, alt_bn128_Fq::num_limbs, + this->Z.c0.as_bigint().data, alt_bn128_Fq::num_limbs); + } +} + +void alt_bn128_G2::to_affine_coordinates() +{ + if (this->is_zero()) + { + this->X = alt_bn128_Fq2::zero(); + this->Y = alt_bn128_Fq2::one(); + this->Z = alt_bn128_Fq2::zero(); + } + else + { + alt_bn128_Fq2 Z_inv = Z.inverse(); + alt_bn128_Fq2 Z2_inv = Z_inv.squared(); + alt_bn128_Fq2 Z3_inv = Z2_inv * Z_inv; + this->X = this->X * Z2_inv; + this->Y = this->Y * Z3_inv; + this->Z = alt_bn128_Fq2::one(); + } +} + +void alt_bn128_G2::to_special() +{ + this->to_affine_coordinates(); +} + +bool alt_bn128_G2::is_special() const +{ + return (this->is_zero() || this->Z == alt_bn128_Fq2::one()); +} + +bool alt_bn128_G2::is_zero() const +{ + return (this->Z.is_zero()); +} + +bool alt_bn128_G2::operator==(const alt_bn128_G2 &other) const +{ + if (this->is_zero()) + { + return other.is_zero(); + } + + if (other.is_zero()) + { + return false; + } + + /* now neither is O */ + + // using Jacobian coordinates so: + // (X1:Y1:Z1) = (X2:Y2:Z2) + // iff + // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 + // iff + // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 + + alt_bn128_Fq2 Z1_squared = (this->Z).squared(); + alt_bn128_Fq2 Z2_squared = (other.Z).squared(); + + if ((this->X * Z2_squared) != (other.X * Z1_squared)) + { + return false; + } + + alt_bn128_Fq2 Z1_cubed = (this->Z) * Z1_squared; + alt_bn128_Fq2 Z2_cubed = (other.Z) * Z2_squared; + + if ((this->Y * Z2_cubed) != (other.Y * Z1_cubed)) + { + return false; + } + + return true; +} + +bool alt_bn128_G2::operator!=(const alt_bn128_G2& other) const +{ + return !(operator==(other)); +} + +alt_bn128_G2 alt_bn128_G2::operator+(const alt_bn128_G2 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // check for doubling case + + // using Jacobian coordinates so: + // (X1:Y1:Z1) = (X2:Y2:Z2) + // iff + // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 + // iff + // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 + + alt_bn128_Fq2 Z1Z1 = (this->Z).squared(); + alt_bn128_Fq2 Z2Z2 = (other.Z).squared(); + + alt_bn128_Fq2 U1 = this->X * Z2Z2; + alt_bn128_Fq2 U2 = other.X * Z1Z1; + + alt_bn128_Fq2 Z1_cubed = (this->Z) * Z1Z1; + alt_bn128_Fq2 Z2_cubed = (other.Z) * Z2Z2; + + alt_bn128_Fq2 S1 = (this->Y) * Z2_cubed; // S1 = Y1 * Z2 * Z2Z2 + alt_bn128_Fq2 S2 = (other.Y) * Z1_cubed; // S2 = Y2 * Z1 * Z1Z1 + + if (U1 == U2 && S1 == S2) + { + // dbl case; nothing of above can be reused + return this->dbl(); + } + + // rest of add case + alt_bn128_Fq2 H = U2 - U1; // H = U2-U1 + alt_bn128_Fq2 S2_minus_S1 = S2-S1; + alt_bn128_Fq2 I = (H+H).squared(); // I = (2 * H)^2 + alt_bn128_Fq2 J = H * I; // J = H * I + alt_bn128_Fq2 r = S2_minus_S1 + S2_minus_S1; // r = 2 * (S2-S1) + alt_bn128_Fq2 V = U1 * I; // V = U1 * I + alt_bn128_Fq2 X3 = r.squared() - J - (V+V); // X3 = r^2 - J - 2 * V + alt_bn128_Fq2 S1_J = S1 * J; + alt_bn128_Fq2 Y3 = r * (V-X3) - (S1_J+S1_J); // Y3 = r * (V-X3)-2 S1 J + alt_bn128_Fq2 Z3 = ((this->Z+other.Z).squared()-Z1Z1-Z2Z2) * H; // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H + + return alt_bn128_G2(X3, Y3, Z3); +} + +alt_bn128_G2 alt_bn128_G2::operator-() const +{ + return alt_bn128_G2(this->X, -(this->Y), this->Z); +} + + +alt_bn128_G2 alt_bn128_G2::operator-(const alt_bn128_G2 &other) const +{ + return (*this) + (-other); +} + +alt_bn128_G2 alt_bn128_G2::add(const alt_bn128_G2 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case + if (this->operator==(other)) + { + return this->dbl(); + } + +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#addition-add-1998-cmo-2 + + alt_bn128_Fq2 Z1Z1 = (this->Z).squared(); // Z1Z1 = Z1^2 + alt_bn128_Fq2 Z2Z2 = (other.Z).squared(); // Z2Z2 = Z2^2 + alt_bn128_Fq2 U1 = (this->X) * Z2Z2; // U1 = X1 * Z2Z2 + alt_bn128_Fq2 U2 = (other.X) * Z1Z1; // U2 = X2 * Z1Z1 + alt_bn128_Fq2 S1 = (this->Y) * (other.Z) * Z2Z2; // S1 = Y1 * Z2 * Z2Z2 + alt_bn128_Fq2 S2 = (other.Y) * (this->Z) * Z1Z1; // S2 = Y2 * Z1 * Z1Z1 + alt_bn128_Fq2 H = U2 - U1; // H = U2-U1 + alt_bn128_Fq2 S2_minus_S1 = S2-S1; + alt_bn128_Fq2 I = (H+H).squared(); // I = (2 * H)^2 + alt_bn128_Fq2 J = H * I; // J = H * I + alt_bn128_Fq2 r = S2_minus_S1 + S2_minus_S1; // r = 2 * (S2-S1) + alt_bn128_Fq2 V = U1 * I; // V = U1 * I + alt_bn128_Fq2 X3 = r.squared() - J - (V+V); // X3 = r^2 - J - 2 * V + alt_bn128_Fq2 S1_J = S1 * J; + alt_bn128_Fq2 Y3 = r * (V-X3) - (S1_J+S1_J); // Y3 = r * (V-X3)-2 S1 J + alt_bn128_Fq2 Z3 = ((this->Z+other.Z).squared()-Z1Z1-Z2Z2) * H; // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H + + return alt_bn128_G2(X3, Y3, Z3); +} + +alt_bn128_G2 alt_bn128_G2::mixed_add(const alt_bn128_G2 &other) const +{ +#ifdef DEBUG + assert(other.is_special()); +#endif + + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // check for doubling case + + // using Jacobian coordinates so: + // (X1:Y1:Z1) = (X2:Y2:Z2) + // iff + // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 + // iff + // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 + + // we know that Z2 = 1 + + const alt_bn128_Fq2 Z1Z1 = (this->Z).squared(); + + const alt_bn128_Fq2 &U1 = this->X; + const alt_bn128_Fq2 U2 = other.X * Z1Z1; + + const alt_bn128_Fq2 Z1_cubed = (this->Z) * Z1Z1; + + const alt_bn128_Fq2 &S1 = (this->Y); // S1 = Y1 * Z2 * Z2Z2 + const alt_bn128_Fq2 S2 = (other.Y) * Z1_cubed; // S2 = Y2 * Z1 * Z1Z1 + + if (U1 == U2 && S1 == S2) + { + // dbl case; nothing of above can be reused + return this->dbl(); + } + +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl + alt_bn128_Fq2 H = U2-(this->X); // H = U2-X1 + alt_bn128_Fq2 HH = H.squared() ; // HH = H&2 + alt_bn128_Fq2 I = HH+HH; // I = 4*HH + I = I + I; + alt_bn128_Fq2 J = H*I; // J = H*I + alt_bn128_Fq2 r = S2-(this->Y); // r = 2*(S2-Y1) + r = r + r; + alt_bn128_Fq2 V = (this->X) * I ; // V = X1*I + alt_bn128_Fq2 X3 = r.squared()-J-V-V; // X3 = r^2-J-2*V + alt_bn128_Fq2 Y3 = (this->Y)*J; // Y3 = r*(V-X3)-2*Y1*J + Y3 = r*(V-X3) - Y3 - Y3; + alt_bn128_Fq2 Z3 = ((this->Z)+H).squared() - Z1Z1 - HH; // Z3 = (Z1+H)^2-Z1Z1-HH + + return alt_bn128_G2(X3, Y3, Z3); +} + +alt_bn128_G2 alt_bn128_G2::dbl() const +{ +#ifdef PROFILE_OP_COUNTS + this->dbl_cnt++; +#endif + // handle point at infinity + if (this->is_zero()) + { + return (*this); + } + + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#doubling-dbl-2007-bl + + alt_bn128_Fq2 A = (this->X).squared(); // A = X1^2 + alt_bn128_Fq2 B = (this->Y).squared(); // B = Y1^2 + alt_bn128_Fq2 C = B.squared(); // C = B^2 + alt_bn128_Fq2 D = (this->X + B).squared() - A - C; + D = D+D; // D = 2 * ((X1 + B)^2 - A - C) + alt_bn128_Fq2 E = A + A + A; // E = 3 * A + alt_bn128_Fq2 F = E.squared(); // F = E^2 + alt_bn128_Fq2 X3 = F - (D+D); // X3 = F - 2 D + alt_bn128_Fq2 eightC = C+C; + eightC = eightC + eightC; + eightC = eightC + eightC; + alt_bn128_Fq2 Y3 = E * (D - X3) - eightC; // Y3 = E * (D - X3) - 8 * C + alt_bn128_Fq2 Y1Z1 = (this->Y)*(this->Z); + alt_bn128_Fq2 Z3 = Y1Z1 + Y1Z1; // Z3 = 2 * Y1 * Z1 + + return alt_bn128_G2(X3, Y3, Z3); +} + +alt_bn128_G2 alt_bn128_G2::mul_by_q() const +{ + return alt_bn128_G2(alt_bn128_twist_mul_by_q_X * (this->X).Frobenius_map(1), + alt_bn128_twist_mul_by_q_Y * (this->Y).Frobenius_map(1), + (this->Z).Frobenius_map(1)); +} + +bool alt_bn128_G2::is_well_formed() const +{ + if (this->is_zero()) + { + return true; + } + else + { + /* + y^2 = x^3 + b + + We are using Jacobian coordinates, so equation we need to check is actually + + (y/z^3)^2 = (x/z^2)^3 + b + y^2 / z^6 = x^3 / z^6 + b + y^2 = x^3 + b z^6 + */ + alt_bn128_Fq2 X2 = this->X.squared(); + alt_bn128_Fq2 Y2 = this->Y.squared(); + alt_bn128_Fq2 Z2 = this->Z.squared(); + + alt_bn128_Fq2 X3 = this->X * X2; + alt_bn128_Fq2 Z3 = this->Z * Z2; + alt_bn128_Fq2 Z6 = Z3.squared(); + + return (Y2 == X3 + alt_bn128_twist_coeff_b * Z6); + } +} + +alt_bn128_G2 alt_bn128_G2::zero() +{ + return G2_zero; +} + +alt_bn128_G2 alt_bn128_G2::one() +{ + return G2_one; +} + +alt_bn128_G2 alt_bn128_G2::random_element() +{ + return (alt_bn128_Fr::random_element().as_bigint()) * G2_one; +} + +std::ostream& operator<<(std::ostream &out, const alt_bn128_G2 &g) +{ + alt_bn128_G2 copy(g); + copy.to_affine_coordinates(); + out << (copy.is_zero() ? 1 : 0) << OUTPUT_SEPARATOR; +#ifdef NO_PT_COMPRESSION + out << copy.X << OUTPUT_SEPARATOR << copy.Y; +#else + /* storing LSB of Y */ + out << copy.X << OUTPUT_SEPARATOR << (copy.Y.c0.as_bigint().data[0] & 1); +#endif + + return out; +} + +std::istream& operator>>(std::istream &in, alt_bn128_G2 &g) +{ + char is_zero; + alt_bn128_Fq2 tX, tY; + +#ifdef NO_PT_COMPRESSION + in >> is_zero >> tX >> tY; + is_zero -= '0'; +#else + in.read((char*)&is_zero, 1); // this reads is_zero; + is_zero -= '0'; + consume_OUTPUT_SEPARATOR(in); + + unsigned char Y_lsb; + in >> tX; + consume_OUTPUT_SEPARATOR(in); + in.read((char*)&Y_lsb, 1); + Y_lsb -= '0'; + + // y = +/- sqrt(x^3 + b) + if (!is_zero) + { + alt_bn128_Fq2 tX2 = tX.squared(); + alt_bn128_Fq2 tY2 = tX2 * tX + alt_bn128_twist_coeff_b; + tY = tY2.sqrt(); + + if ((tY.c0.as_bigint().data[0] & 1) != Y_lsb) + { + tY = -tY; + } + } +#endif + // using projective coordinates + if (!is_zero) + { + g.X = tX; + g.Y = tY; + g.Z = alt_bn128_Fq2::one(); + } + else + { + g = alt_bn128_G2::zero(); + } + + return in; +} + +template<> +void batch_to_special_all_non_zeros(std::vector &vec) +{ + std::vector Z_vec; + Z_vec.reserve(vec.size()); + + for (auto &el: vec) + { + Z_vec.emplace_back(el.Z); + } + batch_invert(Z_vec); + + const alt_bn128_Fq2 one = alt_bn128_Fq2::one(); + + for (size_t i = 0; i < vec.size(); ++i) + { + alt_bn128_Fq2 Z2 = Z_vec[i].squared(); + alt_bn128_Fq2 Z3 = Z_vec[i] * Z2; + + vec[i].X = vec[i].X * Z2; + vec[i].Y = vec[i].Y * Z3; + vec[i].Z = one; + } +} + +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_g2.d b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_g2.d new file mode 100644 index 0000000..e39baf4 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_g2.d @@ -0,0 +1,17 @@ +src/algebra/curves/alt_bn128/alt_bn128_g2.o: \ + src/algebra/curves/alt_bn128/alt_bn128_g2.cpp \ + src/algebra/curves/alt_bn128/alt_bn128_g2.hpp \ + src/algebra/curves/alt_bn128/alt_bn128_init.hpp \ + src/algebra/curves/public_params.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc src/algebra/fields/fp2.hpp \ + src/algebra/fields/fp2.tcc src/algebra/fields/fp6_3over2.hpp \ + src/algebra/fields/fp6_3over2.tcc \ + src/algebra/fields/fp12_2over3over2.hpp \ + src/algebra/fields/fp12_2over3over2.tcc \ + src/algebra/curves/curve_utils.hpp src/algebra/curves/curve_utils.tcc diff --git a/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_g2.hpp b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_g2.hpp new file mode 100644 index 0000000..a996a2d --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_g2.hpp @@ -0,0 +1,96 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALT_BN128_G2_HPP_ +#define ALT_BN128_G2_HPP_ +#include +#include "algebra/curves/alt_bn128/alt_bn128_init.hpp" +#include "algebra/curves/curve_utils.hpp" + +namespace libsnark { + +class alt_bn128_G2; +std::ostream& operator<<(std::ostream &, const alt_bn128_G2&); +std::istream& operator>>(std::istream &, alt_bn128_G2&); + +class alt_bn128_G2 { +public: +#ifdef PROFILE_OP_COUNTS + static long long add_cnt; + static long long dbl_cnt; +#endif + static std::vector wnaf_window_table; + static std::vector fixed_base_exp_window_table; + static alt_bn128_G2 G2_zero; + static alt_bn128_G2 G2_one; + + typedef alt_bn128_Fq base_field; + typedef alt_bn128_Fq2 twist_field; + typedef alt_bn128_Fr scalar_field; + + alt_bn128_Fq2 X, Y, Z; + + // using Jacobian coordinates + alt_bn128_G2(); + alt_bn128_G2(const alt_bn128_Fq2& X, const alt_bn128_Fq2& Y, const alt_bn128_Fq2& Z) : X(X), Y(Y), Z(Z) {}; + + static alt_bn128_Fq2 mul_by_b(const alt_bn128_Fq2 &elt); + + void print() const; + void print_coordinates() const; + + void to_affine_coordinates(); + void to_special(); + bool is_special() const; + + bool is_zero() const; + + bool operator==(const alt_bn128_G2 &other) const; + bool operator!=(const alt_bn128_G2 &other) const; + + alt_bn128_G2 operator+(const alt_bn128_G2 &other) const; + alt_bn128_G2 operator-() const; + alt_bn128_G2 operator-(const alt_bn128_G2 &other) const; + + alt_bn128_G2 add(const alt_bn128_G2 &other) const; + alt_bn128_G2 mixed_add(const alt_bn128_G2 &other) const; + alt_bn128_G2 dbl() const; + alt_bn128_G2 mul_by_q() const; + + bool is_well_formed() const; + + static alt_bn128_G2 zero(); + static alt_bn128_G2 one(); + static alt_bn128_G2 random_element(); + + static size_t size_in_bits() { return twist_field::size_in_bits() + 1; } + static bigint base_field_char() { return base_field::field_char(); } + static bigint order() { return scalar_field::field_char(); } + + friend std::ostream& operator<<(std::ostream &out, const alt_bn128_G2 &g); + friend std::istream& operator>>(std::istream &in, alt_bn128_G2 &g); +}; + +template +alt_bn128_G2 operator*(const bigint &lhs, const alt_bn128_G2 &rhs) +{ + return scalar_mul(rhs, lhs); +} + +template& modulus_p> +alt_bn128_G2 operator*(const Fp_model &lhs, const alt_bn128_G2 &rhs) +{ + return scalar_mul(rhs, lhs.as_bigint()); +} + +template +void batch_to_special_all_non_zeros(std::vector &vec); +template<> +void batch_to_special_all_non_zeros(std::vector &vec); + +} // libsnark +#endif // ALT_BN128_G2_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_init.cpp b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_init.cpp new file mode 100644 index 0000000..7c23773 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_init.cpp @@ -0,0 +1,273 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/alt_bn128/alt_bn128_init.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_g1.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_g2.hpp" + +namespace libsnark { + +bigint alt_bn128_modulus_r; +bigint alt_bn128_modulus_q; + +alt_bn128_Fq alt_bn128_coeff_b; +alt_bn128_Fq2 alt_bn128_twist; +alt_bn128_Fq2 alt_bn128_twist_coeff_b; +alt_bn128_Fq alt_bn128_twist_mul_by_b_c0; +alt_bn128_Fq alt_bn128_twist_mul_by_b_c1; +alt_bn128_Fq2 alt_bn128_twist_mul_by_q_X; +alt_bn128_Fq2 alt_bn128_twist_mul_by_q_Y; + +bigint alt_bn128_ate_loop_count; +bool alt_bn128_ate_is_loop_count_neg; +bigint<12*alt_bn128_q_limbs> alt_bn128_final_exponent; +bigint alt_bn128_final_exponent_z; +bool alt_bn128_final_exponent_is_z_neg; + +void init_alt_bn128_params() +{ + typedef bigint bigint_r; + typedef bigint bigint_q; + + assert(sizeof(mp_limb_t) == 8 || sizeof(mp_limb_t) == 4); // Montgomery assumes this + + /* parameters for scalar field Fr */ + + alt_bn128_modulus_r = bigint_r("21888242871839275222246405745257275088548364400416034343698204186575808495617"); + assert(alt_bn128_Fr::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + alt_bn128_Fr::Rsquared = bigint_r("944936681149208446651664254269745548490766851729442924617792859073125903783"); + alt_bn128_Fr::Rcubed = bigint_r("5866548545943845227489894872040244720403868105578784105281690076696998248512"); + alt_bn128_Fr::inv = 0xc2e1f593efffffff; + } + if (sizeof(mp_limb_t) == 4) + { + alt_bn128_Fr::Rsquared = bigint_r("944936681149208446651664254269745548490766851729442924617792859073125903783"); + alt_bn128_Fr::Rcubed = bigint_r("5866548545943845227489894872040244720403868105578784105281690076696998248512"); + alt_bn128_Fr::inv = 0xefffffff; + } + alt_bn128_Fr::num_bits = 254; + alt_bn128_Fr::euler = bigint_r("10944121435919637611123202872628637544274182200208017171849102093287904247808"); + alt_bn128_Fr::s = 28; + alt_bn128_Fr::t = bigint_r("81540058820840996586704275553141814055101440848469862132140264610111"); + alt_bn128_Fr::t_minus_1_over_2 = bigint_r("40770029410420498293352137776570907027550720424234931066070132305055"); + alt_bn128_Fr::multiplicative_generator = alt_bn128_Fr("5"); + alt_bn128_Fr::root_of_unity = alt_bn128_Fr("19103219067921713944291392827692070036145651957329286315305642004821462161904"); + alt_bn128_Fr::nqr = alt_bn128_Fr("5"); + alt_bn128_Fr::nqr_to_t = alt_bn128_Fr("19103219067921713944291392827692070036145651957329286315305642004821462161904"); + + /* parameters for base field Fq */ + + alt_bn128_modulus_q = bigint_q("21888242871839275222246405745257275088696311157297823662689037894645226208583"); + assert(alt_bn128_Fq::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + alt_bn128_Fq::Rsquared = bigint_q("3096616502983703923843567936837374451735540968419076528771170197431451843209"); + alt_bn128_Fq::Rcubed = bigint_q("14921786541159648185948152738563080959093619838510245177710943249661917737183"); + alt_bn128_Fq::inv = 0x87d20782e4866389; + } + if (sizeof(mp_limb_t) == 4) + { + alt_bn128_Fq::Rsquared = bigint_q("3096616502983703923843567936837374451735540968419076528771170197431451843209"); + alt_bn128_Fq::Rcubed = bigint_q("14921786541159648185948152738563080959093619838510245177710943249661917737183"); + alt_bn128_Fq::inv = 0xe4866389; + } + alt_bn128_Fq::num_bits = 254; + alt_bn128_Fq::euler = bigint_q("10944121435919637611123202872628637544348155578648911831344518947322613104291"); + alt_bn128_Fq::s = 1; + alt_bn128_Fq::t = bigint_q("10944121435919637611123202872628637544348155578648911831344518947322613104291"); + alt_bn128_Fq::t_minus_1_over_2 = bigint_q("5472060717959818805561601436314318772174077789324455915672259473661306552145"); + alt_bn128_Fq::multiplicative_generator = alt_bn128_Fq("3"); + alt_bn128_Fq::root_of_unity = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + alt_bn128_Fq::nqr = alt_bn128_Fq("3"); + alt_bn128_Fq::nqr_to_t = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + + /* parameters for twist field Fq2 */ + alt_bn128_Fq2::euler = bigint<2*alt_bn128_q_limbs>("239547588008311421220994022608339370399626158265550411218223901127035046843189118723920525909718935985594116157406550130918127817069793474323196511433944"); + alt_bn128_Fq2::s = 4; + alt_bn128_Fq2::t = bigint<2*alt_bn128_q_limbs>("29943448501038927652624252826042421299953269783193801402277987640879380855398639840490065738714866998199264519675818766364765977133724184290399563929243"); + alt_bn128_Fq2::t_minus_1_over_2 = bigint<2*alt_bn128_q_limbs>("14971724250519463826312126413021210649976634891596900701138993820439690427699319920245032869357433499099632259837909383182382988566862092145199781964621"); + alt_bn128_Fq2::non_residue = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + alt_bn128_Fq2::nqr = alt_bn128_Fq2(alt_bn128_Fq("2"),alt_bn128_Fq("1")); + alt_bn128_Fq2::nqr_to_t = alt_bn128_Fq2(alt_bn128_Fq("5033503716262624267312492558379982687175200734934877598599011485707452665730"),alt_bn128_Fq("314498342015008975724433667930697407966947188435857772134235984660852259084")); + alt_bn128_Fq2::Frobenius_coeffs_c1[0] = alt_bn128_Fq("1"); + alt_bn128_Fq2::Frobenius_coeffs_c1[1] = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + + /* parameters for Fq6 */ + alt_bn128_Fq6::non_residue = alt_bn128_Fq2(alt_bn128_Fq("9"),alt_bn128_Fq("1")); + alt_bn128_Fq6::Frobenius_coeffs_c1[0] = alt_bn128_Fq2(alt_bn128_Fq("1"),alt_bn128_Fq("0")); + alt_bn128_Fq6::Frobenius_coeffs_c1[1] = alt_bn128_Fq2(alt_bn128_Fq("21575463638280843010398324269430826099269044274347216827212613867836435027261"),alt_bn128_Fq("10307601595873709700152284273816112264069230130616436755625194854815875713954")); + alt_bn128_Fq6::Frobenius_coeffs_c1[2] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556616"),alt_bn128_Fq("0")); + alt_bn128_Fq6::Frobenius_coeffs_c1[3] = alt_bn128_Fq2(alt_bn128_Fq("3772000881919853776433695186713858239009073593817195771773381919316419345261"),alt_bn128_Fq("2236595495967245188281701248203181795121068902605861227855261137820944008926")); + alt_bn128_Fq6::Frobenius_coeffs_c1[4] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651966"),alt_bn128_Fq("0")); + alt_bn128_Fq6::Frobenius_coeffs_c1[5] = alt_bn128_Fq2(alt_bn128_Fq("18429021223477853657660792034369865839114504446431234726392080002137598044644"),alt_bn128_Fq("9344045779998320333812420223237981029506012124075525679208581902008406485703")); + alt_bn128_Fq6::Frobenius_coeffs_c2[0] = alt_bn128_Fq2(alt_bn128_Fq("1"),alt_bn128_Fq("0")); + alt_bn128_Fq6::Frobenius_coeffs_c2[1] = alt_bn128_Fq2(alt_bn128_Fq("2581911344467009335267311115468803099551665605076196740867805258568234346338"),alt_bn128_Fq("19937756971775647987995932169929341994314640652964949448313374472400716661030")); + alt_bn128_Fq6::Frobenius_coeffs_c2[2] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651966"),alt_bn128_Fq("0")); + alt_bn128_Fq6::Frobenius_coeffs_c2[3] = alt_bn128_Fq2(alt_bn128_Fq("5324479202449903542726783395506214481928257762400643279780343368557297135718"),alt_bn128_Fq("16208900380737693084919495127334387981393726419856888799917914180988844123039")); + alt_bn128_Fq6::Frobenius_coeffs_c2[4] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556616"),alt_bn128_Fq("0")); + alt_bn128_Fq6::Frobenius_coeffs_c2[5] = alt_bn128_Fq2(alt_bn128_Fq("13981852324922362344252311234282257507216387789820983642040889267519694726527"),alt_bn128_Fq("7629828391165209371577384193250820201684255241773809077146787135900891633097")); + + /* parameters for Fq12 */ + + alt_bn128_Fq12::non_residue = alt_bn128_Fq2(alt_bn128_Fq("9"),alt_bn128_Fq("1")); + alt_bn128_Fq12::Frobenius_coeffs_c1[0] = alt_bn128_Fq2(alt_bn128_Fq("1"),alt_bn128_Fq("0")); + alt_bn128_Fq12::Frobenius_coeffs_c1[1] = alt_bn128_Fq2(alt_bn128_Fq("8376118865763821496583973867626364092589906065868298776909617916018768340080"),alt_bn128_Fq("16469823323077808223889137241176536799009286646108169935659301613961712198316")); + alt_bn128_Fq12::Frobenius_coeffs_c1[2] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556617"),alt_bn128_Fq("0")); + alt_bn128_Fq12::Frobenius_coeffs_c1[3] = alt_bn128_Fq2(alt_bn128_Fq("11697423496358154304825782922584725312912383441159505038794027105778954184319"),alt_bn128_Fq("303847389135065887422783454877609941456349188919719272345083954437860409601")); + alt_bn128_Fq12::Frobenius_coeffs_c1[4] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556616"),alt_bn128_Fq("0")); + alt_bn128_Fq12::Frobenius_coeffs_c1[5] = alt_bn128_Fq2(alt_bn128_Fq("3321304630594332808241809054958361220322477375291206261884409189760185844239"),alt_bn128_Fq("5722266937896532885780051958958348231143373700109372999374820235121374419868")); + alt_bn128_Fq12::Frobenius_coeffs_c1[6] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"),alt_bn128_Fq("0")); + alt_bn128_Fq12::Frobenius_coeffs_c1[7] = alt_bn128_Fq2(alt_bn128_Fq("13512124006075453725662431877630910996106405091429524885779419978626457868503"),alt_bn128_Fq("5418419548761466998357268504080738289687024511189653727029736280683514010267")); + alt_bn128_Fq12::Frobenius_coeffs_c1[8] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651966"),alt_bn128_Fq("0")); + alt_bn128_Fq12::Frobenius_coeffs_c1[9] = alt_bn128_Fq2(alt_bn128_Fq("10190819375481120917420622822672549775783927716138318623895010788866272024264"),alt_bn128_Fq("21584395482704209334823622290379665147239961968378104390343953940207365798982")); + alt_bn128_Fq12::Frobenius_coeffs_c1[10] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651967"),alt_bn128_Fq("0")); + alt_bn128_Fq12::Frobenius_coeffs_c1[11] = alt_bn128_Fq2(alt_bn128_Fq("18566938241244942414004596690298913868373833782006617400804628704885040364344"),alt_bn128_Fq("16165975933942742336466353786298926857552937457188450663314217659523851788715")); + + /* choice of short Weierstrass curve and its twist */ + + alt_bn128_coeff_b = alt_bn128_Fq("3"); + alt_bn128_twist = alt_bn128_Fq2(alt_bn128_Fq("9"), alt_bn128_Fq("1")); + alt_bn128_twist_coeff_b = alt_bn128_coeff_b * alt_bn128_twist.inverse(); + alt_bn128_twist_mul_by_b_c0 = alt_bn128_coeff_b * alt_bn128_Fq2::non_residue; + alt_bn128_twist_mul_by_b_c1 = alt_bn128_coeff_b * alt_bn128_Fq2::non_residue; + alt_bn128_twist_mul_by_q_X = alt_bn128_Fq2(alt_bn128_Fq("21575463638280843010398324269430826099269044274347216827212613867836435027261"), + alt_bn128_Fq("10307601595873709700152284273816112264069230130616436755625194854815875713954")); + alt_bn128_twist_mul_by_q_Y = alt_bn128_Fq2(alt_bn128_Fq("2821565182194536844548159561693502659359617185244120367078079554186484126554"), + alt_bn128_Fq("3505843767911556378687030309984248845540243509899259641013678093033130930403")); + + /* choice of group G1 */ + alt_bn128_G1::G1_zero = alt_bn128_G1(alt_bn128_Fq::zero(), + alt_bn128_Fq::one(), + alt_bn128_Fq::zero()); + alt_bn128_G1::G1_one = alt_bn128_G1(alt_bn128_Fq("1"), + alt_bn128_Fq("2"), + alt_bn128_Fq::one()); + alt_bn128_G1::wnaf_window_table.push_back(11); + alt_bn128_G1::wnaf_window_table.push_back(24); + alt_bn128_G1::wnaf_window_table.push_back(60); + alt_bn128_G1::wnaf_window_table.push_back(127); + + alt_bn128_G1::fixed_base_exp_window_table.resize(0); + // window 1 is unbeaten in [-inf, 4.99] + alt_bn128_G1::fixed_base_exp_window_table.push_back(1); + // window 2 is unbeaten in [4.99, 10.99] + alt_bn128_G1::fixed_base_exp_window_table.push_back(5); + // window 3 is unbeaten in [10.99, 32.29] + alt_bn128_G1::fixed_base_exp_window_table.push_back(11); + // window 4 is unbeaten in [32.29, 55.23] + alt_bn128_G1::fixed_base_exp_window_table.push_back(32); + // window 5 is unbeaten in [55.23, 162.03] + alt_bn128_G1::fixed_base_exp_window_table.push_back(55); + // window 6 is unbeaten in [162.03, 360.15] + alt_bn128_G1::fixed_base_exp_window_table.push_back(162); + // window 7 is unbeaten in [360.15, 815.44] + alt_bn128_G1::fixed_base_exp_window_table.push_back(360); + // window 8 is unbeaten in [815.44, 2373.07] + alt_bn128_G1::fixed_base_exp_window_table.push_back(815); + // window 9 is unbeaten in [2373.07, 6977.75] + alt_bn128_G1::fixed_base_exp_window_table.push_back(2373); + // window 10 is unbeaten in [6977.75, 7122.23] + alt_bn128_G1::fixed_base_exp_window_table.push_back(6978); + // window 11 is unbeaten in [7122.23, 57818.46] + alt_bn128_G1::fixed_base_exp_window_table.push_back(7122); + // window 12 is never the best + alt_bn128_G1::fixed_base_exp_window_table.push_back(0); + // window 13 is unbeaten in [57818.46, 169679.14] + alt_bn128_G1::fixed_base_exp_window_table.push_back(57818); + // window 14 is never the best + alt_bn128_G1::fixed_base_exp_window_table.push_back(0); + // window 15 is unbeaten in [169679.14, 439758.91] + alt_bn128_G1::fixed_base_exp_window_table.push_back(169679); + // window 16 is unbeaten in [439758.91, 936073.41] + alt_bn128_G1::fixed_base_exp_window_table.push_back(439759); + // window 17 is unbeaten in [936073.41, 4666554.74] + alt_bn128_G1::fixed_base_exp_window_table.push_back(936073); + // window 18 is never the best + alt_bn128_G1::fixed_base_exp_window_table.push_back(0); + // window 19 is unbeaten in [4666554.74, 7580404.42] + alt_bn128_G1::fixed_base_exp_window_table.push_back(4666555); + // window 20 is unbeaten in [7580404.42, 34552892.20] + alt_bn128_G1::fixed_base_exp_window_table.push_back(7580404); + // window 21 is never the best + alt_bn128_G1::fixed_base_exp_window_table.push_back(0); + // window 22 is unbeaten in [34552892.20, inf] + alt_bn128_G1::fixed_base_exp_window_table.push_back(34552892); + + /* choice of group G2 */ + + alt_bn128_G2::G2_zero = alt_bn128_G2(alt_bn128_Fq2::zero(), + alt_bn128_Fq2::one(), + alt_bn128_Fq2::zero()); + + alt_bn128_G2::G2_one = alt_bn128_G2(alt_bn128_Fq2(alt_bn128_Fq("10857046999023057135944570762232829481370756359578518086990519993285655852781"), + alt_bn128_Fq("11559732032986387107991004021392285783925812861821192530917403151452391805634")), + alt_bn128_Fq2(alt_bn128_Fq("8495653923123431417604973247489272438418190587263600148770280649306958101930"), + alt_bn128_Fq("4082367875863433681332203403145435568316851327593401208105741076214120093531")), + alt_bn128_Fq2::one()); + alt_bn128_G2::wnaf_window_table.push_back(5); + alt_bn128_G2::wnaf_window_table.push_back(15); + alt_bn128_G2::wnaf_window_table.push_back(39); + alt_bn128_G2::wnaf_window_table.push_back(109); + + alt_bn128_G2::fixed_base_exp_window_table.resize(0); + // window 1 is unbeaten in [-inf, 5.10] + alt_bn128_G2::fixed_base_exp_window_table.push_back(1); + // window 2 is unbeaten in [5.10, 10.43] + alt_bn128_G2::fixed_base_exp_window_table.push_back(5); + // window 3 is unbeaten in [10.43, 25.28] + alt_bn128_G2::fixed_base_exp_window_table.push_back(10); + // window 4 is unbeaten in [25.28, 59.00] + alt_bn128_G2::fixed_base_exp_window_table.push_back(25); + // window 5 is unbeaten in [59.00, 154.03] + alt_bn128_G2::fixed_base_exp_window_table.push_back(59); + // window 6 is unbeaten in [154.03, 334.25] + alt_bn128_G2::fixed_base_exp_window_table.push_back(154); + // window 7 is unbeaten in [334.25, 742.58] + alt_bn128_G2::fixed_base_exp_window_table.push_back(334); + // window 8 is unbeaten in [742.58, 2034.40] + alt_bn128_G2::fixed_base_exp_window_table.push_back(743); + // window 9 is unbeaten in [2034.40, 4987.56] + alt_bn128_G2::fixed_base_exp_window_table.push_back(2034); + // window 10 is unbeaten in [4987.56, 8888.27] + alt_bn128_G2::fixed_base_exp_window_table.push_back(4988); + // window 11 is unbeaten in [8888.27, 26271.13] + alt_bn128_G2::fixed_base_exp_window_table.push_back(8888); + // window 12 is unbeaten in [26271.13, 39768.20] + alt_bn128_G2::fixed_base_exp_window_table.push_back(26271); + // window 13 is unbeaten in [39768.20, 106275.75] + alt_bn128_G2::fixed_base_exp_window_table.push_back(39768); + // window 14 is unbeaten in [106275.75, 141703.40] + alt_bn128_G2::fixed_base_exp_window_table.push_back(106276); + // window 15 is unbeaten in [141703.40, 462422.97] + alt_bn128_G2::fixed_base_exp_window_table.push_back(141703); + // window 16 is unbeaten in [462422.97, 926871.84] + alt_bn128_G2::fixed_base_exp_window_table.push_back(462423); + // window 17 is unbeaten in [926871.84, 4873049.17] + alt_bn128_G2::fixed_base_exp_window_table.push_back(926872); + // window 18 is never the best + alt_bn128_G2::fixed_base_exp_window_table.push_back(0); + // window 19 is unbeaten in [4873049.17, 5706707.88] + alt_bn128_G2::fixed_base_exp_window_table.push_back(4873049); + // window 20 is unbeaten in [5706707.88, 31673814.95] + alt_bn128_G2::fixed_base_exp_window_table.push_back(5706708); + // window 21 is never the best + alt_bn128_G2::fixed_base_exp_window_table.push_back(0); + // window 22 is unbeaten in [31673814.95, inf] + alt_bn128_G2::fixed_base_exp_window_table.push_back(31673815); + + /* pairing parameters */ + + alt_bn128_ate_loop_count = bigint_q("29793968203157093288"); + alt_bn128_ate_is_loop_count_neg = false; + alt_bn128_final_exponent = bigint<12*alt_bn128_q_limbs>("552484233613224096312617126783173147097382103762957654188882734314196910839907541213974502761540629817009608548654680343627701153829446747810907373256841551006201639677726139946029199968412598804882391702273019083653272047566316584365559776493027495458238373902875937659943504873220554161550525926302303331747463515644711876653177129578303191095900909191624817826566688241804408081892785725967931714097716709526092261278071952560171111444072049229123565057483750161460024353346284167282452756217662335528813519139808291170539072125381230815729071544861602750936964829313608137325426383735122175229541155376346436093930287402089517426973178917569713384748081827255472576937471496195752727188261435633271238710131736096299798168852925540549342330775279877006784354801422249722573783561685179618816480037695005515426162362431072245638324744480"); + alt_bn128_final_exponent_z = bigint_q("4965661367192848881"); + alt_bn128_final_exponent_is_z_neg = false; + +} +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_init.d b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_init.d new file mode 100644 index 0000000..962318e --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_init.d @@ -0,0 +1,18 @@ +src/algebra/curves/alt_bn128/alt_bn128_init.o: \ + src/algebra/curves/alt_bn128/alt_bn128_init.cpp \ + src/algebra/curves/alt_bn128/alt_bn128_init.hpp \ + src/algebra/curves/public_params.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc src/algebra/fields/fp2.hpp \ + src/algebra/fields/fp2.tcc src/algebra/fields/fp6_3over2.hpp \ + src/algebra/fields/fp6_3over2.tcc \ + src/algebra/fields/fp12_2over3over2.hpp \ + src/algebra/fields/fp12_2over3over2.tcc \ + src/algebra/curves/alt_bn128/alt_bn128_g1.hpp \ + src/algebra/curves/curve_utils.hpp src/algebra/curves/curve_utils.tcc \ + src/algebra/curves/alt_bn128/alt_bn128_g2.hpp diff --git a/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_init.hpp b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_init.hpp new file mode 100644 index 0000000..c3bea76 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_init.hpp @@ -0,0 +1,57 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALT_BN128_INIT_HPP_ +#define ALT_BN128_INIT_HPP_ +#include "algebra/curves/public_params.hpp" +#include "algebra/fields/fp.hpp" +#include "algebra/fields/fp2.hpp" +#include "algebra/fields/fp6_3over2.hpp" +#include "algebra/fields/fp12_2over3over2.hpp" + +namespace libsnark { + +const mp_size_t alt_bn128_r_bitcount = 254; +const mp_size_t alt_bn128_q_bitcount = 254; + +const mp_size_t alt_bn128_r_limbs = (alt_bn128_r_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; +const mp_size_t alt_bn128_q_limbs = (alt_bn128_q_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; + +extern bigint alt_bn128_modulus_r; +extern bigint alt_bn128_modulus_q; + +typedef Fp_model alt_bn128_Fr; +typedef Fp_model alt_bn128_Fq; +typedef Fp2_model alt_bn128_Fq2; +typedef Fp6_3over2_model alt_bn128_Fq6; +typedef Fp12_2over3over2_model alt_bn128_Fq12; +typedef alt_bn128_Fq12 alt_bn128_GT; + +// parameters for Barreto--Naehrig curve E/Fq : y^2 = x^3 + b +extern alt_bn128_Fq alt_bn128_coeff_b; +// parameters for twisted Barreto--Naehrig curve E'/Fq2 : y^2 = x^3 + b/xi +extern alt_bn128_Fq2 alt_bn128_twist; +extern alt_bn128_Fq2 alt_bn128_twist_coeff_b; +extern alt_bn128_Fq alt_bn128_twist_mul_by_b_c0; +extern alt_bn128_Fq alt_bn128_twist_mul_by_b_c1; +extern alt_bn128_Fq2 alt_bn128_twist_mul_by_q_X; +extern alt_bn128_Fq2 alt_bn128_twist_mul_by_q_Y; + +// parameters for pairing +extern bigint alt_bn128_ate_loop_count; +extern bool alt_bn128_ate_is_loop_count_neg; +extern bigint<12*alt_bn128_q_limbs> alt_bn128_final_exponent; +extern bigint alt_bn128_final_exponent_z; +extern bool alt_bn128_final_exponent_is_z_neg; + +void init_alt_bn128_params(); + +class alt_bn128_G1; +class alt_bn128_G2; + +} // libsnark +#endif // ALT_BN128_INIT_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_pairing.cpp b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_pairing.cpp new file mode 100644 index 0000000..3eb5aa1 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_pairing.cpp @@ -0,0 +1,546 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/alt_bn128/alt_bn128_pairing.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_init.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_g1.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_g2.hpp" +#include +#include "common/profiling.hpp" + +namespace libsnark { + +bool alt_bn128_ate_G1_precomp::operator==(const alt_bn128_ate_G1_precomp &other) const +{ + return (this->PX == other.PX && + this->PY == other.PY); +} + +std::ostream& operator<<(std::ostream &out, const alt_bn128_ate_G1_precomp &prec_P) +{ + out << prec_P.PX << OUTPUT_SEPARATOR << prec_P.PY; + + return out; +} + +std::istream& operator>>(std::istream &in, alt_bn128_ate_G1_precomp &prec_P) +{ + in >> prec_P.PX; + consume_OUTPUT_SEPARATOR(in); + in >> prec_P.PY; + + return in; +} + +bool alt_bn128_ate_ell_coeffs::operator==(const alt_bn128_ate_ell_coeffs &other) const +{ + return (this->ell_0 == other.ell_0 && + this->ell_VW == other.ell_VW && + this->ell_VV == other.ell_VV); +} + +std::ostream& operator<<(std::ostream &out, const alt_bn128_ate_ell_coeffs &c) +{ + out << c.ell_0 << OUTPUT_SEPARATOR << c.ell_VW << OUTPUT_SEPARATOR << c.ell_VV; + return out; +} + +std::istream& operator>>(std::istream &in, alt_bn128_ate_ell_coeffs &c) +{ + in >> c.ell_0; + consume_OUTPUT_SEPARATOR(in); + in >> c.ell_VW; + consume_OUTPUT_SEPARATOR(in); + in >> c.ell_VV; + + return in; +} + +bool alt_bn128_ate_G2_precomp::operator==(const alt_bn128_ate_G2_precomp &other) const +{ + return (this->QX == other.QX && + this->QY == other.QY && + this->coeffs == other.coeffs); +} + +std::ostream& operator<<(std::ostream& out, const alt_bn128_ate_G2_precomp &prec_Q) +{ + out << prec_Q.QX << OUTPUT_SEPARATOR << prec_Q.QY << "\n"; + out << prec_Q.coeffs.size() << "\n"; + for (const alt_bn128_ate_ell_coeffs &c : prec_Q.coeffs) + { + out << c << OUTPUT_NEWLINE; + } + return out; +} + +std::istream& operator>>(std::istream& in, alt_bn128_ate_G2_precomp &prec_Q) +{ + in >> prec_Q.QX; + consume_OUTPUT_SEPARATOR(in); + in >> prec_Q.QY; + consume_newline(in); + + prec_Q.coeffs.clear(); + size_t s; + in >> s; + + consume_newline(in); + + prec_Q.coeffs.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + alt_bn128_ate_ell_coeffs c; + in >> c; + consume_OUTPUT_NEWLINE(in); + prec_Q.coeffs.emplace_back(c); + } + + return in; +} + +/* final exponentiations */ + +alt_bn128_Fq12 alt_bn128_final_exponentiation_first_chunk(const alt_bn128_Fq12 &elt) +{ + enter_block("Call to alt_bn128_final_exponentiation_first_chunk"); + + /* + Computes result = elt^((q^6-1)*(q^2+1)). + Follows, e.g., Beuchat et al page 9, by computing result as follows: + elt^((q^6-1)*(q^2+1)) = (conj(elt) * elt^(-1))^(q^2+1) + More precisely: + A = conj(elt) + B = elt.inverse() + C = A * B + D = C.Frobenius_map(2) + result = D * C + */ + + const alt_bn128_Fq12 A = alt_bn128_Fq12(elt.c0,-elt.c1); + const alt_bn128_Fq12 B = elt.inverse(); + const alt_bn128_Fq12 C = A * B; + const alt_bn128_Fq12 D = C.Frobenius_map(2); + const alt_bn128_Fq12 result = D * C; + + leave_block("Call to alt_bn128_final_exponentiation_first_chunk"); + + return result; +} + +alt_bn128_Fq12 alt_bn128_exp_by_neg_z(const alt_bn128_Fq12 &elt) +{ + enter_block("Call to alt_bn128_exp_by_neg_z"); + + alt_bn128_Fq12 result = elt.cyclotomic_exp(alt_bn128_final_exponent_z); + if (!alt_bn128_final_exponent_is_z_neg) + { + result = result.unitary_inverse(); + } + + leave_block("Call to alt_bn128_exp_by_neg_z"); + + return result; +} + +alt_bn128_Fq12 alt_bn128_final_exponentiation_last_chunk(const alt_bn128_Fq12 &elt) +{ + enter_block("Call to alt_bn128_final_exponentiation_last_chunk"); + + /* + Follows Laura Fuentes-Castaneda et al. "Faster hashing to G2" + by computing: + + result = elt^(q^3 * (12*z^3 + 6z^2 + 4z - 1) + + q^2 * (12*z^3 + 6z^2 + 6z) + + q * (12*z^3 + 6z^2 + 4z) + + 1 * (12*z^3 + 12z^2 + 6z + 1)) + which equals + + result = elt^( 2z * ( 6z^2 + 3z + 1 ) * (q^4 - q^2 + 1)/r ). + + Using the following addition chain: + + A = exp_by_neg_z(elt) // = elt^(-z) + B = A^2 // = elt^(-2*z) + C = B^2 // = elt^(-4*z) + D = C * B // = elt^(-6*z) + E = exp_by_neg_z(D) // = elt^(6*z^2) + F = E^2 // = elt^(12*z^2) + G = epx_by_neg_z(F) // = elt^(-12*z^3) + H = conj(D) // = elt^(6*z) + I = conj(G) // = elt^(12*z^3) + J = I * E // = elt^(12*z^3 + 6*z^2) + K = J * H // = elt^(12*z^3 + 6*z^2 + 6*z) + L = K * B // = elt^(12*z^3 + 6*z^2 + 4*z) + M = K * E // = elt^(12*z^3 + 12*z^2 + 6*z) + N = M * elt // = elt^(12*z^3 + 12*z^2 + 6*z + 1) + O = L.Frobenius_map(1) // = elt^(q*(12*z^3 + 6*z^2 + 4*z)) + P = O * N // = elt^(q*(12*z^3 + 6*z^2 + 4*z) * (12*z^3 + 12*z^2 + 6*z + 1)) + Q = K.Frobenius_map(2) // = elt^(q^2 * (12*z^3 + 6*z^2 + 6*z)) + R = Q * P // = elt^(q^2 * (12*z^3 + 6*z^2 + 6*z) + q*(12*z^3 + 6*z^2 + 4*z) * (12*z^3 + 12*z^2 + 6*z + 1)) + S = conj(elt) // = elt^(-1) + T = S * L // = elt^(12*z^3 + 6*z^2 + 4*z - 1) + U = T.Frobenius_map(3) // = elt^(q^3(12*z^3 + 6*z^2 + 4*z - 1)) + V = U * R // = elt^(q^3(12*z^3 + 6*z^2 + 4*z - 1) + q^2 * (12*z^3 + 6*z^2 + 6*z) + q*(12*z^3 + 6*z^2 + 4*z) * (12*z^3 + 12*z^2 + 6*z + 1)) + result = V + + */ + + const alt_bn128_Fq12 A = alt_bn128_exp_by_neg_z(elt); + const alt_bn128_Fq12 B = A.cyclotomic_squared(); + const alt_bn128_Fq12 C = B.cyclotomic_squared(); + const alt_bn128_Fq12 D = C * B; + const alt_bn128_Fq12 E = alt_bn128_exp_by_neg_z(D); + const alt_bn128_Fq12 F = E.cyclotomic_squared(); + const alt_bn128_Fq12 G = alt_bn128_exp_by_neg_z(F); + const alt_bn128_Fq12 H = D.unitary_inverse(); + const alt_bn128_Fq12 I = G.unitary_inverse(); + const alt_bn128_Fq12 J = I * E; + const alt_bn128_Fq12 K = J * H; + const alt_bn128_Fq12 L = K * B; + const alt_bn128_Fq12 M = K * E; + const alt_bn128_Fq12 N = M * elt; + const alt_bn128_Fq12 O = L.Frobenius_map(1); + const alt_bn128_Fq12 P = O * N; + const alt_bn128_Fq12 Q = K.Frobenius_map(2); + const alt_bn128_Fq12 R = Q * P; + const alt_bn128_Fq12 S = elt.unitary_inverse(); + const alt_bn128_Fq12 T = S * L; + const alt_bn128_Fq12 U = T.Frobenius_map(3); + const alt_bn128_Fq12 V = U * R; + + const alt_bn128_Fq12 result = V; + + leave_block("Call to alt_bn128_final_exponentiation_last_chunk"); + + return result; +} + +alt_bn128_GT alt_bn128_final_exponentiation(const alt_bn128_Fq12 &elt) +{ + enter_block("Call to alt_bn128_final_exponentiation"); + /* OLD naive version: + alt_bn128_GT result = elt^alt_bn128_final_exponent; + */ + alt_bn128_Fq12 A = alt_bn128_final_exponentiation_first_chunk(elt); + alt_bn128_GT result = alt_bn128_final_exponentiation_last_chunk(A); + + leave_block("Call to alt_bn128_final_exponentiation"); + return result; +} + +/* ate pairing */ + +void doubling_step_for_flipped_miller_loop(const alt_bn128_Fq two_inv, + alt_bn128_G2 ¤t, + alt_bn128_ate_ell_coeffs &c) +{ + const alt_bn128_Fq2 X = current.X, Y = current.Y, Z = current.Z; + + const alt_bn128_Fq2 A = two_inv * (X * Y); // A = X1 * Y1 / 2 + const alt_bn128_Fq2 B = Y.squared(); // B = Y1^2 + const alt_bn128_Fq2 C = Z.squared(); // C = Z1^2 + const alt_bn128_Fq2 D = C+C+C; // D = 3 * C + const alt_bn128_Fq2 E = alt_bn128_twist_coeff_b * D; // E = twist_b * D + const alt_bn128_Fq2 F = E+E+E; // F = 3 * E + const alt_bn128_Fq2 G = two_inv * (B+F); // G = (B+F)/2 + const alt_bn128_Fq2 H = (Y+Z).squared() - (B+C); // H = (Y1+Z1)^2-(B+C) + const alt_bn128_Fq2 I = E-B; // I = E-B + const alt_bn128_Fq2 J = X.squared(); // J = X1^2 + const alt_bn128_Fq2 E_squared = E.squared(); // E_squared = E^2 + + current.X = A * (B-F); // X3 = A * (B-F) + current.Y = G.squared() - (E_squared+E_squared+E_squared); // Y3 = G^2 - 3*E^2 + current.Z = B * H; // Z3 = B * H + c.ell_0 = alt_bn128_twist * I; // ell_0 = xi * I + c.ell_VW = -H; // ell_VW = - H (later: * yP) + c.ell_VV = J+J+J; // ell_VV = 3*J (later: * xP) +} + +void mixed_addition_step_for_flipped_miller_loop(const alt_bn128_G2 base, + alt_bn128_G2 ¤t, + alt_bn128_ate_ell_coeffs &c) +{ + const alt_bn128_Fq2 X1 = current.X, Y1 = current.Y, Z1 = current.Z; + const alt_bn128_Fq2 &x2 = base.X, &y2 = base.Y; + + const alt_bn128_Fq2 D = X1 - x2 * Z1; // D = X1 - X2*Z1 + const alt_bn128_Fq2 E = Y1 - y2 * Z1; // E = Y1 - Y2*Z1 + const alt_bn128_Fq2 F = D.squared(); // F = D^2 + const alt_bn128_Fq2 G = E.squared(); // G = E^2 + const alt_bn128_Fq2 H = D*F; // H = D*F + const alt_bn128_Fq2 I = X1 * F; // I = X1 * F + const alt_bn128_Fq2 J = H + Z1*G - (I+I); // J = H + Z1*G - (I+I) + + current.X = D * J; // X3 = D*J + current.Y = E * (I-J)-(H * Y1); // Y3 = E*(I-J)-(H*Y1) + current.Z = Z1 * H; // Z3 = Z1*H + c.ell_0 = alt_bn128_twist * (E * x2 - D * y2); // ell_0 = xi * (E * X2 - D * Y2) + c.ell_VV = - E; // ell_VV = - E (later: * xP) + c.ell_VW = D; // ell_VW = D (later: * yP ) +} + +alt_bn128_ate_G1_precomp alt_bn128_ate_precompute_G1(const alt_bn128_G1& P) +{ + enter_block("Call to alt_bn128_ate_precompute_G1"); + + alt_bn128_G1 Pcopy = P; + Pcopy.to_affine_coordinates(); + + alt_bn128_ate_G1_precomp result; + result.PX = Pcopy.X; + result.PY = Pcopy.Y; + + leave_block("Call to alt_bn128_ate_precompute_G1"); + return result; +} + +alt_bn128_ate_G2_precomp alt_bn128_ate_precompute_G2(const alt_bn128_G2& Q) +{ + enter_block("Call to alt_bn128_ate_precompute_G2"); + + alt_bn128_G2 Qcopy(Q); + Qcopy.to_affine_coordinates(); + + alt_bn128_Fq two_inv = (alt_bn128_Fq("2").inverse()); // could add to global params if needed + + alt_bn128_ate_G2_precomp result; + result.QX = Qcopy.X; + result.QY = Qcopy.Y; + + alt_bn128_G2 R; + R.X = Qcopy.X; + R.Y = Qcopy.Y; + R.Z = alt_bn128_Fq2::one(); + + const bigint &loop_count = alt_bn128_ate_loop_count; + bool found_one = false; + alt_bn128_ate_ell_coeffs c; + + for (long i = loop_count.max_bits(); i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + doubling_step_for_flipped_miller_loop(two_inv, R, c); + result.coeffs.push_back(c); + + if (bit) + { + mixed_addition_step_for_flipped_miller_loop(Qcopy, R, c); + result.coeffs.push_back(c); + } + } + + alt_bn128_G2 Q1 = Qcopy.mul_by_q(); + assert(Q1.Z == alt_bn128_Fq2::one()); + alt_bn128_G2 Q2 = Q1.mul_by_q(); + assert(Q2.Z == alt_bn128_Fq2::one()); + + if (alt_bn128_ate_is_loop_count_neg) + { + R.Y = - R.Y; + } + Q2.Y = - Q2.Y; + + mixed_addition_step_for_flipped_miller_loop(Q1, R, c); + result.coeffs.push_back(c); + + mixed_addition_step_for_flipped_miller_loop(Q2, R, c); + result.coeffs.push_back(c); + + leave_block("Call to alt_bn128_ate_precompute_G2"); + return result; +} + +alt_bn128_Fq12 alt_bn128_ate_miller_loop(const alt_bn128_ate_G1_precomp &prec_P, + const alt_bn128_ate_G2_precomp &prec_Q) +{ + enter_block("Call to alt_bn128_ate_miller_loop"); + + alt_bn128_Fq12 f = alt_bn128_Fq12::one(); + + bool found_one = false; + size_t idx = 0; + + const bigint &loop_count = alt_bn128_ate_loop_count; + alt_bn128_ate_ell_coeffs c; + + for (long i = loop_count.max_bits(); i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + alt_bn128_param_p (skipping leading zeros) in MSB to LSB + order */ + + c = prec_Q.coeffs[idx++]; + f = f.squared(); + f = f.mul_by_024(c.ell_0, prec_P.PY * c.ell_VW, prec_P.PX * c.ell_VV); + + if (bit) + { + c = prec_Q.coeffs[idx++]; + f = f.mul_by_024(c.ell_0, prec_P.PY * c.ell_VW, prec_P.PX * c.ell_VV); + } + + } + + if (alt_bn128_ate_is_loop_count_neg) + { + f = f.inverse(); + } + + c = prec_Q.coeffs[idx++]; + f = f.mul_by_024(c.ell_0,prec_P.PY * c.ell_VW,prec_P.PX * c.ell_VV); + + c = prec_Q.coeffs[idx++]; + f = f.mul_by_024(c.ell_0,prec_P.PY * c.ell_VW,prec_P.PX * c.ell_VV); + + leave_block("Call to alt_bn128_ate_miller_loop"); + return f; +} + +alt_bn128_Fq12 alt_bn128_ate_double_miller_loop(const alt_bn128_ate_G1_precomp &prec_P1, + const alt_bn128_ate_G2_precomp &prec_Q1, + const alt_bn128_ate_G1_precomp &prec_P2, + const alt_bn128_ate_G2_precomp &prec_Q2) +{ + enter_block("Call to alt_bn128_ate_double_miller_loop"); + + alt_bn128_Fq12 f = alt_bn128_Fq12::one(); + + bool found_one = false; + size_t idx = 0; + + const bigint &loop_count = alt_bn128_ate_loop_count; + for (long i = loop_count.max_bits(); i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + alt_bn128_param_p (skipping leading zeros) in MSB to LSB + order */ + + alt_bn128_ate_ell_coeffs c1 = prec_Q1.coeffs[idx]; + alt_bn128_ate_ell_coeffs c2 = prec_Q2.coeffs[idx]; + ++idx; + + f = f.squared(); + + f = f.mul_by_024(c1.ell_0, prec_P1.PY * c1.ell_VW, prec_P1.PX * c1.ell_VV); + f = f.mul_by_024(c2.ell_0, prec_P2.PY * c2.ell_VW, prec_P2.PX * c2.ell_VV); + + if (bit) + { + alt_bn128_ate_ell_coeffs c1 = prec_Q1.coeffs[idx]; + alt_bn128_ate_ell_coeffs c2 = prec_Q2.coeffs[idx]; + ++idx; + + f = f.mul_by_024(c1.ell_0, prec_P1.PY * c1.ell_VW, prec_P1.PX * c1.ell_VV); + f = f.mul_by_024(c2.ell_0, prec_P2.PY * c2.ell_VW, prec_P2.PX * c2.ell_VV); + } + } + + if (alt_bn128_ate_is_loop_count_neg) + { + f = f.inverse(); + } + + alt_bn128_ate_ell_coeffs c1 = prec_Q1.coeffs[idx]; + alt_bn128_ate_ell_coeffs c2 = prec_Q2.coeffs[idx]; + ++idx; + f = f.mul_by_024(c1.ell_0, prec_P1.PY * c1.ell_VW, prec_P1.PX * c1.ell_VV); + f = f.mul_by_024(c2.ell_0, prec_P2.PY * c2.ell_VW, prec_P2.PX * c2.ell_VV); + + c1 = prec_Q1.coeffs[idx]; + c2 = prec_Q2.coeffs[idx]; + ++idx; + f = f.mul_by_024(c1.ell_0, prec_P1.PY * c1.ell_VW, prec_P1.PX * c1.ell_VV); + f = f.mul_by_024(c2.ell_0, prec_P2.PY * c2.ell_VW, prec_P2.PX * c2.ell_VV); + + leave_block("Call to alt_bn128_ate_double_miller_loop"); + + return f; +} + +alt_bn128_Fq12 alt_bn128_ate_pairing(const alt_bn128_G1& P, const alt_bn128_G2 &Q) +{ + enter_block("Call to alt_bn128_ate_pairing"); + alt_bn128_ate_G1_precomp prec_P = alt_bn128_ate_precompute_G1(P); + alt_bn128_ate_G2_precomp prec_Q = alt_bn128_ate_precompute_G2(Q); + alt_bn128_Fq12 result = alt_bn128_ate_miller_loop(prec_P, prec_Q); + leave_block("Call to alt_bn128_ate_pairing"); + return result; +} + +alt_bn128_GT alt_bn128_ate_reduced_pairing(const alt_bn128_G1 &P, const alt_bn128_G2 &Q) +{ + enter_block("Call to alt_bn128_ate_reduced_pairing"); + const alt_bn128_Fq12 f = alt_bn128_ate_pairing(P, Q); + const alt_bn128_GT result = alt_bn128_final_exponentiation(f); + leave_block("Call to alt_bn128_ate_reduced_pairing"); + return result; +} + +/* choice of pairing */ + +alt_bn128_G1_precomp alt_bn128_precompute_G1(const alt_bn128_G1& P) +{ + return alt_bn128_ate_precompute_G1(P); +} + +alt_bn128_G2_precomp alt_bn128_precompute_G2(const alt_bn128_G2& Q) +{ + return alt_bn128_ate_precompute_G2(Q); +} + +alt_bn128_Fq12 alt_bn128_miller_loop(const alt_bn128_G1_precomp &prec_P, + const alt_bn128_G2_precomp &prec_Q) +{ + return alt_bn128_ate_miller_loop(prec_P, prec_Q); +} + +alt_bn128_Fq12 alt_bn128_double_miller_loop(const alt_bn128_G1_precomp &prec_P1, + const alt_bn128_G2_precomp &prec_Q1, + const alt_bn128_G1_precomp &prec_P2, + const alt_bn128_G2_precomp &prec_Q2) +{ + return alt_bn128_ate_double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); +} + +alt_bn128_Fq12 alt_bn128_pairing(const alt_bn128_G1& P, + const alt_bn128_G2 &Q) +{ + return alt_bn128_ate_pairing(P, Q); +} + +alt_bn128_GT alt_bn128_reduced_pairing(const alt_bn128_G1 &P, + const alt_bn128_G2 &Q) +{ + return alt_bn128_ate_reduced_pairing(P, Q); +} +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_pairing.d b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_pairing.d new file mode 100644 index 0000000..ebf52a4 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_pairing.d @@ -0,0 +1,19 @@ +src/algebra/curves/alt_bn128/alt_bn128_pairing.o: \ + src/algebra/curves/alt_bn128/alt_bn128_pairing.cpp \ + src/algebra/curves/alt_bn128/alt_bn128_pairing.hpp \ + src/algebra/curves/alt_bn128/alt_bn128_init.hpp \ + src/algebra/curves/public_params.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc src/algebra/fields/fp2.hpp \ + src/algebra/fields/fp2.tcc src/algebra/fields/fp6_3over2.hpp \ + src/algebra/fields/fp6_3over2.tcc \ + src/algebra/fields/fp12_2over3over2.hpp \ + src/algebra/fields/fp12_2over3over2.tcc \ + src/algebra/curves/alt_bn128/alt_bn128_g1.hpp \ + src/algebra/curves/curve_utils.hpp src/algebra/curves/curve_utils.tcc \ + src/algebra/curves/alt_bn128/alt_bn128_g2.hpp src/common/profiling.hpp diff --git a/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_pairing.hpp b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_pairing.hpp new file mode 100644 index 0000000..15d3254 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_pairing.hpp @@ -0,0 +1,92 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALT_BN128_PAIRING_HPP_ +#define ALT_BN128_PAIRING_HPP_ +#include +#include "algebra/curves/alt_bn128/alt_bn128_init.hpp" + +namespace libsnark { + +/* final exponentiation */ + +alt_bn128_GT alt_bn128_final_exponentiation(const alt_bn128_Fq12 &elt); + +/* ate pairing */ + +struct alt_bn128_ate_G1_precomp { + alt_bn128_Fq PX; + alt_bn128_Fq PY; + + bool operator==(const alt_bn128_ate_G1_precomp &other) const; + friend std::ostream& operator<<(std::ostream &out, const alt_bn128_ate_G1_precomp &prec_P); + friend std::istream& operator>>(std::istream &in, alt_bn128_ate_G1_precomp &prec_P); +}; + +struct alt_bn128_ate_ell_coeffs { + alt_bn128_Fq2 ell_0; + alt_bn128_Fq2 ell_VW; + alt_bn128_Fq2 ell_VV; + + bool operator==(const alt_bn128_ate_ell_coeffs &other) const; + friend std::ostream& operator<<(std::ostream &out, const alt_bn128_ate_ell_coeffs &dc); + friend std::istream& operator>>(std::istream &in, alt_bn128_ate_ell_coeffs &dc); +}; + +struct alt_bn128_ate_G2_precomp { + alt_bn128_Fq2 QX; + alt_bn128_Fq2 QY; + std::vector coeffs; + + bool operator==(const alt_bn128_ate_G2_precomp &other) const; + friend std::ostream& operator<<(std::ostream &out, const alt_bn128_ate_G2_precomp &prec_Q); + friend std::istream& operator>>(std::istream &in, alt_bn128_ate_G2_precomp &prec_Q); +}; + +alt_bn128_ate_G1_precomp alt_bn128_ate_precompute_G1(const alt_bn128_G1& P); +alt_bn128_ate_G2_precomp alt_bn128_ate_precompute_G2(const alt_bn128_G2& Q); + +alt_bn128_Fq12 alt_bn128_ate_miller_loop(const alt_bn128_ate_G1_precomp &prec_P, + const alt_bn128_ate_G2_precomp &prec_Q); +alt_bn128_Fq12 alt_bn128_ate_double_miller_loop(const alt_bn128_ate_G1_precomp &prec_P1, + const alt_bn128_ate_G2_precomp &prec_Q1, + const alt_bn128_ate_G1_precomp &prec_P2, + const alt_bn128_ate_G2_precomp &prec_Q2); + +alt_bn128_Fq12 alt_bn128_ate_pairing(const alt_bn128_G1& P, + const alt_bn128_G2 &Q); +alt_bn128_GT alt_bn128_ate_reduced_pairing(const alt_bn128_G1 &P, + const alt_bn128_G2 &Q); + +/* choice of pairing */ + +typedef alt_bn128_ate_G1_precomp alt_bn128_G1_precomp; +typedef alt_bn128_ate_G2_precomp alt_bn128_G2_precomp; + +alt_bn128_G1_precomp alt_bn128_precompute_G1(const alt_bn128_G1& P); + +alt_bn128_G2_precomp alt_bn128_precompute_G2(const alt_bn128_G2& Q); + +alt_bn128_Fq12 alt_bn128_miller_loop(const alt_bn128_G1_precomp &prec_P, + const alt_bn128_G2_precomp &prec_Q); + +alt_bn128_Fq12 alt_bn128_double_miller_loop(const alt_bn128_G1_precomp &prec_P1, + const alt_bn128_G2_precomp &prec_Q1, + const alt_bn128_G1_precomp &prec_P2, + const alt_bn128_G2_precomp &prec_Q2); + +alt_bn128_Fq12 alt_bn128_pairing(const alt_bn128_G1& P, + const alt_bn128_G2 &Q); + +alt_bn128_GT alt_bn128_reduced_pairing(const alt_bn128_G1 &P, + const alt_bn128_G2 &Q); + +alt_bn128_GT alt_bn128_affine_reduced_pairing(const alt_bn128_G1 &P, + const alt_bn128_G2 &Q); + +} // libsnark +#endif // ALT_BN128_PAIRING_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_pp.cpp b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_pp.cpp new file mode 100644 index 0000000..25ea924 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_pp.cpp @@ -0,0 +1,58 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" + +namespace libsnark { + +void alt_bn128_pp::init_public_params() +{ + init_alt_bn128_params(); +} + +alt_bn128_GT alt_bn128_pp::final_exponentiation(const alt_bn128_Fq12 &elt) +{ + return alt_bn128_final_exponentiation(elt); +} + +alt_bn128_G1_precomp alt_bn128_pp::precompute_G1(const alt_bn128_G1 &P) +{ + return alt_bn128_precompute_G1(P); +} + +alt_bn128_G2_precomp alt_bn128_pp::precompute_G2(const alt_bn128_G2 &Q) +{ + return alt_bn128_precompute_G2(Q); +} + +alt_bn128_Fq12 alt_bn128_pp::miller_loop(const alt_bn128_G1_precomp &prec_P, + const alt_bn128_G2_precomp &prec_Q) +{ + return alt_bn128_miller_loop(prec_P, prec_Q); +} + +alt_bn128_Fq12 alt_bn128_pp::double_miller_loop(const alt_bn128_G1_precomp &prec_P1, + const alt_bn128_G2_precomp &prec_Q1, + const alt_bn128_G1_precomp &prec_P2, + const alt_bn128_G2_precomp &prec_Q2) +{ + return alt_bn128_double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); +} + +alt_bn128_Fq12 alt_bn128_pp::pairing(const alt_bn128_G1 &P, + const alt_bn128_G2 &Q) +{ + return alt_bn128_pairing(P, Q); +} + +alt_bn128_Fq12 alt_bn128_pp::reduced_pairing(const alt_bn128_G1 &P, + const alt_bn128_G2 &Q) +{ + return alt_bn128_reduced_pairing(P, Q); +} + +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_pp.d b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_pp.d new file mode 100644 index 0000000..a3f7ec8 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_pp.d @@ -0,0 +1,20 @@ +src/algebra/curves/alt_bn128/alt_bn128_pp.o: \ + src/algebra/curves/alt_bn128/alt_bn128_pp.cpp \ + src/algebra/curves/alt_bn128/alt_bn128_pp.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/alt_bn128/alt_bn128_init.hpp \ + src/algebra/fields/fp.hpp src/algebra/fields/bigint.hpp \ + src/common/serialization.hpp src/common/serialization.tcc \ + src/common/utils.hpp src/common/utils.tcc src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc src/algebra/fields/fp2.hpp \ + src/algebra/fields/fp2.tcc src/algebra/fields/fp6_3over2.hpp \ + src/algebra/fields/fp6_3over2.tcc \ + src/algebra/fields/fp12_2over3over2.hpp \ + src/algebra/fields/fp12_2over3over2.tcc \ + src/algebra/curves/alt_bn128/alt_bn128_g1.hpp \ + src/algebra/curves/curve_utils.hpp src/algebra/curves/curve_utils.tcc \ + src/algebra/curves/alt_bn128/alt_bn128_g2.hpp \ + src/algebra/curves/alt_bn128/alt_bn128_pairing.hpp diff --git a/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_pp.hpp b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_pp.hpp new file mode 100644 index 0000000..ec8059d --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/alt_bn128/alt_bn128_pp.hpp @@ -0,0 +1,50 @@ +/** @file +***************************************************************************** +* @author This file is part of libsnark, developed by SCIPR Lab +* and contributors (see AUTHORS). +* @copyright MIT license (see LICENSE file) +*****************************************************************************/ + +#ifndef ALT_BN128_PP_HPP_ +#define ALT_BN128_PP_HPP_ +#include "algebra/curves/public_params.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_init.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_g1.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_g2.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_pairing.hpp" + +namespace libsnark { + +class alt_bn128_pp { +public: + typedef alt_bn128_Fr Fp_type; + typedef alt_bn128_G1 G1_type; + typedef alt_bn128_G2 G2_type; + typedef alt_bn128_G1_precomp G1_precomp_type; + typedef alt_bn128_G2_precomp G2_precomp_type; + typedef alt_bn128_Fq Fq_type; + typedef alt_bn128_Fq2 Fqe_type; + typedef alt_bn128_Fq12 Fqk_type; + typedef alt_bn128_GT GT_type; + + static const bool has_affine_pairing = false; + + static void init_public_params(); + static alt_bn128_GT final_exponentiation(const alt_bn128_Fq12 &elt); + static alt_bn128_G1_precomp precompute_G1(const alt_bn128_G1 &P); + static alt_bn128_G2_precomp precompute_G2(const alt_bn128_G2 &Q); + static alt_bn128_Fq12 miller_loop(const alt_bn128_G1_precomp &prec_P, + const alt_bn128_G2_precomp &prec_Q); + static alt_bn128_Fq12 double_miller_loop(const alt_bn128_G1_precomp &prec_P1, + const alt_bn128_G2_precomp &prec_Q1, + const alt_bn128_G1_precomp &prec_P2, + const alt_bn128_G2_precomp &prec_Q2); + static alt_bn128_Fq12 pairing(const alt_bn128_G1 &P, + const alt_bn128_G2 &Q); + static alt_bn128_Fq12 reduced_pairing(const alt_bn128_G1 &P, + const alt_bn128_G2 &Q); +}; + +} // libsnark + +#endif // ALT_BN128_PP_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/bn128/bn128_g1.cpp b/privacy/zsl/zsl/algebra/curves/bn128/bn128_g1.cpp new file mode 100644 index 0000000..04a25c7 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/bn128/bn128_g1.cpp @@ -0,0 +1,520 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/bn128/bn128_g1.hpp" +#include "algebra/curves/bn128/bn_utils.hpp" + +namespace libsnark { + +#ifdef PROFILE_OP_COUNTS +long long bn128_G1::add_cnt = 0; +long long bn128_G1::dbl_cnt = 0; +#endif + +std::vector bn128_G1::wnaf_window_table; +std::vector bn128_G1::fixed_base_exp_window_table; +bn128_G1 bn128_G1::G1_zero; +bn128_G1 bn128_G1::G1_one; + +bn::Fp bn128_G1::sqrt(const bn::Fp &el) +{ + size_t v = bn128_Fq_s; + bn::Fp z = bn128_Fq_nqr_to_t; + bn::Fp w = mie::power(el, bn128_Fq_t_minus_1_over_2); + bn::Fp x = el * w; + bn::Fp b = x * w; + +#if DEBUG + // check if square with Euler's criterion + bn::Fp check = b; + for (size_t i = 0; i < v-1; ++i) + { + bn::Fp::square(check, check); + } + + assert(check == bn::Fp(1)); +#endif + + // compute square root with Tonelli--Shanks + // (does not terminate if not a square!) + + while (b != bn::Fp(1)) + { + size_t m = 0; + bn::Fp b2m = b; + while (b2m != bn::Fp(1)) + { + // invariant: b2m = b^(2^m) after entering this loop + bn::Fp::square(b2m, b2m); + m += 1; + } + + int j = v-m-1; + w = z; + while (j > 0) + { + bn::Fp::square(w, w); + --j; + } // w = z^2^(v-m-1) + + z = w * w; + b = b * z; + x = x * w; + v = m; + } + + return x; +} + +bn128_G1::bn128_G1() +{ + this->coord[0] = G1_zero.coord[0]; + this->coord[1] = G1_zero.coord[1]; + this->coord[2] = G1_zero.coord[2]; +} + +void bn128_G1::print() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + bn128_G1 copy(*this); + copy.to_affine_coordinates(); + std::cout << "(" << copy.coord[0].toString(10) << " : " << copy.coord[1].toString(10) << " : " << copy.coord[2].toString(10) << ")\n"; + } +} + +void bn128_G1::print_coordinates() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + std::cout << "(" << coord[0].toString(10) << " : " << coord[1].toString(10) << " : " << coord[2].toString(10) << ")\n"; + } +} + +void bn128_G1::to_affine_coordinates() +{ + if (this->is_zero()) + { + coord[0] = 0; + coord[1] = 1; + coord[2] = 0; + } + else + { + bn::Fp r; + r = coord[2]; + r.inverse(); + bn::Fp::square(coord[2], r); + coord[0] *= coord[2]; + r *= coord[2]; + coord[1] *= r; + coord[2] = 1; + } +} + +void bn128_G1::to_special() +{ + this->to_affine_coordinates(); +} + +bool bn128_G1::is_special() const +{ + return (this->is_zero() || this->coord[2] == 1); +} + +bool bn128_G1::is_zero() const +{ + return coord[2].isZero(); +} + +bool bn128_G1::operator==(const bn128_G1 &other) const +{ + if (this->is_zero()) + { + return other.is_zero(); + } + + if (other.is_zero()) + { + return false; + } + + /* now neither is O */ + + bn::Fp Z1sq, Z2sq, lhs, rhs; + bn::Fp::square(Z1sq, this->coord[2]); + bn::Fp::square(Z2sq, other.coord[2]); + bn::Fp::mul(lhs, Z2sq, this->coord[0]); + bn::Fp::mul(rhs, Z1sq, other.coord[0]); + + if (lhs != rhs) + { + return false; + } + + bn::Fp Z1cubed, Z2cubed; + bn::Fp::mul(Z1cubed, Z1sq, this->coord[2]); + bn::Fp::mul(Z2cubed, Z2sq, other.coord[2]); + bn::Fp::mul(lhs, Z2cubed, this->coord[1]); + bn::Fp::mul(rhs, Z1cubed, other.coord[1]); + + return (lhs == rhs); +} + +bool bn128_G1::operator!=(const bn128_G1& other) const +{ + return !(operator==(other)); +} + +bn128_G1 bn128_G1::operator+(const bn128_G1 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case, and then all the rest + if (this->operator==(other)) + { + return this->dbl(); + } + else + { + return this->add(other); + } +} + +bn128_G1 bn128_G1::operator-() const +{ + bn128_G1 result(*this); + bn::Fp::neg(result.coord[1], result.coord[1]); + return result; +} + +bn128_G1 bn128_G1::operator-(const bn128_G1 &other) const +{ + return (*this) + (-other); +} + +bn128_G1 bn128_G1::add(const bn128_G1 &other) const +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + + bn128_G1 result; + bn::ecop::ECAdd(result.coord, this->coord, other.coord); + return result; +} + +bn128_G1 bn128_G1::mixed_add(const bn128_G1 &other) const +{ + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + +#ifdef DEBUG + assert(other.is_special()); +#endif + + // check for doubling case + + // using Jacobian coordinates so: + // (X1:Y1:Z1) = (X2:Y2:Z2) + // iff + // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 + // iff + // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 + + // we know that Z2 = 1 + + bn::Fp Z1Z1; + bn::Fp::square(Z1Z1, this->coord[2]); + const bn::Fp &U1 = this->coord[0]; + bn::Fp U2; + bn::Fp::mul(U2, other.coord[0], Z1Z1); + bn::Fp Z1_cubed; + bn::Fp::mul(Z1_cubed, this->coord[2], Z1Z1); + + const bn::Fp &S1 = this->coord[1]; + bn::Fp S2; + bn::Fp::mul(S2, other.coord[1], Z1_cubed); // S2 = Y2*Z1*Z1Z1 + + if (U1 == U2 && S1 == S2) + { + // dbl case; nothing of above can be reused + return this->dbl(); + } + +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + + bn128_G1 result; + bn::Fp H, HH, I, J, r, V, tmp; + // H = U2-X1 + bn::Fp::sub(H, U2, this->coord[0]); + // HH = H^2 + bn::Fp::square(HH, H); + // I = 4*HH + bn::Fp::add(tmp, HH, HH); + bn::Fp::add(I, tmp, tmp); + // J = H*I + bn::Fp::mul(J, H, I); + // r = 2*(S2-Y1) + bn::Fp::sub(tmp, S2, this->coord[1]); + bn::Fp::add(r, tmp, tmp); + // V = X1*I + bn::Fp::mul(V, this->coord[0], I); + // X3 = r^2-J-2*V + bn::Fp::square(result.coord[0], r); + bn::Fp::sub(result.coord[0], result.coord[0], J); + bn::Fp::sub(result.coord[0], result.coord[0], V); + bn::Fp::sub(result.coord[0], result.coord[0], V); + // Y3 = r*(V-X3)-2*Y1*J + bn::Fp::sub(tmp, V, result.coord[0]); + bn::Fp::mul(result.coord[1], r, tmp); + bn::Fp::mul(tmp, this->coord[1], J); + bn::Fp::sub(result.coord[1], result.coord[1], tmp); + bn::Fp::sub(result.coord[1], result.coord[1], tmp); + // Z3 = (Z1+H)^2-Z1Z1-HH + bn::Fp::add(tmp, this->coord[2], H); + bn::Fp::square(result.coord[2], tmp); + bn::Fp::sub(result.coord[2], result.coord[2], Z1Z1); + bn::Fp::sub(result.coord[2], result.coord[2], HH); + return result; +} + +bn128_G1 bn128_G1::dbl() const +{ +#ifdef PROFILE_OP_COUNTS + this->dbl_cnt++; +#endif + + bn128_G1 result; + bn::ecop::ECDouble(result.coord, this->coord); + return result; +} + +bn128_G1 bn128_G1::zero() +{ + return G1_zero; +} + +bn128_G1 bn128_G1::one() +{ + return G1_one; +} + +bn128_G1 bn128_G1::random_element() +{ + return bn128_Fr::random_element().as_bigint() * G1_one; +} + +std::ostream& operator<<(std::ostream &out, const bn128_G1 &g) +{ + bn128_G1 gcopy(g); + gcopy.to_affine_coordinates(); + + out << (gcopy.is_zero() ? '1' : '0') << OUTPUT_SEPARATOR; + +#ifdef NO_PT_COMPRESSION + /* no point compression case */ +#ifndef BINARY_OUTPUT + out << gcopy.coord[0] << OUTPUT_SEPARATOR << gcopy.coord[1]; +#else + out.write((char*) &gcopy.coord[0], sizeof(gcopy.coord[0])); + out.write((char*) &gcopy.coord[1], sizeof(gcopy.coord[1])); +#endif + +#else + /* point compression case */ +#ifndef BINARY_OUTPUT + out << gcopy.coord[0]; +#else + out.write((char*) &gcopy.coord[0], sizeof(gcopy.coord[0])); +#endif + out << OUTPUT_SEPARATOR << (((unsigned char*)&gcopy.coord[1])[0] & 1 ? '1' : '0'); +#endif + + return out; +} + +bool bn128_G1::is_well_formed() const +{ + if (this->is_zero()) + { + return true; + } + else + { + /* + y^2 = x^3 + b + + We are using Jacobian coordinates, so equation we need to check is actually + + (y/z^3)^2 = (x/z^2)^3 + b + y^2 / z^6 = x^3 / z^6 + b + y^2 = x^3 + b z^6 + */ + bn::Fp X2, Y2, Z2; + bn::Fp::square(X2, this->coord[0]); + bn::Fp::square(Y2, this->coord[1]); + bn::Fp::square(Z2, this->coord[2]); + + bn::Fp X3, Z3, Z6; + bn::Fp::mul(X3, X2, this->coord[0]); + bn::Fp::mul(Z3, Z2, this->coord[2]); + bn::Fp::square(Z6, Z3); + + return (Y2 == X3 + bn128_coeff_b * Z6); + } +} + +std::istream& operator>>(std::istream &in, bn128_G1 &g) +{ + char is_zero; + in.read((char*)&is_zero, 1); // this reads is_zero; + is_zero -= '0'; + consume_OUTPUT_SEPARATOR(in); + +#ifdef NO_PT_COMPRESSION + /* no point compression case */ +#ifndef BINARY_OUTPUT + in >> g.coord[0]; + consume_OUTPUT_SEPARATOR(in); + in >> g.coord[1]; +#else + in.read((char*) &g.coord[0], sizeof(g.coord[0])); + in.read((char*) &g.coord[1], sizeof(g.coord[1])); +#endif + +#else + /* point compression case */ + bn::Fp tX; +#ifndef BINARY_OUTPUT + in >> tX; +#else + in.read((char*)&tX, sizeof(tX)); +#endif + consume_OUTPUT_SEPARATOR(in); + unsigned char Y_lsb; + in.read((char*)&Y_lsb, 1); + Y_lsb -= '0'; + + // y = +/- sqrt(x^3 + b) + if (!is_zero) + { + g.coord[0] = tX; + bn::Fp tX2, tY2; + bn::Fp::square(tX2, tX); + bn::Fp::mul(tY2, tX2, tX); + bn::Fp::add(tY2, tY2, bn128_coeff_b); + + g.coord[1] = bn128_G1::sqrt(tY2); + if ((((unsigned char*)&g.coord[1])[0] & 1) != Y_lsb) + { + bn::Fp::neg(g.coord[1], g.coord[1]); + } + } +#endif + + /* finalize */ + if (!is_zero) + { + g.coord[2] = bn::Fp(1); + } + else + { + g = bn128_G1::zero(); + } + + return in; +} + +std::ostream& operator<<(std::ostream& out, const std::vector &v) +{ + out << v.size() << "\n"; + for (const bn128_G1& t : v) + { + out << t << OUTPUT_NEWLINE; + } + return out; +} + +std::istream& operator>>(std::istream& in, std::vector &v) +{ + v.clear(); + + size_t s; + in >> s; + consume_newline(in); + v.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + bn128_G1 g; + in >> g; + consume_OUTPUT_NEWLINE(in); + v.emplace_back(g); + } + return in; +} + +template<> +void batch_to_special_all_non_zeros(std::vector &vec) +{ + std::vector Z_vec; + Z_vec.reserve(vec.size()); + + for (auto &el: vec) + { + Z_vec.emplace_back(el.coord[2]); + } + bn_batch_invert(Z_vec); + + const bn::Fp one = 1; + + for (size_t i = 0; i < vec.size(); ++i) + { + bn::Fp Z2, Z3; + bn::Fp::square(Z2, Z_vec[i]); + bn::Fp::mul(Z3, Z2, Z_vec[i]); + + bn::Fp::mul(vec[i].coord[0], vec[i].coord[0], Z2); + bn::Fp::mul(vec[i].coord[1], vec[i].coord[1], Z3); + vec[i].coord[2] = one; + } +} + +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/bn128/bn128_g1.d b/privacy/zsl/zsl/algebra/curves/bn128/bn128_g1.d new file mode 100644 index 0000000..c94207e --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/bn128/bn128_g1.d @@ -0,0 +1,16 @@ +src/algebra/curves/bn128/bn128_g1.o: \ + src/algebra/curves/bn128/bn128_g1.cpp \ + src/algebra/curves/bn128/bn128_g1.hpp \ + src/algebra/curves/bn128/bn128_init.hpp \ + src/algebra/curves/public_params.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc depinst/include/bn.h \ + depinst/include/zm2.h depinst/include/zm.h \ + src/algebra/curves/curve_utils.hpp src/algebra/curves/curve_utils.tcc \ + src/algebra/curves/bn128/bn_utils.hpp \ + src/algebra/curves/bn128/bn_utils.tcc diff --git a/privacy/zsl/zsl/algebra/curves/bn128/bn128_g1.hpp b/privacy/zsl/zsl/algebra/curves/bn128/bn128_g1.hpp new file mode 100644 index 0000000..77d78ef --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/bn128/bn128_g1.hpp @@ -0,0 +1,94 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BN128_G1_HPP_ +#define BN128_G1_HPP_ +#include +#include "algebra/curves/bn128/bn128_init.hpp" +#include "algebra/curves/curve_utils.hpp" +#include "bn.h" + +namespace libsnark { + +class bn128_G1; +std::ostream& operator<<(std::ostream &, const bn128_G1&); +std::istream& operator>>(std::istream &, bn128_G1&); + +class bn128_G1 { +private: + static bn::Fp sqrt(const bn::Fp &el); +public: +#ifdef PROFILE_OP_COUNTS + static long long add_cnt; + static long long dbl_cnt; +#endif + static std::vector wnaf_window_table; + static std::vector fixed_base_exp_window_table; + static bn128_G1 G1_zero; + static bn128_G1 G1_one; + + bn::Fp coord[3]; + bn128_G1(); + typedef bn128_Fq base_field; + typedef bn128_Fr scalar_field; + + void print() const; + void print_coordinates() const; + + void to_affine_coordinates(); + void to_special(); + bool is_special() const; + + bool is_zero() const; + + bool operator==(const bn128_G1 &other) const; + bool operator!=(const bn128_G1 &other) const; + + bn128_G1 operator+(const bn128_G1 &other) const; + bn128_G1 operator-() const; + bn128_G1 operator-(const bn128_G1 &other) const; + + bn128_G1 add(const bn128_G1 &other) const; + bn128_G1 mixed_add(const bn128_G1 &other) const; + bn128_G1 dbl() const; + + bool is_well_formed() const; + + static bn128_G1 zero(); + static bn128_G1 one(); + static bn128_G1 random_element(); + + static size_t size_in_bits() { return bn128_Fq::size_in_bits() + 1; } + static bigint base_field_char() { return base_field::field_char(); } + static bigint order() { return scalar_field::field_char(); } + + friend std::ostream& operator<<(std::ostream &out, const bn128_G1 &g); + friend std::istream& operator>>(std::istream &in, bn128_G1 &g); +}; + +template +bn128_G1 operator*(const bigint &lhs, const bn128_G1 &rhs) +{ + return scalar_mul(rhs, lhs); +} + +template& modulus_p> +bn128_G1 operator*(const Fp_model &lhs, const bn128_G1 &rhs) +{ + return scalar_mul(rhs, lhs.as_bigint()); +} + +std::ostream& operator<<(std::ostream& out, const std::vector &v); +std::istream& operator>>(std::istream& in, std::vector &v); + +template +void batch_to_special_all_non_zeros(std::vector &vec); +template<> +void batch_to_special_all_non_zeros(std::vector &vec); + +} // libsnark +#endif // BN128_G1_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/bn128/bn128_g2.cpp b/privacy/zsl/zsl/algebra/curves/bn128/bn128_g2.cpp new file mode 100644 index 0000000..061fe89 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/bn128/bn128_g2.cpp @@ -0,0 +1,503 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/bn128/bn128_g2.hpp" +#include "algebra/curves/bn128/bn_utils.hpp" + +namespace libsnark { + +#ifdef PROFILE_OP_COUNTS +long long bn128_G2::add_cnt = 0; +long long bn128_G2::dbl_cnt = 0; +#endif + +std::vector bn128_G2::wnaf_window_table; +std::vector bn128_G2::fixed_base_exp_window_table; +bn128_G2 bn128_G2::G2_zero; +bn128_G2 bn128_G2::G2_one; + +bn::Fp2 bn128_G2::sqrt(const bn::Fp2 &el) +{ + size_t v = bn128_Fq2_s; + bn::Fp2 z = bn128_Fq2_nqr_to_t; + bn::Fp2 w = mie::power(el, bn128_Fq2_t_minus_1_over_2); + bn::Fp2 x = el * w; + bn::Fp2 b = x * w; + +#if DEBUG + // check if square with Euler's criterion + bn::Fp2 check = b; + for (size_t i = 0; i < v-1; ++i) + { + bn::Fp2::square(check, check); + } + + assert(check == bn::Fp2(bn::Fp(1), bn::Fp(0))); +#endif + + // compute square root with Tonelli--Shanks + // (does not terminate if not a square!) + + while (b != bn::Fp2(1)) + { + size_t m = 0; + bn::Fp2 b2m = b; + while (b2m != bn::Fp2(bn::Fp(1), bn::Fp(0))) + { + // invariant: b2m = b^(2^m) after entering this loop + bn::Fp2::square(b2m, b2m); + m += 1; + } + + int j = v-m-1; + w = z; + while (j > 0) + { + bn::Fp2::square(w, w); + --j; + } // w = z^2^(v-m-1) + + z = w * w; + b = b * z; + x = x * w; + v = m; + } + + return x; +} + +bn128_G2::bn128_G2() +{ + this->coord[0] = G2_zero.coord[0]; + this->coord[1] = G2_zero.coord[1]; + this->coord[2] = G2_zero.coord[2]; +} + +void bn128_G2::print() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + bn128_G2 copy(*this); + copy.to_affine_coordinates(); + std::cout << "(" << copy.coord[0].toString(10) << " : " << copy.coord[1].toString(10) << " : " << copy.coord[2].toString(10) << ")\n"; + } +} + +void bn128_G2::print_coordinates() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + std::cout << "(" << coord[0].toString(10) << " : " << coord[1].toString(10) << " : " << coord[2].toString(10) << ")\n"; + } +} + +void bn128_G2::to_affine_coordinates() +{ + if (this->is_zero()) + { + coord[0] = 0; + coord[1] = 1; + coord[2] = 0; + } + else + { + bn::Fp2 r; + r = coord[2]; + r.inverse(); + bn::Fp2::square(coord[2], r); + coord[0] *= coord[2]; + r *= coord[2]; + coord[1] *= r; + coord[2] = 1; + } +} + +void bn128_G2::to_special() +{ + this->to_affine_coordinates(); +} + +bool bn128_G2::is_special() const +{ + return (this->is_zero() || this->coord[2] == 1); +} + +bool bn128_G2::is_zero() const +{ + return coord[2].isZero(); +} + +bool bn128_G2::operator==(const bn128_G2 &other) const +{ + if (this->is_zero()) + { + return other.is_zero(); + } + + if (other.is_zero()) + { + return false; + } + + /* now neither is O */ + + bn::Fp2 Z1sq, Z2sq, lhs, rhs; + bn::Fp2::square(Z1sq, this->coord[2]); + bn::Fp2::square(Z2sq, other.coord[2]); + bn::Fp2::mul(lhs, Z2sq, this->coord[0]); + bn::Fp2::mul(rhs, Z1sq, other.coord[0]); + + if (lhs != rhs) + { + return false; + } + + bn::Fp2 Z1cubed, Z2cubed; + bn::Fp2::mul(Z1cubed, Z1sq, this->coord[2]); + bn::Fp2::mul(Z2cubed, Z2sq, other.coord[2]); + bn::Fp2::mul(lhs, Z2cubed, this->coord[1]); + bn::Fp2::mul(rhs, Z1cubed, other.coord[1]); + + return (lhs == rhs); +} + +bool bn128_G2::operator!=(const bn128_G2& other) const +{ + return !(operator==(other)); +} + +bn128_G2 bn128_G2::operator+(const bn128_G2 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case, and then all the rest + if (this->operator==(other)) + { + return this->dbl(); + } + else + { + return this->add(other); + } +} + +bn128_G2 bn128_G2::operator-() const +{ + bn128_G2 result(*this); + bn::Fp2::neg(result.coord[1], result.coord[1]); + return result; +} + +bn128_G2 bn128_G2::operator-(const bn128_G2 &other) const +{ + return (*this) + (-other); +} + +bn128_G2 bn128_G2::add(const bn128_G2 &other) const +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + + bn128_G2 result; + bn::ecop::ECAdd(result.coord, this->coord, other.coord); + return result; +} + +bn128_G2 bn128_G2::mixed_add(const bn128_G2 &other) const +{ + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + +#ifdef DEBUG + assert(other.is_special()); +#endif + + // check for doubling case + + // using Jacobian coordinates so: + // (X1:Y1:Z1) = (X2:Y2:Z2) + // iff + // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 + // iff + // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 + + // we know that Z2 = 1 + + bn::Fp2 Z1Z1; + bn::Fp2::square(Z1Z1, this->coord[2]); + const bn::Fp2 &U1 = this->coord[0]; + bn::Fp2 U2; + bn::Fp2::mul(U2, other.coord[0], Z1Z1); + bn::Fp2 Z1_cubed; + bn::Fp2::mul(Z1_cubed, this->coord[2], Z1Z1); + + const bn::Fp2 &S1 = this->coord[1]; + bn::Fp2 S2; + bn::Fp2::mul(S2, other.coord[1], Z1_cubed); // S2 = Y2*Z1*Z1Z1 + + if (U1 == U2 && S1 == S2) + { + // dbl case; nothing of above can be reused + return this->dbl(); + } + +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + + bn128_G2 result; + bn::Fp2 H, HH, I, J, r, V, tmp; + // H = U2-X1 + bn::Fp2::sub(H, U2, this->coord[0]); + // HH = H^2 + bn::Fp2::square(HH, H); + // I = 4*HH + bn::Fp2::add(tmp, HH, HH); + bn::Fp2::add(I, tmp, tmp); + // J = H*I + bn::Fp2::mul(J, H, I); + // r = 2*(S2-Y1) + bn::Fp2::sub(tmp, S2, this->coord[1]); + bn::Fp2::add(r, tmp, tmp); + // V = X1*I + bn::Fp2::mul(V, this->coord[0], I); + // X3 = r^2-J-2*V + bn::Fp2::square(result.coord[0], r); + bn::Fp2::sub(result.coord[0], result.coord[0], J); + bn::Fp2::sub(result.coord[0], result.coord[0], V); + bn::Fp2::sub(result.coord[0], result.coord[0], V); + // Y3 = r*(V-X3)-2*Y1*J + bn::Fp2::sub(tmp, V, result.coord[0]); + bn::Fp2::mul(result.coord[1], r, tmp); + bn::Fp2::mul(tmp, this->coord[1], J); + bn::Fp2::sub(result.coord[1], result.coord[1], tmp); + bn::Fp2::sub(result.coord[1], result.coord[1], tmp); + // Z3 = (Z1+H)^2-Z1Z1-HH + bn::Fp2::add(tmp, this->coord[2], H); + bn::Fp2::square(result.coord[2], tmp); + bn::Fp2::sub(result.coord[2], result.coord[2], Z1Z1); + bn::Fp2::sub(result.coord[2], result.coord[2], HH); + return result; +} + +bn128_G2 bn128_G2::dbl() const +{ +#ifdef PROFILE_OP_COUNTS + this->dbl_cnt++; +#endif + bn128_G2 result; + bn::ecop::ECDouble(result.coord, this->coord); + return result; +} + +bool bn128_G2::is_well_formed() const +{ + if (this->is_zero()) + { + return true; + } + else + { + /* + y^2 = x^3 + b + + We are using Jacobian coordinates, so equation we need to check is actually + + (y/z^3)^2 = (x/z^2)^3 + b + y^2 / z^6 = x^3 / z^6 + b + y^2 = x^3 + b z^6 + */ + bn::Fp2 X2, Y2, Z2; + bn::Fp2::square(X2, this->coord[0]); + bn::Fp2::square(Y2, this->coord[1]); + bn::Fp2::square(Z2, this->coord[2]); + + bn::Fp2 X3, Z3, Z6; + bn::Fp2::mul(X3, X2, this->coord[0]); + bn::Fp2::mul(Z3, Z2, this->coord[2]); + bn::Fp2::square(Z6, Z3); + + return (Y2 == X3 + bn128_twist_coeff_b * Z6); + } +} + +bn128_G2 bn128_G2::zero() +{ + return G2_zero; +} + +bn128_G2 bn128_G2::one() +{ + return G2_one; +} + +bn128_G2 bn128_G2::random_element() +{ + return bn128_Fr::random_element().as_bigint() * G2_one; +} + +std::ostream& operator<<(std::ostream &out, const bn128_G2 &g) +{ + bn128_G2 gcopy(g); + gcopy.to_affine_coordinates(); + + out << (gcopy.is_zero() ? '1' : '0') << OUTPUT_SEPARATOR; + +#ifdef NO_PT_COMPRESSION + /* no point compression case */ +#ifndef BINARY_OUTPUT + out << gcopy.coord[0].a_ << OUTPUT_SEPARATOR << gcopy.coord[0].b_ << OUTPUT_SEPARATOR; + out << gcopy.coord[1].a_ << OUTPUT_SEPARATOR << gcopy.coord[1].b_; +#else + out.write((char*) &gcopy.coord[0].a_, sizeof(gcopy.coord[0].a_)); + out.write((char*) &gcopy.coord[0].b_, sizeof(gcopy.coord[0].b_)); + out.write((char*) &gcopy.coord[1].a_, sizeof(gcopy.coord[1].a_)); + out.write((char*) &gcopy.coord[1].b_, sizeof(gcopy.coord[1].b_)); +#endif + +#else + /* point compression case */ +#ifndef BINARY_OUTPUT + out << gcopy.coord[0].a_ << OUTPUT_SEPARATOR << gcopy.coord[0].b_; +#else + out.write((char*) &gcopy.coord[0].a_, sizeof(gcopy.coord[0].a_)); + out.write((char*) &gcopy.coord[0].b_, sizeof(gcopy.coord[0].b_)); +#endif + out << OUTPUT_SEPARATOR << (((unsigned char*)&gcopy.coord[1].a_)[0] & 1 ? '1' : '0'); +#endif + + return out; +} + +std::istream& operator>>(std::istream &in, bn128_G2 &g) +{ + char is_zero; + in.read((char*)&is_zero, 1); // this reads is_zero; + is_zero -= '0'; + consume_OUTPUT_SEPARATOR(in); + +#ifdef NO_PT_COMPRESSION + /* no point compression case */ +#ifndef BINARY_OUTPUT + in >> g.coord[0].a_; + consume_OUTPUT_SEPARATOR(in); + in >> g.coord[0].b_; + consume_OUTPUT_SEPARATOR(in); + in >> g.coord[1].a_; + consume_OUTPUT_SEPARATOR(in); + in >> g.coord[1].b_; +#else + in.read((char*) &g.coord[0].a_, sizeof(g.coord[0].a_)); + in.read((char*) &g.coord[0].b_, sizeof(g.coord[0].b_)); + in.read((char*) &g.coord[1].a_, sizeof(g.coord[1].a_)); + in.read((char*) &g.coord[1].b_, sizeof(g.coord[1].b_)); +#endif + +#else + /* point compression case */ + bn::Fp2 tX; +#ifndef BINARY_OUTPUT + in >> tX.a_; + consume_OUTPUT_SEPARATOR(in); + in >> tX.b_; +#else + in.read((char*)&tX.a_, sizeof(tX.a_)); + in.read((char*)&tX.b_, sizeof(tX.b_)); +#endif + consume_OUTPUT_SEPARATOR(in); + unsigned char Y_lsb; + in.read((char*)&Y_lsb, 1); + Y_lsb -= '0'; + + // y = +/- sqrt(x^3 + b) + if (!is_zero) + { + g.coord[0] = tX; + bn::Fp2 tX2, tY2; + bn::Fp2::square(tX2, tX); + bn::Fp2::mul(tY2, tX2, tX); + bn::Fp2::add(tY2, tY2, bn128_twist_coeff_b); + + g.coord[1] = bn128_G2::sqrt(tY2); + if ((((unsigned char*)&g.coord[1].a_)[0] & 1) != Y_lsb) + { + bn::Fp2::neg(g.coord[1], g.coord[1]); + } + } +#endif + + /* finalize */ + if (!is_zero) + { + g.coord[2] = bn::Fp2(bn::Fp(1), bn::Fp(0)); + } + else + { + g = bn128_G2::zero(); + } + + return in; +} + +template<> +void batch_to_special_all_non_zeros(std::vector &vec) +{ + std::vector Z_vec; + Z_vec.reserve(vec.size()); + + for (auto &el: vec) + { + Z_vec.emplace_back(el.coord[2]); + } + bn_batch_invert(Z_vec); + + const bn::Fp2 one = 1; + + for (size_t i = 0; i < vec.size(); ++i) + { + bn::Fp2 Z2, Z3; + bn::Fp2::square(Z2, Z_vec[i]); + bn::Fp2::mul(Z3, Z2, Z_vec[i]); + + bn::Fp2::mul(vec[i].coord[0], vec[i].coord[0], Z2); + bn::Fp2::mul(vec[i].coord[1], vec[i].coord[1], Z3); + vec[i].coord[2] = one; + } +} + +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/bn128/bn128_g2.d b/privacy/zsl/zsl/algebra/curves/bn128/bn128_g2.d new file mode 100644 index 0000000..41aa77f --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/bn128/bn128_g2.d @@ -0,0 +1,16 @@ +src/algebra/curves/bn128/bn128_g2.o: \ + src/algebra/curves/bn128/bn128_g2.cpp \ + src/algebra/curves/bn128/bn128_g2.hpp \ + src/algebra/curves/bn128/bn128_init.hpp \ + src/algebra/curves/public_params.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc depinst/include/bn.h \ + depinst/include/zm2.h depinst/include/zm.h \ + src/algebra/curves/curve_utils.hpp src/algebra/curves/curve_utils.tcc \ + src/algebra/curves/bn128/bn_utils.hpp \ + src/algebra/curves/bn128/bn_utils.tcc diff --git a/privacy/zsl/zsl/algebra/curves/bn128/bn128_g2.hpp b/privacy/zsl/zsl/algebra/curves/bn128/bn128_g2.hpp new file mode 100644 index 0000000..dba9c6b --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/bn128/bn128_g2.hpp @@ -0,0 +1,92 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BN128_G2_HPP_ +#define BN128_G2_HPP_ +#include +#include +#include "algebra/curves/bn128/bn128_init.hpp" +#include "algebra/curves/curve_utils.hpp" +#include "bn.h" + +namespace libsnark { + +class bn128_G2; +std::ostream& operator<<(std::ostream &, const bn128_G2&); +std::istream& operator>>(std::istream &, bn128_G2&); + +class bn128_G2 { +private: + static bn::Fp2 sqrt(const bn::Fp2 &el); +public: +#ifdef PROFILE_OP_COUNTS + static long long add_cnt; + static long long dbl_cnt; +#endif + static std::vector wnaf_window_table; + static std::vector fixed_base_exp_window_table; + static bn128_G2 G2_zero; + static bn128_G2 G2_one; + + bn::Fp2 coord[3]; + bn128_G2(); + typedef bn128_Fq base_field; + typedef bn128_Fr scalar_field; + + void print() const; + void print_coordinates() const; + + void to_affine_coordinates(); + void to_special(); + bool is_special() const; + + bool is_zero() const; + + bool operator==(const bn128_G2 &other) const; + bool operator!=(const bn128_G2 &other) const; + + bn128_G2 operator+(const bn128_G2 &other) const; + bn128_G2 operator-() const; + bn128_G2 operator-(const bn128_G2 &other) const; + + bn128_G2 add(const bn128_G2 &other) const; + bn128_G2 mixed_add(const bn128_G2 &other) const; + bn128_G2 dbl() const; + + bool is_well_formed() const; + + static bn128_G2 zero(); + static bn128_G2 one(); + static bn128_G2 random_element(); + + static size_t size_in_bits() { return 2*base_field::size_in_bits() + 1; } + static bigint base_field_char() { return base_field::field_char(); } + static bigint order() { return scalar_field::field_char(); } + + friend std::ostream& operator<<(std::ostream &out, const bn128_G2 &g); + friend std::istream& operator>>(std::istream &in, bn128_G2 &g); +}; + +template +bn128_G2 operator*(const bigint &lhs, const bn128_G2 &rhs) +{ + return scalar_mul(rhs, lhs); +} + +template& modulus_p> +bn128_G2 operator*(const Fp_model &lhs, const bn128_G2 &rhs) +{ + return scalar_mul(rhs, lhs.as_bigint()); +} + +template +void batch_to_special_all_non_zeros(std::vector &vec); +template<> +void batch_to_special_all_non_zeros(std::vector &vec); + +} // libsnark +#endif // BN128_G2_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/bn128/bn128_gt.cpp b/privacy/zsl/zsl/algebra/curves/bn128/bn128_gt.cpp new file mode 100644 index 0000000..8c0d785 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/bn128/bn128_gt.cpp @@ -0,0 +1,70 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/bn128/bn128_gt.hpp" + +namespace libsnark { + +bn128_GT bn128_GT::GT_one; +bn128_GT::bn128_GT() +{ + this->elem.clear(); +} + +bool bn128_GT::operator==(const bn128_GT &other) const +{ + return (this->elem == other.elem); +} + +bool bn128_GT::operator!=(const bn128_GT& other) const +{ + return !(operator==(other)); +} + +bn128_GT bn128_GT::operator*(const bn128_GT &other) const +{ + bn128_GT result; + bn::Fp12::mul(result.elem, this->elem, other.elem); + return result; +} + +bn128_GT bn128_GT::unitary_inverse() const +{ + bn128_GT result(*this); + bn::Fp6::neg(result.elem.b_, result.elem.b_); + return result; +} + +bn128_GT bn128_GT::one() +{ + return GT_one; +} + +std::ostream& operator<<(std::ostream &out, const bn128_GT &g) +{ +#ifndef BINARY_OUTPUT + out << g.elem.a_ << OUTPUT_SEPARATOR << g.elem.b_; +#else + out.write((char*) &g.elem.a_, sizeof(g.elem.a_)); + out.write((char*) &g.elem.b_, sizeof(g.elem.b_)); +#endif + return out; +} + +std::istream& operator>>(std::istream &in, bn128_GT &g) +{ +#ifndef BINARY_OUTPUT + in >> g.elem.a_; + consume_OUTPUT_SEPARATOR(in); + in >> g.elem.b_; +#else + in.read((char*) &g.elem.a_, sizeof(g.elem.a_)); + in.read((char*) &g.elem.b_, sizeof(g.elem.b_)); +#endif + return in; +} +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/bn128/bn128_gt.d b/privacy/zsl/zsl/algebra/curves/bn128/bn128_gt.d new file mode 100644 index 0000000..444834a --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/bn128/bn128_gt.d @@ -0,0 +1,11 @@ +src/algebra/curves/bn128/bn128_gt.o: \ + src/algebra/curves/bn128/bn128_gt.cpp \ + src/algebra/curves/bn128/bn128_gt.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc depinst/include/bn.h \ + depinst/include/zm2.h depinst/include/zm.h diff --git a/privacy/zsl/zsl/algebra/curves/bn128/bn128_gt.hpp b/privacy/zsl/zsl/algebra/curves/bn128/bn128_gt.hpp new file mode 100644 index 0000000..bc08fa1 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/bn128/bn128_gt.hpp @@ -0,0 +1,55 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BN128_GT_HPP_ +#define BN128_GT_HPP_ +#include "algebra/fields/fp.hpp" +#include "algebra/fields/field_utils.hpp" +#include +#include "bn.h" + +namespace libsnark { + +class bn128_GT; +std::ostream& operator<<(std::ostream &, const bn128_GT&); +std::istream& operator>>(std::istream &, bn128_GT&); + +class bn128_GT { +public: + static bn128_GT GT_one; + bn::Fp12 elem; + + bn128_GT(); + bool operator==(const bn128_GT &other) const; + bool operator!=(const bn128_GT &other) const; + + bn128_GT operator*(const bn128_GT &other) const; + bn128_GT unitary_inverse() const; + + static bn128_GT one(); + + void print() { std::cout << this->elem << "\n"; }; + + friend std::ostream& operator<<(std::ostream &out, const bn128_GT &g); + friend std::istream& operator>>(std::istream &in, bn128_GT &g); +}; + +template +bn128_GT operator^(const bn128_GT &rhs, const bigint &lhs) +{ + return power(rhs, lhs); +} + + +template& modulus_p> +bn128_GT operator^(const bn128_GT &rhs, const Fp_model &lhs) +{ + return power(rhs, lhs.as_bigint()); +} + +} // libsnark +#endif // BN128_GT_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/bn128/bn128_init.cpp b/privacy/zsl/zsl/algebra/curves/bn128/bn128_init.cpp new file mode 100644 index 0000000..d9c005a --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/bn128/bn128_init.cpp @@ -0,0 +1,226 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/bn128/bn128_init.hpp" +#include "algebra/curves/bn128/bn128_g1.hpp" +#include "algebra/curves/bn128/bn128_g2.hpp" +#include "algebra/curves/bn128/bn128_gt.hpp" + +namespace libsnark { + +bigint bn128_modulus_r; +bigint bn128_modulus_q; + +bn::Fp bn128_coeff_b; +size_t bn128_Fq_s; +bn::Fp bn128_Fq_nqr_to_t; +mie::Vuint bn128_Fq_t_minus_1_over_2; + +bn::Fp2 bn128_twist_coeff_b; +size_t bn128_Fq2_s; +bn::Fp2 bn128_Fq2_nqr_to_t; +mie::Vuint bn128_Fq2_t_minus_1_over_2; + +void init_bn128_params() +{ + bn::Param::init(); // init ate-pairing library + + typedef bigint bigint_r; + typedef bigint bigint_q; + + assert(sizeof(mp_limb_t) == 8 || sizeof(mp_limb_t) == 4); // Montgomery assumes this + + /* parameters for scalar field Fr */ + bn128_modulus_r = bigint_r("21888242871839275222246405745257275088548364400416034343698204186575808495617"); + assert(bn128_Fr::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + bn128_Fr::Rsquared = bigint_r("944936681149208446651664254269745548490766851729442924617792859073125903783"); + bn128_Fr::Rcubed = bigint_r("5866548545943845227489894872040244720403868105578784105281690076696998248512"); + bn128_Fr::inv = 0xc2e1f593efffffff; + } + if (sizeof(mp_limb_t) == 4) + { + bn128_Fr::Rsquared = bigint_r("944936681149208446651664254269745548490766851729442924617792859073125903783"); + bn128_Fr::Rcubed = bigint_r("5866548545943845227489894872040244720403868105578784105281690076696998248512"); + bn128_Fr::inv = 0xefffffff; + } + bn128_Fr::num_bits = 254; + bn128_Fr::euler = bigint_r("10944121435919637611123202872628637544274182200208017171849102093287904247808"); + bn128_Fr::s = 28; + bn128_Fr::t = bigint_r("81540058820840996586704275553141814055101440848469862132140264610111"); + bn128_Fr::t_minus_1_over_2 = bigint_r("40770029410420498293352137776570907027550720424234931066070132305055"); + bn128_Fr::multiplicative_generator = bn128_Fr("5"); + bn128_Fr::root_of_unity = bn128_Fr("19103219067921713944291392827692070036145651957329286315305642004821462161904"); + bn128_Fr::nqr = bn128_Fr("5"); + bn128_Fr::nqr_to_t = bn128_Fr("19103219067921713944291392827692070036145651957329286315305642004821462161904"); + + /* parameters for base field Fq */ + bn128_modulus_q = bigint_q("21888242871839275222246405745257275088696311157297823662689037894645226208583"); + assert(bn128_Fq::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + bn128_Fq::Rsquared = bigint_q("3096616502983703923843567936837374451735540968419076528771170197431451843209"); + bn128_Fq::Rcubed = bigint_q("14921786541159648185948152738563080959093619838510245177710943249661917737183"); + bn128_Fq::inv = 0x87d20782e4866389; + } + if (sizeof(mp_limb_t) == 4) + { + bn128_Fq::Rsquared = bigint_q("3096616502983703923843567936837374451735540968419076528771170197431451843209"); + bn128_Fq::Rcubed = bigint_q("14921786541159648185948152738563080959093619838510245177710943249661917737183"); + bn128_Fq::inv = 0xe4866389; + } + bn128_Fq::num_bits = 254; + bn128_Fq::euler = bigint_q("10944121435919637611123202872628637544348155578648911831344518947322613104291"); + bn128_Fq::s = 1; + bn128_Fq::t = bigint_q("10944121435919637611123202872628637544348155578648911831344518947322613104291"); + bn128_Fq::t_minus_1_over_2 = bigint_q("5472060717959818805561601436314318772174077789324455915672259473661306552145"); + bn128_Fq::multiplicative_generator = bn128_Fq("3"); + bn128_Fq::root_of_unity = bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + bn128_Fq::nqr = bn128_Fq("3"); + bn128_Fq::nqr_to_t = bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + + /* additional parameters for square roots in Fq/Fq2 */ + bn128_coeff_b = bn::Fp(3); + bn128_Fq_s = 1; + bn128_Fq_nqr_to_t = bn::Fp("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + bn128_Fq_t_minus_1_over_2 = mie::Vuint("5472060717959818805561601436314318772174077789324455915672259473661306552145"); + + bn128_twist_coeff_b = bn::Fp2(bn::Fp("19485874751759354771024239261021720505790618469301721065564631296452457478373"), + bn::Fp("266929791119991161246907387137283842545076965332900288569378510910307636690")); + bn128_Fq2_s = 4; + bn128_Fq2_nqr_to_t = bn::Fp2(bn::Fp("5033503716262624267312492558379982687175200734934877598599011485707452665730"), + bn::Fp("314498342015008975724433667930697407966947188435857772134235984660852259084")); + bn128_Fq2_t_minus_1_over_2 = mie::Vuint("14971724250519463826312126413021210649976634891596900701138993820439690427699319920245032869357433499099632259837909383182382988566862092145199781964621"); + + /* choice of group G1 */ + bn128_G1::G1_zero.coord[0] = bn::Fp(1); + bn128_G1::G1_zero.coord[1] = bn::Fp(1); + bn128_G1::G1_zero.coord[2] = bn::Fp(0); + + bn128_G1::G1_one.coord[0] = bn::Fp(1); + bn128_G1::G1_one.coord[1] = bn::Fp(2); + bn128_G1::G1_one.coord[2] = bn::Fp(1); + + bn128_G1::wnaf_window_table.resize(0); + bn128_G1::wnaf_window_table.push_back(10); + bn128_G1::wnaf_window_table.push_back(24); + bn128_G1::wnaf_window_table.push_back(40); + bn128_G1::wnaf_window_table.push_back(132); + + bn128_G1::fixed_base_exp_window_table.resize(0); + // window 1 is unbeaten in [-inf, 4.24] + bn128_G1::fixed_base_exp_window_table.push_back(1); + // window 2 is unbeaten in [4.24, 10.43] + bn128_G1::fixed_base_exp_window_table.push_back(4); + // window 3 is unbeaten in [10.43, 24.88] + bn128_G1::fixed_base_exp_window_table.push_back(10); + // window 4 is unbeaten in [24.88, 62.10] + bn128_G1::fixed_base_exp_window_table.push_back(25); + // window 5 is unbeaten in [62.10, 157.80] + bn128_G1::fixed_base_exp_window_table.push_back(62); + // window 6 is unbeaten in [157.80, 362.05] + bn128_G1::fixed_base_exp_window_table.push_back(158); + // window 7 is unbeaten in [362.05, 806.67] + bn128_G1::fixed_base_exp_window_table.push_back(362); + // window 8 is unbeaten in [806.67, 2090.34] + bn128_G1::fixed_base_exp_window_table.push_back(807); + // window 9 is unbeaten in [2090.34, 4459.58] + bn128_G1::fixed_base_exp_window_table.push_back(2090); + // window 10 is unbeaten in [4459.58, 9280.12] + bn128_G1::fixed_base_exp_window_table.push_back(4460); + // window 11 is unbeaten in [9280.12, 43302.64] + bn128_G1::fixed_base_exp_window_table.push_back(9280); + // window 12 is unbeaten in [43302.64, 210998.73] + bn128_G1::fixed_base_exp_window_table.push_back(43303); + // window 13 is never the best + bn128_G1::fixed_base_exp_window_table.push_back(0); + // window 14 is never the best + bn128_G1::fixed_base_exp_window_table.push_back(0); + // window 15 is unbeaten in [210998.73, 506869.47] + bn128_G1::fixed_base_exp_window_table.push_back(210999); + // window 16 is unbeaten in [506869.47, 930023.36] + bn128_G1::fixed_base_exp_window_table.push_back(506869); + // window 17 is unbeaten in [930023.36, 8350812.20] + bn128_G1::fixed_base_exp_window_table.push_back(930023); + // window 18 is never the best + bn128_G1::fixed_base_exp_window_table.push_back(0); + // window 19 is never the best + bn128_G1::fixed_base_exp_window_table.push_back(0); + // window 20 is unbeaten in [8350812.20, 21708138.87] + bn128_G1::fixed_base_exp_window_table.push_back(8350812); + // window 21 is unbeaten in [21708138.87, 29482995.52] + bn128_G1::fixed_base_exp_window_table.push_back(21708139); + // window 22 is unbeaten in [29482995.52, inf] + bn128_G1::fixed_base_exp_window_table.push_back(29482996); + + /* choice of group G2 */ + bn128_G2::G2_zero.coord[0] = bn::Fp2(bn::Fp(1), bn::Fp(0)); + bn128_G2::G2_zero.coord[1] = bn::Fp2(bn::Fp(1), bn::Fp(0)); + bn128_G2::G2_zero.coord[2] = bn::Fp2(bn::Fp(0), bn::Fp(0)); + + bn128_G2::G2_one.coord[0] = bn::Fp2(bn::Fp("15267802884793550383558706039165621050290089775961208824303765753922461897946"), + bn::Fp("9034493566019742339402378670461897774509967669562610788113215988055021632533")); + bn128_G2::G2_one.coord[1] = bn::Fp2(bn::Fp("644888581738283025171396578091639672120333224302184904896215738366765861164"), + bn::Fp("20532875081203448695448744255224543661959516361327385779878476709582931298750")); + bn128_G2::G2_one.coord[2] = bn::Fp2(bn::Fp(1), bn::Fp(0)); + + bn128_G2::wnaf_window_table.resize(0); + bn128_G2::wnaf_window_table.push_back(7); + bn128_G2::wnaf_window_table.push_back(18); + bn128_G2::wnaf_window_table.push_back(35); + bn128_G2::wnaf_window_table.push_back(116); + + bn128_G2::fixed_base_exp_window_table.resize(0); + // window 1 is unbeaten in [-inf, 4.13] + bn128_G2::fixed_base_exp_window_table.push_back(1); + // window 2 is unbeaten in [4.13, 10.72] + bn128_G2::fixed_base_exp_window_table.push_back(4); + // window 3 is unbeaten in [10.72, 25.60] + bn128_G2::fixed_base_exp_window_table.push_back(11); + // window 4 is unbeaten in [25.60, 60.99] + bn128_G2::fixed_base_exp_window_table.push_back(26); + // window 5 is unbeaten in [60.99, 153.66] + bn128_G2::fixed_base_exp_window_table.push_back(61); + // window 6 is unbeaten in [153.66, 353.13] + bn128_G2::fixed_base_exp_window_table.push_back(154); + // window 7 is unbeaten in [353.13, 771.87] + bn128_G2::fixed_base_exp_window_table.push_back(353); + // window 8 is unbeaten in [771.87, 2025.85] + bn128_G2::fixed_base_exp_window_table.push_back(772); + // window 9 is unbeaten in [2025.85, 4398.65] + bn128_G2::fixed_base_exp_window_table.push_back(2026); + // window 10 is unbeaten in [4398.65, 10493.42] + bn128_G2::fixed_base_exp_window_table.push_back(4399); + // window 11 is unbeaten in [10493.42, 37054.73] + bn128_G2::fixed_base_exp_window_table.push_back(10493); + // window 12 is unbeaten in [37054.73, 49928.78] + bn128_G2::fixed_base_exp_window_table.push_back(37055); + // window 13 is unbeaten in [49928.78, 114502.82] + bn128_G2::fixed_base_exp_window_table.push_back(49929); + // window 14 is unbeaten in [114502.82, 161445.26] + bn128_G2::fixed_base_exp_window_table.push_back(114503); + // window 15 is unbeaten in [161445.26, 470648.01] + bn128_G2::fixed_base_exp_window_table.push_back(161445); + // window 16 is unbeaten in [470648.01, 1059821.87] + bn128_G2::fixed_base_exp_window_table.push_back(470648); + // window 17 is unbeaten in [1059821.87, 5450848.25] + bn128_G2::fixed_base_exp_window_table.push_back(1059822); + // window 18 is never the best + bn128_G2::fixed_base_exp_window_table.push_back(0); + // window 19 is unbeaten in [5450848.25, 5566795.57] + bn128_G2::fixed_base_exp_window_table.push_back(5450848); + // window 20 is unbeaten in [5566795.57, 33055217.52] + bn128_G2::fixed_base_exp_window_table.push_back(5566796); + // window 21 is never the best + bn128_G2::fixed_base_exp_window_table.push_back(0); + // window 22 is unbeaten in [33055217.52, inf] + bn128_G2::fixed_base_exp_window_table.push_back(33055218); + + bn128_GT::GT_one.elem = bn::Fp12(1); +} +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/bn128/bn128_init.d b/privacy/zsl/zsl/algebra/curves/bn128/bn128_init.d new file mode 100644 index 0000000..a30d8b4 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/bn128/bn128_init.d @@ -0,0 +1,15 @@ +src/algebra/curves/bn128/bn128_init.o: \ + src/algebra/curves/bn128/bn128_init.cpp \ + src/algebra/curves/bn128/bn128_init.hpp \ + src/algebra/curves/public_params.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc depinst/include/bn.h \ + depinst/include/zm2.h depinst/include/zm.h \ + src/algebra/curves/bn128/bn128_g1.hpp src/algebra/curves/curve_utils.hpp \ + src/algebra/curves/curve_utils.tcc src/algebra/curves/bn128/bn128_g2.hpp \ + src/algebra/curves/bn128/bn128_gt.hpp diff --git a/privacy/zsl/zsl/algebra/curves/bn128/bn128_init.hpp b/privacy/zsl/zsl/algebra/curves/bn128/bn128_init.hpp new file mode 100644 index 0000000..ddb5c62 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/bn128/bn128_init.hpp @@ -0,0 +1,46 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BN128_INIT_HPP_ +#define BN128_INIT_HPP_ +#include "algebra/curves/public_params.hpp" +#include "algebra/fields/fp.hpp" +#include "bn.h" // If you're missing this file, run libsnark's ./prepare-depends.sh + +namespace libsnark { + +const mp_size_t bn128_r_bitcount = 254; +const mp_size_t bn128_q_bitcount = 254; + +const mp_size_t bn128_r_limbs = (bn128_r_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; +const mp_size_t bn128_q_limbs = (bn128_q_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; + +extern bigint bn128_modulus_r; +extern bigint bn128_modulus_q; + +extern bn::Fp bn128_coeff_b; +extern size_t bn128_Fq_s; +extern bn::Fp bn128_Fq_nqr_to_t; +extern mie::Vuint bn128_Fq_t_minus_1_over_2; + +extern bn::Fp2 bn128_twist_coeff_b; +extern size_t bn128_Fq2_s; +extern bn::Fp2 bn128_Fq2_nqr_to_t; +extern mie::Vuint bn128_Fq2_t_minus_1_over_2; + +typedef Fp_model bn128_Fr; +typedef Fp_model bn128_Fq; + +void init_bn128_params(); + +class bn128_G1; +class bn128_G2; +class bn128_GT; +typedef bn128_GT bn128_Fq12; + +} // libsnark +#endif // BN128_INIT_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/bn128/bn128_pairing.cpp b/privacy/zsl/zsl/algebra/curves/bn128/bn128_pairing.cpp new file mode 100644 index 0000000..ac4290a --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/bn128/bn128_pairing.cpp @@ -0,0 +1,212 @@ +/** @file + ******************************************************************************** + Implements functions for computing Ate pairings over the bn128 curves, split into a + offline and online stages. + ******************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *******************************************************************************/ + +#include + +#include "algebra/curves/bn128/bn128_pairing.hpp" +#include "common/profiling.hpp" +#include "algebra/curves/bn128/bn128_init.hpp" +#include "algebra/curves/bn128/bn128_g1.hpp" +#include "algebra/curves/bn128/bn128_g2.hpp" +#include "algebra/curves/bn128/bn128_gt.hpp" + +namespace libsnark { + +bool bn128_ate_G1_precomp::operator==(const bn128_ate_G1_precomp &other) const +{ + return (this->P[0] == other.P[0] && + this->P[1] == other.P[1] && + this->P[2] == other.P[2]); +} + +std::ostream& operator<<(std::ostream &out, const bn128_ate_G1_precomp &prec_P) +{ + for (size_t i = 0; i < 3; ++i) + { +#ifndef BINARY_OUTPUT + out << prec_P.P[i] << "\n"; +#else + out.write((char*) &prec_P.P[i], sizeof(prec_P.P[i])); +#endif + } + return out; +} + +std::istream& operator>>(std::istream &in, bn128_ate_G1_precomp &prec_P) +{ + for (size_t i = 0; i < 3; ++i) + { +#ifndef BINARY_OUTPUT + in >> prec_P.P[i]; + consume_newline(in); +#else + in.read((char*) &prec_P.P[i], sizeof(prec_P.P[i])); +#endif + } + return in; +} + +bool bn128_ate_G2_precomp::operator==(const bn128_ate_G2_precomp &other) const +{ + if (!(this->Q[0] == other.Q[0] && + this->Q[1] == other.Q[1] && + this->Q[2] == other.Q[2] && + this->coeffs.size() == other.coeffs.size())) + { + return false; + } + + /* work around for upstream serialization bug */ + for (size_t i = 0; i < this->coeffs.size(); ++i) + { + std::stringstream this_ss, other_ss; + this_ss << this->coeffs[i]; + other_ss << other.coeffs[i]; + if (this_ss.str() != other_ss.str()) + { + return false; + } + } + + return true; +} + +std::ostream& operator<<(std::ostream &out, const bn128_ate_G2_precomp &prec_Q) +{ + for (size_t i = 0; i < 3; ++i) + { +#ifndef BINARY_OUTPUT + out << prec_Q.Q[i].a_ << "\n"; + out << prec_Q.Q[i].b_ << "\n"; +#else + out.write((char*) &prec_Q.Q[i].a_, sizeof(prec_Q.Q[i].a_)); + out.write((char*) &prec_Q.Q[i].b_, sizeof(prec_Q.Q[i].b_)); +#endif + } + + out << prec_Q.coeffs.size() << "\n"; + + for (size_t i = 0; i < prec_Q.coeffs.size(); ++i) + { +#ifndef BINARY_OUTPUT + out << prec_Q.coeffs[i].a_.a_ << "\n"; + out << prec_Q.coeffs[i].a_.b_ << "\n"; + out << prec_Q.coeffs[i].b_.a_ << "\n"; + out << prec_Q.coeffs[i].b_.b_ << "\n"; + out << prec_Q.coeffs[i].c_.a_ << "\n"; + out << prec_Q.coeffs[i].c_.b_ << "\n"; +#else + out.write((char*) &prec_Q.coeffs[i].a_.a_, sizeof(prec_Q.coeffs[i].a_.a_)); + out.write((char*) &prec_Q.coeffs[i].a_.b_, sizeof(prec_Q.coeffs[i].a_.b_)); + out.write((char*) &prec_Q.coeffs[i].b_.a_, sizeof(prec_Q.coeffs[i].b_.a_)); + out.write((char*) &prec_Q.coeffs[i].b_.b_, sizeof(prec_Q.coeffs[i].b_.b_)); + out.write((char*) &prec_Q.coeffs[i].c_.a_, sizeof(prec_Q.coeffs[i].c_.a_)); + out.write((char*) &prec_Q.coeffs[i].c_.b_, sizeof(prec_Q.coeffs[i].c_.b_)); +#endif + } + + return out; +} + +std::istream& operator>>(std::istream &in, bn128_ate_G2_precomp &prec_Q) +{ + for (size_t i = 0; i < 3; ++i) + { +#ifndef BINARY_OUTPUT + in >> prec_Q.Q[i].a_; + consume_newline(in); + in >> prec_Q.Q[i].b_; + consume_newline(in); +#else + in.read((char*) &prec_Q.Q[i].a_, sizeof(prec_Q.Q[i].a_)); + in.read((char*) &prec_Q.Q[i].b_, sizeof(prec_Q.Q[i].b_)); +#endif + } + + size_t count; + in >> count; + consume_newline(in); + prec_Q.coeffs.resize(count); + for (size_t i = 0; i < count; ++i) + { +#ifndef BINARY_OUTPUT + in >> prec_Q.coeffs[i].a_.a_; + consume_newline(in); + in >> prec_Q.coeffs[i].a_.b_; + consume_newline(in); + in >> prec_Q.coeffs[i].b_.a_; + consume_newline(in); + in >> prec_Q.coeffs[i].b_.b_; + consume_newline(in); + in >> prec_Q.coeffs[i].c_.a_; + consume_newline(in); + in >> prec_Q.coeffs[i].c_.b_; + consume_newline(in); +#else + in.read((char*) &prec_Q.coeffs[i].a_.a_, sizeof(prec_Q.coeffs[i].a_.a_)); + in.read((char*) &prec_Q.coeffs[i].a_.b_, sizeof(prec_Q.coeffs[i].a_.b_)); + in.read((char*) &prec_Q.coeffs[i].b_.a_, sizeof(prec_Q.coeffs[i].b_.a_)); + in.read((char*) &prec_Q.coeffs[i].b_.b_, sizeof(prec_Q.coeffs[i].b_.b_)); + in.read((char*) &prec_Q.coeffs[i].c_.a_, sizeof(prec_Q.coeffs[i].c_.a_)); + in.read((char*) &prec_Q.coeffs[i].c_.b_, sizeof(prec_Q.coeffs[i].c_.b_)); +#endif + } + return in; +} + +bn128_ate_G1_precomp bn128_ate_precompute_G1(const bn128_G1& P) +{ + enter_block("Call to bn128_ate_precompute_G1"); + + bn128_ate_G1_precomp result; + bn::ecop::NormalizeJac(result.P, P.coord); + + leave_block("Call to bn128_ate_precompute_G1"); + return result; +} + +bn128_ate_G2_precomp bn128_ate_precompute_G2(const bn128_G2& Q) +{ + enter_block("Call to bn128_ate_precompute_G2"); + + bn128_ate_G2_precomp result; + bn::components::precomputeG2(result.coeffs, result.Q, Q.coord); + + leave_block("Call to bn128_ate_precompute_G2"); + return result; +} + +bn128_Fq12 bn128_ate_miller_loop(const bn128_ate_G1_precomp &prec_P, + const bn128_ate_G2_precomp &prec_Q) +{ + bn128_Fq12 f; + bn::components::millerLoop(f.elem, prec_Q.coeffs, prec_P.P); + return f; +} + +bn128_Fq12 bn128_double_ate_miller_loop(const bn128_ate_G1_precomp &prec_P1, + const bn128_ate_G2_precomp &prec_Q1, + const bn128_ate_G1_precomp &prec_P2, + const bn128_ate_G2_precomp &prec_Q2) +{ + bn128_Fq12 f; + bn::components::millerLoop2(f.elem, prec_Q1.coeffs, prec_P1.P, prec_Q2.coeffs, prec_P2.P); + return f; +} + +bn128_GT bn128_final_exponentiation(const bn128_Fq12 &elt) +{ + enter_block("Call to bn128_final_exponentiation"); + bn128_GT eltcopy = elt; + eltcopy.elem.final_exp(); + leave_block("Call to bn128_final_exponentiation"); + return eltcopy; +} +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/bn128/bn128_pairing.d b/privacy/zsl/zsl/algebra/curves/bn128/bn128_pairing.d new file mode 100644 index 0000000..cdcc39b --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/bn128/bn128_pairing.d @@ -0,0 +1,17 @@ +src/algebra/curves/bn128/bn128_pairing.o: \ + src/algebra/curves/bn128/bn128_pairing.cpp \ + src/algebra/curves/bn128/bn128_pairing.hpp \ + src/algebra/curves/bn128/bn128_g1.hpp \ + src/algebra/curves/bn128/bn128_init.hpp \ + src/algebra/curves/public_params.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc depinst/include/bn.h \ + depinst/include/zm2.h depinst/include/zm.h \ + src/algebra/curves/curve_utils.hpp src/algebra/curves/curve_utils.tcc \ + src/algebra/curves/bn128/bn128_g2.hpp \ + src/algebra/curves/bn128/bn128_gt.hpp src/common/profiling.hpp diff --git a/privacy/zsl/zsl/algebra/curves/bn128/bn128_pairing.hpp b/privacy/zsl/zsl/algebra/curves/bn128/bn128_pairing.hpp new file mode 100644 index 0000000..f639d0a --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/bn128/bn128_pairing.hpp @@ -0,0 +1,52 @@ +/** @file + ******************************************************************************** + Declares functions for computing Ate pairings over the bn128 curves, split into a + offline and online stages. + ******************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *******************************************************************************/ + +#ifndef BN128_PAIRING_HPP_ +#define BN128_PAIRING_HPP_ +#include "algebra/curves/bn128/bn128_g1.hpp" +#include "algebra/curves/bn128/bn128_g2.hpp" +#include "algebra/curves/bn128/bn128_gt.hpp" +#include "bn.h" + +namespace libsnark { + +struct bn128_ate_G1_precomp { + bn::Fp P[3]; + + bool operator==(const bn128_ate_G1_precomp &other) const; + friend std::ostream& operator<<(std::ostream &out, const bn128_ate_G1_precomp &prec_P); + friend std::istream& operator>>(std::istream &in, bn128_ate_G1_precomp &prec_P); +}; + +typedef bn::Fp6 bn128_ate_ell_coeffs; + +struct bn128_ate_G2_precomp { + bn::Fp2 Q[3]; + std::vector coeffs; + + bool operator==(const bn128_ate_G2_precomp &other) const; + friend std::ostream& operator<<(std::ostream &out, const bn128_ate_G2_precomp &prec_Q); + friend std::istream& operator>>(std::istream &in, bn128_ate_G2_precomp &prec_Q); +}; + +bn128_ate_G1_precomp bn128_ate_precompute_G1(const bn128_G1& P); +bn128_ate_G2_precomp bn128_ate_precompute_G2(const bn128_G2& Q); + +bn128_Fq12 bn128_double_ate_miller_loop(const bn128_ate_G1_precomp &prec_P1, + const bn128_ate_G2_precomp &prec_Q1, + const bn128_ate_G1_precomp &prec_P2, + const bn128_ate_G2_precomp &prec_Q2); +bn128_Fq12 bn128_ate_miller_loop(const bn128_ate_G1_precomp &prec_P, + const bn128_ate_G2_precomp &prec_Q); + +bn128_GT bn128_final_exponentiation(const bn128_Fq12 &elt); + +} // libsnark +#endif // BN128_PAIRING_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/bn128/bn128_pp.cpp b/privacy/zsl/zsl/algebra/curves/bn128/bn128_pp.cpp new file mode 100644 index 0000000..6557f04 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/bn128/bn128_pp.cpp @@ -0,0 +1,75 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/bn128/bn128_pp.hpp" +#include "common/profiling.hpp" + +namespace libsnark { + +void bn128_pp::init_public_params() +{ + init_bn128_params(); +} + +bn128_GT bn128_pp::final_exponentiation(const bn128_GT &elt) +{ + return bn128_final_exponentiation(elt); +} + +bn128_ate_G1_precomp bn128_pp::precompute_G1(const bn128_G1 &P) +{ + return bn128_ate_precompute_G1(P); +} + +bn128_ate_G2_precomp bn128_pp::precompute_G2(const bn128_G2 &Q) +{ + return bn128_ate_precompute_G2(Q); +} + +bn128_Fq12 bn128_pp::miller_loop(const bn128_ate_G1_precomp &prec_P, + const bn128_ate_G2_precomp &prec_Q) +{ + enter_block("Call to miller_loop"); + bn128_Fq12 result = bn128_ate_miller_loop(prec_P, prec_Q); + leave_block("Call to miller_loop"); + return result; +} + +bn128_Fq12 bn128_pp::double_miller_loop(const bn128_ate_G1_precomp &prec_P1, + const bn128_ate_G2_precomp &prec_Q1, + const bn128_ate_G1_precomp &prec_P2, + const bn128_ate_G2_precomp &prec_Q2) +{ + enter_block("Call to double_miller_loop"); + bn128_Fq12 result = bn128_double_ate_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); + leave_block("Call to double_miller_loop"); + return result; +} + +bn128_Fq12 bn128_pp::pairing(const bn128_G1 &P, + const bn128_G2 &Q) +{ + enter_block("Call to pairing"); + bn128_ate_G1_precomp prec_P = bn128_pp::precompute_G1(P); + bn128_ate_G2_precomp prec_Q = bn128_pp::precompute_G2(Q); + + bn128_Fq12 result = bn128_pp::miller_loop(prec_P, prec_Q); + leave_block("Call to pairing"); + return result; +} + +bn128_GT bn128_pp::reduced_pairing(const bn128_G1 &P, + const bn128_G2 &Q) +{ + enter_block("Call to reduced_pairing"); + const bn128_Fq12 f = bn128_pp::pairing(P, Q); + const bn128_GT result = bn128_pp::final_exponentiation(f); + leave_block("Call to reduced_pairing"); + return result; +} + +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/bn128/bn128_pp.d b/privacy/zsl/zsl/algebra/curves/bn128/bn128_pp.d new file mode 100644 index 0000000..28f476f --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/bn128/bn128_pp.d @@ -0,0 +1,17 @@ +src/algebra/curves/bn128/bn128_pp.o: \ + src/algebra/curves/bn128/bn128_pp.cpp \ + src/algebra/curves/bn128/bn128_pp.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/bn128/bn128_init.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc depinst/include/bn.h \ + depinst/include/zm2.h depinst/include/zm.h \ + src/algebra/curves/bn128/bn128_g1.hpp src/algebra/curves/curve_utils.hpp \ + src/algebra/curves/curve_utils.tcc src/algebra/curves/bn128/bn128_g2.hpp \ + src/algebra/curves/bn128/bn128_gt.hpp \ + src/algebra/curves/bn128/bn128_pairing.hpp src/common/profiling.hpp diff --git a/privacy/zsl/zsl/algebra/curves/bn128/bn128_pp.hpp b/privacy/zsl/zsl/algebra/curves/bn128/bn128_pp.hpp new file mode 100644 index 0000000..dfd1c6b --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/bn128/bn128_pp.hpp @@ -0,0 +1,51 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BN128_PP_HPP_ +#define BN128_PP_HPP_ +#include "algebra/curves/public_params.hpp" +#include "algebra/curves/bn128/bn128_init.hpp" +#include "algebra/curves/bn128/bn128_g1.hpp" +#include "algebra/curves/bn128/bn128_g2.hpp" +#include "algebra/curves/bn128/bn128_gt.hpp" +#include "algebra/curves/bn128/bn128_pairing.hpp" + +namespace libsnark { + +class bn128_pp { +public: + typedef bn128_Fr Fp_type; + typedef bn128_G1 G1_type; + typedef bn128_G2 G2_type; + typedef bn128_ate_G1_precomp G1_precomp_type; + typedef bn128_ate_G2_precomp G2_precomp_type; + typedef bn128_Fq Fq_type; + typedef bn128_Fq12 Fqk_type; + typedef bn128_GT GT_type; + + static const bool has_affine_pairing = false; + + static void init_public_params(); + static bn128_GT final_exponentiation(const bn128_Fq12 &elt); + static bn128_ate_G1_precomp precompute_G1(const bn128_G1 &P); + static bn128_ate_G2_precomp precompute_G2(const bn128_G2 &Q); + static bn128_Fq12 miller_loop(const bn128_ate_G1_precomp &prec_P, + const bn128_ate_G2_precomp &prec_Q); + static bn128_Fq12 double_miller_loop(const bn128_ate_G1_precomp &prec_P1, + const bn128_ate_G2_precomp &prec_Q1, + const bn128_ate_G1_precomp &prec_P2, + const bn128_ate_G2_precomp &prec_Q2); + + /* the following are used in test files */ + static bn128_GT pairing(const bn128_G1 &P, + const bn128_G2 &Q); + static bn128_GT reduced_pairing(const bn128_G1 &P, + const bn128_G2 &Q); +}; + +} // libsnark +#endif // BN128_PP_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/bn128/bn_utils.hpp b/privacy/zsl/zsl/algebra/curves/bn128/bn_utils.hpp new file mode 100644 index 0000000..d6caf43 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/bn128/bn_utils.hpp @@ -0,0 +1,22 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BN_UTILS_HPP_ +#define BN_UTILS_HPP_ +#include +#include "bn.h" + +namespace libsnark { + +template +void bn_batch_invert(std::vector &vec); + +} // libsnark + +#include "algebra/curves/bn128/bn_utils.tcc" + +#endif // BN_UTILS_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/bn128/bn_utils.tcc b/privacy/zsl/zsl/algebra/curves/bn128/bn_utils.tcc new file mode 100644 index 0000000..931dac4 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/bn128/bn_utils.tcc @@ -0,0 +1,40 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BN_UTILS_TCC_ +#define BN_UTILS_TCC_ + +namespace libsnark { + +template +void bn_batch_invert(std::vector &vec) +{ + std::vector prod; + prod.reserve(vec.size()); + + FieldT acc = 1; + + for (auto el : vec) + { + assert(!el.isZero()); + prod.emplace_back(acc); + FieldT::mul(acc, acc, el); + } + + FieldT acc_inverse = acc; + acc_inverse.inverse(); + + for (long i = vec.size()-1; i >= 0; --i) + { + const FieldT old_el = vec[i]; + FieldT::mul(vec[i], acc_inverse, prod[i]); + FieldT::mul(acc_inverse, acc_inverse, old_el); + } +} + +} // libsnark +#endif // FIELD_UTILS_TCC_ diff --git a/privacy/zsl/zsl/algebra/curves/curve_utils.hpp b/privacy/zsl/zsl/algebra/curves/curve_utils.hpp new file mode 100644 index 0000000..33a8e1e --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/curve_utils.hpp @@ -0,0 +1,22 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef CURVE_UTILS_HPP_ +#define CURVE_UTILS_HPP_ +#include + +#include "algebra/fields/bigint.hpp" + +namespace libsnark { + +template +GroupT scalar_mul(const GroupT &base, const bigint &scalar); + +} // libsnark +#include "algebra/curves/curve_utils.tcc" + +#endif // CURVE_UTILS_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/curve_utils.tcc b/privacy/zsl/zsl/algebra/curves/curve_utils.tcc new file mode 100644 index 0000000..251d75d --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/curve_utils.tcc @@ -0,0 +1,37 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef CURVE_UTILS_TCC_ +#define CURVE_UTILS_TCC_ + +namespace libsnark { + +template +GroupT scalar_mul(const GroupT &base, const bigint &scalar) +{ + GroupT result = GroupT::zero(); + + bool found_one = false; + for (long i = scalar.max_bits() - 1; i >= 0; --i) + { + if (found_one) + { + result = result.dbl(); + } + + if (scalar.test_bit(i)) + { + found_one = true; + result = result + base; + } + } + + return result; +} + +} // libsnark +#endif // CURVE_UTILS_TCC_ diff --git a/privacy/zsl/zsl/algebra/curves/edwards/edwards_g1.cpp b/privacy/zsl/zsl/algebra/curves/edwards/edwards_g1.cpp new file mode 100644 index 0000000..7d507fe --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/edwards/edwards_g1.cpp @@ -0,0 +1,413 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/edwards/edwards_g1.hpp" + +namespace libsnark { + +#ifdef PROFILE_OP_COUNTS +long long edwards_G1::add_cnt = 0; +long long edwards_G1::dbl_cnt = 0; +#endif + +std::vector edwards_G1::wnaf_window_table; +std::vector edwards_G1::fixed_base_exp_window_table; +edwards_G1 edwards_G1::G1_zero; +edwards_G1 edwards_G1::G1_one; + +edwards_G1::edwards_G1() +{ + this->X = G1_zero.X; + this->Y = G1_zero.Y; + this->Z = G1_zero.Z; +} + +void edwards_G1::print() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + edwards_G1 copy(*this); + copy.to_affine_coordinates(); + gmp_printf("(%Nd , %Nd)\n", + copy.X.as_bigint().data, edwards_Fq::num_limbs, + copy.Y.as_bigint().data, edwards_Fq::num_limbs); + } +} + +void edwards_G1::print_coordinates() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + gmp_printf("(%Nd : %Nd : %Nd)\n", + this->X.as_bigint().data, edwards_Fq::num_limbs, + this->Y.as_bigint().data, edwards_Fq::num_limbs, + this->Z.as_bigint().data, edwards_Fq::num_limbs); + } +} + +void edwards_G1::to_affine_coordinates() +{ + if (this->is_zero()) + { + this->X = edwards_Fq::zero(); + this->Y = edwards_Fq::one(); + this->Z = edwards_Fq::one(); + } + else + { + // go from inverted coordinates to projective coordinates + edwards_Fq tX = this->Y * this->Z; + edwards_Fq tY = this->X * this->Z; + edwards_Fq tZ = this->X * this->Y; + // go from projective coordinates to affine coordinates + edwards_Fq tZ_inv = tZ.inverse(); + this->X = tX * tZ_inv; + this->Y = tY * tZ_inv; + this->Z = edwards_Fq::one(); + } +} + +void edwards_G1::to_special() +{ + if (this->Z.is_zero()) + { + return; + } + +#ifdef DEBUG + const edwards_G1 copy(*this); +#endif + + edwards_Fq Z_inv = this->Z.inverse(); + this->X = this->X * Z_inv; + this->Y = this->Y * Z_inv; + this->Z = edwards_Fq::one(); + +#ifdef DEBUG + assert((*this) == copy); +#endif +} + +bool edwards_G1::is_special() const +{ + return (this->is_zero() || this->Z == edwards_Fq::one()); +} + +bool edwards_G1::is_zero() const +{ + return (this->Y.is_zero() && this->Z.is_zero()); +} + +bool edwards_G1::operator==(const edwards_G1 &other) const +{ + if (this->is_zero()) + { + return other.is_zero(); + } + + if (other.is_zero()) + { + return false; + } + + /* now neither is O */ + + // X1/Z1 = X2/Z2 <=> X1*Z2 = X2*Z1 + if ((this->X * other.Z) != (other.X * this->Z)) + { + return false; + } + + // Y1/Z1 = Y2/Z2 <=> Y1*Z2 = Y2*Z1 + if ((this->Y * other.Z) != (other.Y * this->Z)) + { + return false; + } + + return true; +} + +bool edwards_G1::operator!=(const edwards_G1& other) const +{ + return !(operator==(other)); +} + +edwards_G1 edwards_G1::operator+(const edwards_G1 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return (*this); + } + + return this->add(other); +} + +edwards_G1 edwards_G1::operator-() const +{ + return edwards_G1(-(this->X), this->Y, this->Z); +} + + +edwards_G1 edwards_G1::operator-(const edwards_G1 &other) const +{ + return (*this) + (-other); +} + +edwards_G1 edwards_G1::add(const edwards_G1 &other) const +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-edwards-inverted.html#addition-add-2007-bl + + edwards_Fq A = (this->Z) * (other.Z); // A = Z1*Z2 + edwards_Fq B = edwards_coeff_d * A.squared(); // B = d*A^2 + edwards_Fq C = (this->X) * (other.X); // C = X1*X2 + edwards_Fq D = (this->Y) * (other.Y); // D = Y1*Y2 + edwards_Fq E = C * D; // E = C*D + edwards_Fq H = C - D; // H = C-D + edwards_Fq I = (this->X+this->Y)*(other.X+other.Y)-C-D; // I = (X1+Y1)*(X2+Y2)-C-D + edwards_Fq X3 = (E+B)*H; // X3 = c*(E+B)*H + edwards_Fq Y3 = (E-B)*I; // Y3 = c*(E-B)*I + edwards_Fq Z3 = A*H*I; // Z3 = A*H*I + + return edwards_G1(X3, Y3, Z3); +} + +edwards_G1 edwards_G1::mixed_add(const edwards_G1 &other) const +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + +#ifdef DEBUG + assert(other.is_special()); +#endif + + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-edwards-inverted.html#addition-madd-2007-lb + + edwards_Fq A = this->Z; // A = Z1 + edwards_Fq B = edwards_coeff_d * A.squared(); // B = d*A^2 + edwards_Fq C = (this->X) * (other.X); // C = X1*X2 + edwards_Fq D = (this->Y) * (other.Y); // D = Y1*Y2 + edwards_Fq E = C * D; // E = C*D + edwards_Fq H = C - D; // H = C-D + edwards_Fq I = (this->X+this->Y)*(other.X+other.Y)-C-D; // I = (X1+Y1)*(X2+Y2)-C-D + edwards_Fq X3 = (E+B)*H; // X3 = c*(E+B)*H + edwards_Fq Y3 = (E-B)*I; // Y3 = c*(E-B)*I + edwards_Fq Z3 = A*H*I; // Z3 = A*H*I + + return edwards_G1(X3, Y3, Z3); +} + +edwards_G1 edwards_G1::dbl() const +{ +#ifdef PROFILE_OP_COUNTS + this->dbl_cnt++; +#endif + if (this->is_zero()) + { + return (*this); + } + else + { + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-edwards-inverted.html#doubling-dbl-2007-bl + + edwards_Fq A = (this->X).squared(); // A = X1^2 + edwards_Fq B = (this->Y).squared(); // B = Y1^2 + edwards_Fq C = A+B; // C = A+B + edwards_Fq D = A-B; // D = A-B + edwards_Fq E = (this->X+this->Y).squared()-C; // E = (X1+Y1)^2-C + edwards_Fq X3 = C*D; // X3 = C*D + edwards_Fq dZZ = edwards_coeff_d * this->Z.squared(); + edwards_Fq Y3 = E*(C-dZZ-dZZ); // Y3 = E*(C-2*d*Z1^2) + edwards_Fq Z3 = D*E; // Z3 = D*E + + return edwards_G1(X3, Y3, Z3); + } +} + +bool edwards_G1::is_well_formed() const +{ + /* Note that point at infinity is the only special case we must check as + inverted representation does no cover points (0, +-c) and (+-c, 0). */ + if (this->is_zero()) + { + return true; + } + else + { + /* + a x^2 + y^2 = 1 + d x^2 y^2 + + We are using inverted, so equation we need to check is actually + + a (z/x)^2 + (z/y)^2 = 1 + d z^4 / (x^2 * y^2) + z^2 (a y^2 + x^2 - dz^2) = x^2 y^2 + */ + edwards_Fq X2 = this->X.squared(); + edwards_Fq Y2 = this->Y.squared(); + edwards_Fq Z2 = this->Z.squared(); + + // for G1 a = 1 + return (Z2 * (Y2 + X2 - edwards_coeff_d * Z2) == X2 * Y2); + } +} + +edwards_G1 edwards_G1::zero() +{ + return G1_zero; +} + +edwards_G1 edwards_G1::one() +{ + return G1_one; +} + +edwards_G1 edwards_G1::random_element() +{ + return edwards_Fr::random_element().as_bigint() * G1_one; +} + +std::ostream& operator<<(std::ostream &out, const edwards_G1 &g) +{ + edwards_G1 copy(g); + copy.to_affine_coordinates(); +#ifdef NO_PT_COMPRESSION + out << copy.X << OUTPUT_SEPARATOR << copy.Y; +#else + /* storing LSB of Y */ + out << copy.X << OUTPUT_SEPARATOR << (copy.Y.as_bigint().data[0] & 1); +#endif + + return out; +} + +std::istream& operator>>(std::istream &in, edwards_G1 &g) +{ + edwards_Fq tX, tY; + +#ifdef NO_PT_COMPRESSION + in >> tX; + consume_OUTPUT_SEPARATOR(in); + in >> tY; +#else + /* + a x^2 + y^2 = 1 + d x^2 y^2 + y = sqrt((1-ax^2)/(1-dx^2)) + */ + unsigned char Y_lsb; + in >> tX; + + consume_OUTPUT_SEPARATOR(in); + in.read((char*)&Y_lsb, 1); + Y_lsb -= '0'; + + edwards_Fq tX2 = tX.squared(); + edwards_Fq tY2 = (edwards_Fq::one() - tX2) * // a = 1 for G1 (not a twist) + (edwards_Fq::one() - edwards_coeff_d * tX2).inverse(); + tY = tY2.sqrt(); + + if ((tY.as_bigint().data[0] & 1) != Y_lsb) + { + tY = -tY; + } +#endif + + // using inverted coordinates + g.X = tY; + g.Y = tX; + g.Z = tX * tY; + +#ifdef USE_MIXED_ADDITION + g.to_special(); +#endif + + return in; +} + +std::ostream& operator<<(std::ostream& out, const std::vector &v) +{ + out << v.size() << "\n"; + for (const edwards_G1& t : v) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +std::istream& operator>>(std::istream& in, std::vector &v) +{ + v.clear(); + + size_t s; + in >> s; + v.reserve(s); + consume_newline(in); + + for (size_t i = 0; i < s; ++i) + { + edwards_G1 g; + in >> g; + v.emplace_back(g); + consume_OUTPUT_NEWLINE(in); + } + + return in; +} + +template<> +void batch_to_special_all_non_zeros(std::vector &vec) +{ + std::vector Z_vec; + Z_vec.reserve(vec.size()); + + for (auto &el: vec) + { + Z_vec.emplace_back(el.Z); + } + batch_invert(Z_vec); + + const edwards_Fq one = edwards_Fq::one(); + + for (size_t i = 0; i < vec.size(); ++i) + { + vec[i].X = vec[i].X * Z_vec[i]; + vec[i].Y = vec[i].Y * Z_vec[i]; + vec[i].Z = one; + } +} + +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/edwards/edwards_g1.d b/privacy/zsl/zsl/algebra/curves/edwards/edwards_g1.d new file mode 100644 index 0000000..cf8d4be --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/edwards/edwards_g1.d @@ -0,0 +1,18 @@ +src/algebra/curves/edwards/edwards_g1.o: \ + src/algebra/curves/edwards/edwards_g1.cpp \ + src/algebra/curves/edwards/edwards_g1.hpp \ + src/algebra/curves/edwards/edwards_init.hpp \ + src/algebra/curves/public_params.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc src/algebra/fields/fp3.hpp \ + src/algebra/fields/fp3.tcc src/algebra/fields/fp6_2over3.hpp \ + src/algebra/fields/fp2.hpp src/algebra/fields/fp2.tcc \ + src/algebra/fields/fp6_2over3.tcc \ + src/algebra/scalar_multiplication/wnaf.hpp \ + src/algebra/scalar_multiplication/wnaf.tcc \ + src/algebra/curves/curve_utils.hpp src/algebra/curves/curve_utils.tcc diff --git a/privacy/zsl/zsl/algebra/curves/edwards/edwards_g1.hpp b/privacy/zsl/zsl/algebra/curves/edwards/edwards_g1.hpp new file mode 100644 index 0000000..27cb1a8 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/edwards/edwards_g1.hpp @@ -0,0 +1,97 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EDWARDS_G1_HPP_ +#define EDWARDS_G1_HPP_ +#include +#include "algebra/curves/edwards/edwards_init.hpp" +#include "algebra/curves/curve_utils.hpp" + +namespace libsnark { + +class edwards_G1; +std::ostream& operator<<(std::ostream &, const edwards_G1&); +std::istream& operator>>(std::istream &, edwards_G1&); + +class edwards_G1 { +public: +#ifdef PROFILE_OP_COUNTS + static long long add_cnt; + static long long dbl_cnt; +#endif + static std::vector wnaf_window_table; + static std::vector fixed_base_exp_window_table; + static edwards_G1 G1_zero; + static edwards_G1 G1_one; + + edwards_Fq X, Y, Z; + edwards_G1(); +private: + edwards_G1(const edwards_Fq& X, const edwards_Fq& Y, const edwards_Fq& Z) : X(X), Y(Y), Z(Z) {}; + +public: + typedef edwards_Fq base_field; + typedef edwards_Fr scalar_field; + // using inverted coordinates + edwards_G1(const edwards_Fq& X, const edwards_Fq& Y) : X(Y), Y(X), Z(X*Y) {}; + + void print() const; + void print_coordinates() const; + + void to_affine_coordinates(); + void to_special(); + bool is_special() const; + + bool is_zero() const; + + bool operator==(const edwards_G1 &other) const; + bool operator!=(const edwards_G1 &other) const; + + edwards_G1 operator+(const edwards_G1 &other) const; + edwards_G1 operator-() const; + edwards_G1 operator-(const edwards_G1 &other) const; + + edwards_G1 add(const edwards_G1 &other) const; + edwards_G1 mixed_add(const edwards_G1 &other) const; + edwards_G1 dbl() const; + + bool is_well_formed() const; + + static edwards_G1 zero(); + static edwards_G1 one(); + static edwards_G1 random_element(); + + static size_t size_in_bits() { return edwards_Fq::size_in_bits() + 1; } + static bigint base_field_char() { return base_field::field_char(); } + static bigint order() { return scalar_field::field_char(); } + + friend std::ostream& operator<<(std::ostream &out, const edwards_G1 &g); + friend std::istream& operator>>(std::istream &in, edwards_G1 &g); +}; + +template +edwards_G1 operator*(const bigint &lhs, const edwards_G1 &rhs) +{ + return scalar_mul(rhs, lhs); +} + +template& modulus_p> +edwards_G1 operator*(const Fp_model &lhs, const edwards_G1 &rhs) +{ + return scalar_mul(rhs, lhs.as_bigint()); +} + +std::ostream& operator<<(std::ostream& out, const std::vector &v); +std::istream& operator>>(std::istream& in, std::vector &v); + +template +void batch_to_special_all_non_zeros(std::vector &vec); +template<> +void batch_to_special_all_non_zeros(std::vector &vec); + +} // libsnark +#endif // EDWARDS_G1_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/edwards/edwards_g2.cpp b/privacy/zsl/zsl/algebra/curves/edwards/edwards_g2.cpp new file mode 100644 index 0000000..1880787 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/edwards/edwards_g2.cpp @@ -0,0 +1,416 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/edwards/edwards_g2.hpp" + +namespace libsnark { + +#ifdef PROFILE_OP_COUNTS +long long edwards_G2::add_cnt = 0; +long long edwards_G2::dbl_cnt = 0; +#endif + +std::vector edwards_G2::wnaf_window_table; +std::vector edwards_G2::fixed_base_exp_window_table; + +edwards_G2 edwards_G2::G2_zero; +edwards_G2 edwards_G2::G2_one; + +edwards_G2::edwards_G2() +{ + this->X = G2_zero.X; + this->Y = G2_zero.Y; + this->Z = G2_zero.Z; +} + +edwards_Fq3 edwards_G2::mul_by_a(const edwards_Fq3 &elt) +{ + // should be + // edwards_Fq3(edwards_twist_mul_by_a_c0 * elt.c2, edwards_twist_mul_by_a_c1 * elt.c0, edwards_twist_mul_by_a_c2 * elt.c1) + // but optimizing the fact that edwards_twist_mul_by_a_c1 = edwards_twist_mul_by_a_c2 = 1 + return edwards_Fq3(edwards_twist_mul_by_a_c0 * elt.c2, elt.c0, elt.c1); +} + +edwards_Fq3 edwards_G2::mul_by_d(const edwards_Fq3 &elt) +{ + return edwards_Fq3(edwards_twist_mul_by_d_c0 * elt.c2, edwards_twist_mul_by_d_c1 * elt.c0, edwards_twist_mul_by_d_c2 * elt.c1); +} + +void edwards_G2::print() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + edwards_G2 copy(*this); + copy.to_affine_coordinates(); + gmp_printf("(%Nd*z^2 + %Nd*z + %Nd , %Nd*z^2 + %Nd*z + %Nd)\n", + copy.X.c2.as_bigint().data, edwards_Fq::num_limbs, + copy.X.c1.as_bigint().data, edwards_Fq::num_limbs, + copy.X.c0.as_bigint().data, edwards_Fq::num_limbs, + copy.Y.c2.as_bigint().data, edwards_Fq::num_limbs, + copy.Y.c1.as_bigint().data, edwards_Fq::num_limbs, + copy.Y.c0.as_bigint().data, edwards_Fq::num_limbs); + } +} + +void edwards_G2::print_coordinates() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + gmp_printf("(%Nd*z^2 + %Nd*z + %Nd : %Nd*z^2 + %Nd*z + %Nd : %Nd*z^2 + %Nd*z + %Nd)\n", + this->X.c2.as_bigint().data, edwards_Fq::num_limbs, + this->X.c1.as_bigint().data, edwards_Fq::num_limbs, + this->X.c0.as_bigint().data, edwards_Fq::num_limbs, + this->Y.c2.as_bigint().data, edwards_Fq::num_limbs, + this->Y.c1.as_bigint().data, edwards_Fq::num_limbs, + this->Y.c0.as_bigint().data, edwards_Fq::num_limbs, + this->Z.c2.as_bigint().data, edwards_Fq::num_limbs, + this->Z.c1.as_bigint().data, edwards_Fq::num_limbs, + this->Z.c0.as_bigint().data, edwards_Fq::num_limbs); + } +} + +void edwards_G2::to_affine_coordinates() +{ + if (this->is_zero()) + { + this->X = edwards_Fq3::zero(); + this->Y = edwards_Fq3::one(); + this->Z = edwards_Fq3::one(); + } + else + { + // go from inverted coordinates to projective coordinates + edwards_Fq3 tX = this->Y * this->Z; + edwards_Fq3 tY = this->X * this->Z; + edwards_Fq3 tZ = this->X * this->Y; + // go from projective coordinates to affine coordinates + edwards_Fq3 tZ_inv = tZ.inverse(); + this->X = tX * tZ_inv; + this->Y = tY * tZ_inv; + this->Z = edwards_Fq3::one(); + } +} + +void edwards_G2::to_special() +{ + if (this->Z.is_zero()) + { + return; + } + +#ifdef DEBUG + const edwards_G2 copy(*this); +#endif + + edwards_Fq3 Z_inv = this->Z.inverse(); + this->X = this->X * Z_inv; + this->Y = this->Y * Z_inv; + this->Z = edwards_Fq3::one(); + +#ifdef DEBUG + assert((*this) == copy); +#endif +} + +bool edwards_G2::is_special() const +{ + return (this->is_zero() || this->Z == edwards_Fq3::one()); +} + +bool edwards_G2::is_zero() const +{ + return (this->Y.is_zero() && this->Z.is_zero()); +} + +bool edwards_G2::operator==(const edwards_G2 &other) const +{ + if (this->is_zero()) + { + return other.is_zero(); + } + + if (other.is_zero()) + { + return false; + } + + /* now neither is O */ + + // X1/Z1 = X2/Z2 <=> X1*Z2 = X2*Z1 + if ((this->X * other.Z) != (other.X * this->Z)) + { + return false; + } + + // Y1/Z1 = Y2/Z2 <=> Y1*Z2 = Y2*Z1 + if ((this->Y * other.Z) != (other.Y * this->Z)) + { + return false; + } + + return true; +} + +bool edwards_G2::operator!=(const edwards_G2& other) const +{ + return !(operator==(other)); +} + +edwards_G2 edwards_G2::operator+(const edwards_G2 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return (*this); + } + + return this->add(other); +} + +edwards_G2 edwards_G2::operator-() const +{ + return edwards_G2(-(this->X), this->Y, this->Z); +} + + +edwards_G2 edwards_G2::operator-(const edwards_G2 &other) const +{ + return (*this) + (-other); +} + +edwards_G2 edwards_G2::add(const edwards_G2 &other) const +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-twisted-inverted.html#addition-add-2008-bbjlp + + const edwards_Fq3 A = (this->Z) * (other.Z); // A = Z1*Z2 + const edwards_Fq3 B = edwards_G2::mul_by_d(A.squared()); // B = d*A^2 + const edwards_Fq3 C = (this->X) * (other.X); // C = X1*X2 + const edwards_Fq3 D = (this->Y) * (other.Y); // D = Y1*Y2 + const edwards_Fq3 E = C*D; // E = C*D + const edwards_Fq3 H = C - edwards_G2::mul_by_a(D); // H = C-a*D + const edwards_Fq3 I = (this->X+this->Y)*(other.X+other.Y)-C-D; // I = (X1+Y1)*(X2+Y2)-C-D + const edwards_Fq3 X3 = (E+B)*H; // X3 = (E+B)*H + const edwards_Fq3 Y3 = (E-B)*I; // Y3 = (E-B)*I + const edwards_Fq3 Z3 = A*H*I; // Z3 = A*H*I + + return edwards_G2(X3, Y3, Z3); +} + +edwards_G2 edwards_G2::mixed_add(const edwards_G2 &other) const +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + +#ifdef DEBUG + assert(other.is_special()); +#endif + + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-edwards-inverted.html#addition-madd-2007-lb + + const edwards_Fq3 A = this->Z; // A = Z1*Z2 + const edwards_Fq3 B = edwards_G2::mul_by_d(A.squared()); // B = d*A^2 + const edwards_Fq3 C = (this->X) * (other.X); // C = X1*X2 + const edwards_Fq3 D = (this->Y) * (other.Y); // D = Y1*Y2 + const edwards_Fq3 E = C*D; // E = C*D + const edwards_Fq3 H = C - edwards_G2::mul_by_a(D); // H = C-a*D + const edwards_Fq3 I = (this->X+this->Y)*(other.X+other.Y)-C-D; // I = (X1+Y1)*(X2+Y2)-C-D + const edwards_Fq3 X3 = (E+B)*H; // X3 = (E+B)*H + const edwards_Fq3 Y3 = (E-B)*I; // Y3 = (E-B)*I + const edwards_Fq3 Z3 = A*H*I; // Z3 = A*H*I + + return edwards_G2(X3, Y3, Z3); +} + +edwards_G2 edwards_G2::dbl() const +{ +#ifdef PROFILE_OP_COUNTS + this->dbl_cnt++; +#endif + if (this->is_zero()) + { + return (*this); + } + else + { + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-twisted-inverted.html#doubling-dbl-2008-bbjlp + + const edwards_Fq3 A = (this->X).squared(); // A = X1^2 + const edwards_Fq3 B = (this->Y).squared(); // B = Y1^2 + const edwards_Fq3 U = edwards_G2::mul_by_a(B); // U = a*B + const edwards_Fq3 C = A+U; // C = A+U + const edwards_Fq3 D = A-U; // D = A-U + const edwards_Fq3 E = (this->X+this->Y).squared()-A-B; // E = (X1+Y1)^2-A-B + const edwards_Fq3 X3 = C*D; // X3 = C*D + const edwards_Fq3 dZZ = edwards_G2::mul_by_d(this->Z.squared()); + const edwards_Fq3 Y3 = E*(C-dZZ-dZZ); // Y3 = E*(C-2*d*Z1^2) + const edwards_Fq3 Z3 = D*E; // Z3 = D*E + + return edwards_G2(X3, Y3, Z3); + } +} + +edwards_G2 edwards_G2::mul_by_q() const +{ + return edwards_G2((this->X).Frobenius_map(1), + edwards_twist_mul_by_q_Y * (this->Y).Frobenius_map(1), + edwards_twist_mul_by_q_Z * (this->Z).Frobenius_map(1)); +} + +bool edwards_G2::is_well_formed() const +{ + /* Note that point at infinity is the only special case we must check as + inverted representation does no cover points (0, +-c) and (+-c, 0). */ + if (this->is_zero()) + { + return true; + } + else + { + /* + a x^2 + y^2 = 1 + d x^2 y^2 + + We are using inverted, so equation we need to check is actually + + a (z/x)^2 + (z/y)^2 = 1 + d z^4 / (x^2 * y^2) + z^2 (a y^2 + x^2 - dz^2) = x^2 y^2 + */ + edwards_Fq3 X2 = this->X.squared(); + edwards_Fq3 Y2 = this->Y.squared(); + edwards_Fq3 Z2 = this->Z.squared(); + edwards_Fq3 aY2 = edwards_G2::mul_by_a(Y2); + edwards_Fq3 dZ2 = edwards_G2::mul_by_d(Z2); + return (Z2 * (aY2 + X2 - dZ2) == X2 * Y2); + } +} + +edwards_G2 edwards_G2::zero() +{ + return G2_zero; +} + +edwards_G2 edwards_G2::one() +{ + return G2_one; +} + +edwards_G2 edwards_G2::random_element() +{ + return edwards_Fr::random_element().as_bigint() * G2_one; +} + +std::ostream& operator<<(std::ostream &out, const edwards_G2 &g) +{ + edwards_G2 copy(g); + copy.to_affine_coordinates(); +#ifdef NO_PT_COMPRESSION + out << copy.X << OUTPUT_SEPARATOR << copy.Y; +#else + /* storing LSB of Y */ + out << copy.X << OUTPUT_SEPARATOR << (copy.Y.c0.as_bigint().data[0] & 1); +#endif + return out; +} + +std::istream& operator>>(std::istream &in, edwards_G2 &g) +{ + edwards_Fq3 tX, tY; + +#ifdef NO_PT_COMPRESSION + in >> tX; + consume_OUTPUT_SEPARATOR(in); + in >> tY; +#else + /* + a x^2 + y^2 = 1 + d x^2 y^2 + y = sqrt((1-ax^2)/(1-dx^2)) + */ + unsigned char Y_lsb; + in >> tX; + consume_OUTPUT_SEPARATOR(in); + + in.read((char*)&Y_lsb, 1); + Y_lsb -= '0'; + + edwards_Fq3 tX2 = tX.squared(); + const edwards_Fq3 tY2 = + (edwards_Fq3::one() - edwards_G2::mul_by_a(tX2)) * + (edwards_Fq3::one() - edwards_G2::mul_by_d(tX2)).inverse(); + tY = tY2.sqrt(); + + if ((tY.c0.as_bigint().data[0] & 1) != Y_lsb) + { + tY = -tY; + } +#endif + + // using inverted coordinates + g.X = tY; + g.Y = tX; + g.Z = tX * tY; + +#ifdef USE_MIXED_ADDITION + g.to_special(); +#endif + + return in; +} + +template +void batch_to_special_all_non_zeros(std::vector &vec); +template<> +void batch_to_special_all_non_zeros(std::vector &vec) +{ + std::vector Z_vec; + Z_vec.reserve(vec.size()); + + for (auto &el: vec) + { + Z_vec.emplace_back(el.Z); + } + batch_invert(Z_vec); + + const edwards_Fq3 one = edwards_Fq3::one(); + + for (size_t i = 0; i < vec.size(); ++i) + { + vec[i].X = vec[i].X * Z_vec[i]; + vec[i].Y = vec[i].Y * Z_vec[i]; + vec[i].Z = one; + } +} + +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/edwards/edwards_g2.d b/privacy/zsl/zsl/algebra/curves/edwards/edwards_g2.d new file mode 100644 index 0000000..399310f --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/edwards/edwards_g2.d @@ -0,0 +1,18 @@ +src/algebra/curves/edwards/edwards_g2.o: \ + src/algebra/curves/edwards/edwards_g2.cpp \ + src/algebra/curves/edwards/edwards_g2.hpp \ + src/algebra/curves/edwards/edwards_init.hpp \ + src/algebra/curves/public_params.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc src/algebra/fields/fp3.hpp \ + src/algebra/fields/fp3.tcc src/algebra/fields/fp6_2over3.hpp \ + src/algebra/fields/fp2.hpp src/algebra/fields/fp2.tcc \ + src/algebra/fields/fp6_2over3.tcc \ + src/algebra/scalar_multiplication/wnaf.hpp \ + src/algebra/scalar_multiplication/wnaf.tcc \ + src/algebra/curves/curve_utils.hpp src/algebra/curves/curve_utils.tcc diff --git a/privacy/zsl/zsl/algebra/curves/edwards/edwards_g2.hpp b/privacy/zsl/zsl/algebra/curves/edwards/edwards_g2.hpp new file mode 100644 index 0000000..bf35aef --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/edwards/edwards_g2.hpp @@ -0,0 +1,100 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EDWARDS_G2_HPP_ +#define EDWARDS_G2_HPP_ +#include +#include +#include "algebra/curves/edwards/edwards_init.hpp" +#include "algebra/curves/curve_utils.hpp" + +namespace libsnark { + +class edwards_G2; +std::ostream& operator<<(std::ostream &, const edwards_G2&); +std::istream& operator>>(std::istream &, edwards_G2&); + +class edwards_G2 { +public: +#ifdef PROFILE_OP_COUNTS + static long long add_cnt; + static long long dbl_cnt; +#endif + static std::vector wnaf_window_table; + static std::vector fixed_base_exp_window_table; + + static edwards_G2 G2_zero; + static edwards_G2 G2_one; + + edwards_Fq3 X, Y, Z; + edwards_G2(); +private: + edwards_G2(const edwards_Fq3& X, const edwards_Fq3& Y, const edwards_Fq3& Z) : X(X), Y(Y), Z(Z) {}; +public: + static edwards_Fq3 mul_by_a(const edwards_Fq3 &elt); + static edwards_Fq3 mul_by_d(const edwards_Fq3 &elt); + typedef edwards_Fq base_field; + typedef edwards_Fq3 twist_field; + typedef edwards_Fr scalar_field; + + // using inverted coordinates + edwards_G2(const edwards_Fq3& X, const edwards_Fq3& Y) : X(Y), Y(X), Z(X*Y) {}; + + void print() const; + void print_coordinates() const; + + void to_affine_coordinates(); + void to_special(); + bool is_special() const; + + bool is_zero() const; + + bool operator==(const edwards_G2 &other) const; + bool operator!=(const edwards_G2 &other) const; + + edwards_G2 operator+(const edwards_G2 &other) const; + edwards_G2 operator-() const; + edwards_G2 operator-(const edwards_G2 &other) const; + + edwards_G2 add(const edwards_G2 &other) const; + edwards_G2 mixed_add(const edwards_G2 &other) const; + edwards_G2 dbl() const; + edwards_G2 mul_by_q() const; + + bool is_well_formed() const; + + static edwards_G2 zero(); + static edwards_G2 one(); + static edwards_G2 random_element(); + + static size_t size_in_bits() { return twist_field::size_in_bits() + 1; } + static bigint base_field_char() { return base_field::field_char(); } + static bigint order() { return scalar_field::field_char(); } + + friend std::ostream& operator<<(std::ostream &out, const edwards_G2 &g); + friend std::istream& operator>>(std::istream &in, edwards_G2 &g); +}; + +template +edwards_G2 operator*(const bigint &lhs, const edwards_G2 &rhs) +{ + return scalar_mul(rhs, lhs); +} + +template& modulus_p> +edwards_G2 operator*(const Fp_model &lhs, const edwards_G2 &rhs) +{ + return scalar_mul(rhs, lhs.as_bigint()); +} + +template +void batch_to_special_all_non_zeros(std::vector &vec); +template<> +void batch_to_special_all_non_zeros(std::vector &vec); + +} // libsnark +#endif // EDWARDS_G2_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/edwards/edwards_init.cpp b/privacy/zsl/zsl/algebra/curves/edwards/edwards_init.cpp new file mode 100644 index 0000000..99538ac --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/edwards/edwards_init.cpp @@ -0,0 +1,270 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/edwards/edwards_init.hpp" +#include "algebra/curves/edwards/edwards_g1.hpp" +#include "algebra/curves/edwards/edwards_g2.hpp" + +namespace libsnark { + +bigint edwards_modulus_r; +bigint edwards_modulus_q; + +edwards_Fq edwards_coeff_a; +edwards_Fq edwards_coeff_d; +edwards_Fq3 edwards_twist; +edwards_Fq3 edwards_twist_coeff_a; +edwards_Fq3 edwards_twist_coeff_d; +edwards_Fq edwards_twist_mul_by_a_c0; +edwards_Fq edwards_twist_mul_by_a_c1; +edwards_Fq edwards_twist_mul_by_a_c2; +edwards_Fq edwards_twist_mul_by_d_c0; +edwards_Fq edwards_twist_mul_by_d_c1; +edwards_Fq edwards_twist_mul_by_d_c2; +edwards_Fq edwards_twist_mul_by_q_Y; +edwards_Fq edwards_twist_mul_by_q_Z; + +bigint edwards_ate_loop_count; +bigint<6*edwards_q_limbs> edwards_final_exponent; +bigint edwards_final_exponent_last_chunk_abs_of_w0; +bool edwards_final_exponent_last_chunk_is_w0_neg; +bigint edwards_final_exponent_last_chunk_w1; + +void init_edwards_params() +{ + typedef bigint bigint_r; + typedef bigint bigint_q; + + assert(sizeof(mp_limb_t) == 8 || sizeof(mp_limb_t) == 4); // Montgomery assumes this + + /* parameters for scalar field Fr */ + + edwards_modulus_r = bigint_r("1552511030102430251236801561344621993261920897571225601"); + assert(edwards_Fr::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + edwards_Fr::Rsquared = bigint_r("621738487827897760168419760282818735947979812540885779"); + edwards_Fr::Rcubed = bigint_r("899968968216802386013510389846941393831065658679774050"); + edwards_Fr::inv = 0xdde553277fffffff; + } + if (sizeof(mp_limb_t) == 4) + { + edwards_Fr::Rsquared = bigint_r("621738487827897760168419760282818735947979812540885779"); + edwards_Fr::Rcubed = bigint_r("899968968216802386013510389846941393831065658679774050"); + edwards_Fr::inv = 0x7fffffff; + } + edwards_Fr::num_bits = 181; + edwards_Fr::euler = bigint_r("776255515051215125618400780672310996630960448785612800"); + edwards_Fr::s = 31; + edwards_Fr::t = bigint_r("722944284836962004768104088187507350585386575"); + edwards_Fr::t_minus_1_over_2 = bigint_r("361472142418481002384052044093753675292693287"); + edwards_Fr::multiplicative_generator = edwards_Fr("19"); + edwards_Fr::root_of_unity = edwards_Fr("695314865466598274460565335217615316274564719601897184"); + edwards_Fr::nqr = edwards_Fr("11"); + edwards_Fr::nqr_to_t = edwards_Fr("1326707053668679463752768729767248251415639579872144553"); + + /* parameters for base field Fq */ + + edwards_modulus_q = bigint_q("6210044120409721004947206240885978274523751269793792001"); + assert(edwards_Fq::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + edwards_Fq::Rsquared = bigint_q("5943559676554581037560514598978484097352477055348195432"); + edwards_Fq::Rcubed = bigint_q("1081560488703514202058739223469726982199727506489234349"); + edwards_Fq::inv = 0x76eb690b7fffffff; + } + if (sizeof(mp_limb_t) == 4) + { + edwards_Fq::Rsquared = bigint_q("5943559676554581037560514598978484097352477055348195432"); + edwards_Fq::Rcubed = bigint_q("1081560488703514202058739223469726982199727506489234349"); + edwards_Fq::inv = 0x7fffffff; + } + edwards_Fq::num_bits = 183; + edwards_Fq::euler = bigint_q("3105022060204860502473603120442989137261875634896896000"); + edwards_Fq::s = 31; + edwards_Fq::t = bigint_q("2891777139347848019072416350658041552884388375"); + edwards_Fq::t_minus_1_over_2 = bigint_q("1445888569673924009536208175329020776442194187"); + edwards_Fq::multiplicative_generator = edwards_Fq("61"); + edwards_Fq::root_of_unity = edwards_Fq("4692813029219384139894873043933463717810008194158530536"); + edwards_Fq::nqr = edwards_Fq("23"); + edwards_Fq::nqr_to_t = edwards_Fq("2626736066325740702418554487368721595489070118548299138"); + + /* parameters for twist field Fq3 */ + + edwards_Fq3::euler = bigint<3*edwards_q_limbs>("119744082713971502962992613191067836698205043373978948903839934564152994858051284658545502971203325031831647424413111161318314144765646525057914792711854057586688000"); + edwards_Fq3::s = 31; + edwards_Fq3::t = bigint<3*edwards_q_limbs>("111520367408144756185815309352304634357062208814526860512643991563611659089151103662834971185031649686239331424621037357783237607000066456438894190557165125"); + edwards_Fq3::t_minus_1_over_2 = bigint<3*edwards_q_limbs>("55760183704072378092907654676152317178531104407263430256321995781805829544575551831417485592515824843119665712310518678891618803500033228219447095278582562"); + edwards_Fq3::non_residue = edwards_Fq("61"); + edwards_Fq3::nqr = edwards_Fq3(edwards_Fq("23"),edwards_Fq("0"),edwards_Fq("0")); + edwards_Fq3::nqr_to_t = edwards_Fq3(edwards_Fq("104810943629412208121981114244673004633270996333237516"),edwards_Fq("0"),edwards_Fq("0")); + edwards_Fq3::Frobenius_coeffs_c1[0] = edwards_Fq("1"); + edwards_Fq3::Frobenius_coeffs_c1[1] = edwards_Fq("1073752683758513276629212192812154536507607213288832061"); + edwards_Fq3::Frobenius_coeffs_c1[2] = edwards_Fq("5136291436651207728317994048073823738016144056504959939"); + edwards_Fq3::Frobenius_coeffs_c2[0] = edwards_Fq("1"); + edwards_Fq3::Frobenius_coeffs_c2[1] = edwards_Fq("5136291436651207728317994048073823738016144056504959939"); + edwards_Fq3::Frobenius_coeffs_c2[2] = edwards_Fq("1073752683758513276629212192812154536507607213288832061"); + + /* parameters for Fq6 */ + + edwards_Fq6::non_residue = edwards_Fq("61"); + edwards_Fq6::Frobenius_coeffs_c1[0] = edwards_Fq("1"); + edwards_Fq6::Frobenius_coeffs_c1[1] = edwards_Fq("1073752683758513276629212192812154536507607213288832062"); + edwards_Fq6::Frobenius_coeffs_c1[2] = edwards_Fq("1073752683758513276629212192812154536507607213288832061"); + edwards_Fq6::Frobenius_coeffs_c1[3] = edwards_Fq("6210044120409721004947206240885978274523751269793792000"); + edwards_Fq6::Frobenius_coeffs_c1[4] = edwards_Fq("5136291436651207728317994048073823738016144056504959939"); + edwards_Fq6::Frobenius_coeffs_c1[5] = edwards_Fq("5136291436651207728317994048073823738016144056504959940"); + edwards_Fq6::my_Fp2::non_residue = edwards_Fq3::non_residue; + + /* choice of Edwards curve and its twist */ + + edwards_coeff_a = edwards_Fq::one(); + edwards_coeff_d = edwards_Fq("600581931845324488256649384912508268813600056237543024"); + edwards_twist = edwards_Fq3(edwards_Fq::zero(), edwards_Fq::one(), edwards_Fq::zero()); + edwards_twist_coeff_a = edwards_coeff_a * edwards_twist; + edwards_twist_coeff_d = edwards_coeff_d * edwards_twist; + edwards_twist_mul_by_a_c0 = edwards_coeff_a * edwards_Fq3::non_residue; + edwards_twist_mul_by_a_c1 = edwards_coeff_a; + edwards_twist_mul_by_a_c2 = edwards_coeff_a; + edwards_twist_mul_by_d_c0 = edwards_coeff_d * edwards_Fq3::non_residue; + edwards_twist_mul_by_d_c1 = edwards_coeff_d; + edwards_twist_mul_by_d_c2 = edwards_coeff_d; + edwards_twist_mul_by_q_Y = edwards_Fq("1073752683758513276629212192812154536507607213288832062"); + edwards_twist_mul_by_q_Z = edwards_Fq("1073752683758513276629212192812154536507607213288832062"); + + /* choice of group G1 */ + + edwards_G1::G1_zero = edwards_G1(edwards_Fq::zero(), + edwards_Fq::one()); + edwards_G1::G1_one = edwards_G1(edwards_Fq("3713709671941291996998665608188072510389821008693530490"), + edwards_Fq("4869953702976555123067178261685365085639705297852816679")); + + edwards_G1::wnaf_window_table.resize(0); + edwards_G1::wnaf_window_table.push_back(9); + edwards_G1::wnaf_window_table.push_back(14); + edwards_G1::wnaf_window_table.push_back(24); + edwards_G1::wnaf_window_table.push_back(117); + + edwards_G1::fixed_base_exp_window_table.resize(0); + // window 1 is unbeaten in [-inf, 4.10] + edwards_G1::fixed_base_exp_window_table.push_back(1); + // window 2 is unbeaten in [4.10, 9.69] + edwards_G1::fixed_base_exp_window_table.push_back(4); + // window 3 is unbeaten in [9.69, 25.21] + edwards_G1::fixed_base_exp_window_table.push_back(10); + // window 4 is unbeaten in [25.21, 60.00] + edwards_G1::fixed_base_exp_window_table.push_back(25); + // window 5 is unbeaten in [60.00, 149.33] + edwards_G1::fixed_base_exp_window_table.push_back(60); + // window 6 is unbeaten in [149.33, 369.61] + edwards_G1::fixed_base_exp_window_table.push_back(149); + // window 7 is unbeaten in [369.61, 849.07] + edwards_G1::fixed_base_exp_window_table.push_back(370); + // window 8 is unbeaten in [849.07, 1764.94] + edwards_G1::fixed_base_exp_window_table.push_back(849); + // window 9 is unbeaten in [1764.94, 4429.59] + edwards_G1::fixed_base_exp_window_table.push_back(1765); + // window 10 is unbeaten in [4429.59, 13388.78] + edwards_G1::fixed_base_exp_window_table.push_back(4430); + // window 11 is unbeaten in [13388.78, 15368.00] + edwards_G1::fixed_base_exp_window_table.push_back(13389); + // window 12 is unbeaten in [15368.00, 74912.07] + edwards_G1::fixed_base_exp_window_table.push_back(15368); + // window 13 is unbeaten in [74912.07, 438107.20] + edwards_G1::fixed_base_exp_window_table.push_back(74912); + // window 14 is never the best + edwards_G1::fixed_base_exp_window_table.push_back(0); + // window 15 is unbeaten in [438107.20, 1045626.18] + edwards_G1::fixed_base_exp_window_table.push_back(438107); + // window 16 is never the best + edwards_G1::fixed_base_exp_window_table.push_back(0); + // window 17 is unbeaten in [1045626.18, 1577434.48] + edwards_G1::fixed_base_exp_window_table.push_back(1045626); + // window 18 is unbeaten in [1577434.48, 17350594.23] + edwards_G1::fixed_base_exp_window_table.push_back(1577434); + // window 19 is never the best + edwards_G1::fixed_base_exp_window_table.push_back(0); + // window 20 is never the best + edwards_G1::fixed_base_exp_window_table.push_back(0); + // window 21 is unbeaten in [17350594.23, inf] + edwards_G1::fixed_base_exp_window_table.push_back(17350594); + // window 22 is never the best + edwards_G1::fixed_base_exp_window_table.push_back(0); + + /* choice of group G2 */ + + edwards_G2::G2_zero = edwards_G2(edwards_Fq3::zero(), + edwards_Fq3::one()); + edwards_G2::G2_one = edwards_G2(edwards_Fq3(edwards_Fq("4531683359223370252210990718516622098304721701253228128"), + edwards_Fq("5339624155305731263217400504407647531329993548123477368"), + edwards_Fq("3964037981777308726208525982198654699800283729988686552")), + edwards_Fq3(edwards_Fq("364634864866983740775341816274081071386963546650700569"), + edwards_Fq("3264380230116139014996291397901297105159834497864380415"), + edwards_Fq("3504781284999684163274269077749440837914479176282903747"))); + + edwards_G2::wnaf_window_table.resize(0); + edwards_G2::wnaf_window_table.push_back(6); + edwards_G2::wnaf_window_table.push_back(12); + edwards_G2::wnaf_window_table.push_back(42); + edwards_G2::wnaf_window_table.push_back(97); + + edwards_G2::fixed_base_exp_window_table.resize(0); + // window 1 is unbeaten in [-inf, 4.74] + edwards_G2::fixed_base_exp_window_table.push_back(1); + // window 2 is unbeaten in [4.74, 10.67] + edwards_G2::fixed_base_exp_window_table.push_back(5); + // window 3 is unbeaten in [10.67, 25.53] + edwards_G2::fixed_base_exp_window_table.push_back(11); + // window 4 is unbeaten in [25.53, 60.67] + edwards_G2::fixed_base_exp_window_table.push_back(26); + // window 5 is unbeaten in [60.67, 145.77] + edwards_G2::fixed_base_exp_window_table.push_back(61); + // window 6 is unbeaten in [145.77, 356.76] + edwards_G2::fixed_base_exp_window_table.push_back(146); + // window 7 is unbeaten in [356.76, 823.08] + edwards_G2::fixed_base_exp_window_table.push_back(357); + // window 8 is unbeaten in [823.08, 1589.45] + edwards_G2::fixed_base_exp_window_table.push_back(823); + // window 9 is unbeaten in [1589.45, 4135.70] + edwards_G2::fixed_base_exp_window_table.push_back(1589); + // window 10 is unbeaten in [4135.70, 14297.74] + edwards_G2::fixed_base_exp_window_table.push_back(4136); + // window 11 is unbeaten in [14297.74, 16744.85] + edwards_G2::fixed_base_exp_window_table.push_back(14298); + // window 12 is unbeaten in [16744.85, 51768.98] + edwards_G2::fixed_base_exp_window_table.push_back(16745); + // window 13 is unbeaten in [51768.98, 99811.01] + edwards_G2::fixed_base_exp_window_table.push_back(51769); + // window 14 is unbeaten in [99811.01, 193306.72] + edwards_G2::fixed_base_exp_window_table.push_back(99811); + // window 15 is unbeaten in [193306.72, 907184.68] + edwards_G2::fixed_base_exp_window_table.push_back(193307); + // window 16 is never the best + edwards_G2::fixed_base_exp_window_table.push_back(0); + // window 17 is unbeaten in [907184.68, 1389682.59] + edwards_G2::fixed_base_exp_window_table.push_back(907185); + // window 18 is unbeaten in [1389682.59, 6752695.74] + edwards_G2::fixed_base_exp_window_table.push_back(1389683); + // window 19 is never the best + edwards_G2::fixed_base_exp_window_table.push_back(0); + // window 20 is unbeaten in [6752695.74, 193642894.51] + edwards_G2::fixed_base_exp_window_table.push_back(6752696); + // window 21 is unbeaten in [193642894.51, 226760202.29] + edwards_G2::fixed_base_exp_window_table.push_back(193642895); + // window 22 is unbeaten in [226760202.29, inf] + edwards_G2::fixed_base_exp_window_table.push_back(226760202); + + /* pairing parameters */ + + edwards_ate_loop_count = bigint_q("4492509698523932320491110403"); + edwards_final_exponent = bigint<6*edwards_q_limbs>("36943107177961694649618797346446870138748651578611748415128207429491593976636391130175425245705674550269561361208979548749447898941828686017765730419416875539615941651269793928962468899856083169227457503942470721108165443528513330156264699608120624990672333642644221591552000"); + edwards_final_exponent_last_chunk_abs_of_w0 = bigint_q("17970038794095729281964441603"); + edwards_final_exponent_last_chunk_is_w0_neg = true; + edwards_final_exponent_last_chunk_w1 = bigint_q("4"); + +} +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/edwards/edwards_init.d b/privacy/zsl/zsl/algebra/curves/edwards/edwards_init.d new file mode 100644 index 0000000..f5853f5 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/edwards/edwards_init.d @@ -0,0 +1,19 @@ +src/algebra/curves/edwards/edwards_init.o: \ + src/algebra/curves/edwards/edwards_init.cpp \ + src/algebra/curves/edwards/edwards_init.hpp \ + src/algebra/curves/public_params.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc src/algebra/fields/fp3.hpp \ + src/algebra/fields/fp3.tcc src/algebra/fields/fp6_2over3.hpp \ + src/algebra/fields/fp2.hpp src/algebra/fields/fp2.tcc \ + src/algebra/fields/fp6_2over3.tcc \ + src/algebra/scalar_multiplication/wnaf.hpp \ + src/algebra/scalar_multiplication/wnaf.tcc \ + src/algebra/curves/edwards/edwards_g1.hpp \ + src/algebra/curves/curve_utils.hpp src/algebra/curves/curve_utils.tcc \ + src/algebra/curves/edwards/edwards_g2.hpp diff --git a/privacy/zsl/zsl/algebra/curves/edwards/edwards_init.hpp b/privacy/zsl/zsl/algebra/curves/edwards/edwards_init.hpp new file mode 100644 index 0000000..3ada55b --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/edwards/edwards_init.hpp @@ -0,0 +1,61 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EDWARDS_INIT_HPP_ +#define EDWARDS_INIT_HPP_ +#include "algebra/curves/public_params.hpp" +#include "algebra/fields/fp.hpp" +#include "algebra/fields/fp3.hpp" +#include "algebra/fields/fp6_2over3.hpp" + +namespace libsnark { + +const mp_size_t edwards_r_bitcount = 181; +const mp_size_t edwards_q_bitcount = 183; + +const mp_size_t edwards_r_limbs = (edwards_r_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; +const mp_size_t edwards_q_limbs = (edwards_q_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; + +extern bigint edwards_modulus_r; +extern bigint edwards_modulus_q; + +typedef Fp_model edwards_Fr; +typedef Fp_model edwards_Fq; +typedef Fp3_model edwards_Fq3; +typedef Fp6_2over3_model edwards_Fq6; +typedef edwards_Fq6 edwards_GT; + +// parameters for Edwards curve E_{1,d}(F_q) +extern edwards_Fq edwards_coeff_a; +extern edwards_Fq edwards_coeff_d; +// parameters for twisted Edwards curve E_{a',d'}(F_q^3) +extern edwards_Fq3 edwards_twist; +extern edwards_Fq3 edwards_twist_coeff_a; +extern edwards_Fq3 edwards_twist_coeff_d; +extern edwards_Fq edwards_twist_mul_by_a_c0; +extern edwards_Fq edwards_twist_mul_by_a_c1; +extern edwards_Fq edwards_twist_mul_by_a_c2; +extern edwards_Fq edwards_twist_mul_by_d_c0; +extern edwards_Fq edwards_twist_mul_by_d_c1; +extern edwards_Fq edwards_twist_mul_by_d_c2; +extern edwards_Fq edwards_twist_mul_by_q_Y; +extern edwards_Fq edwards_twist_mul_by_q_Z; + +// parameters for pairing +extern bigint edwards_ate_loop_count; +extern bigint<6*edwards_q_limbs> edwards_final_exponent; +extern bigint edwards_final_exponent_last_chunk_abs_of_w0; +extern bool edwards_final_exponent_last_chunk_is_w0_neg; +extern bigint edwards_final_exponent_last_chunk_w1; + +void init_edwards_params(); + +class edwards_G1; +class edwards_G2; + +} // libsnark +#endif // EDWARDS_INIT_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/edwards/edwards_pairing.cpp b/privacy/zsl/zsl/algebra/curves/edwards/edwards_pairing.cpp new file mode 100644 index 0000000..22fab01 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/edwards/edwards_pairing.cpp @@ -0,0 +1,775 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/edwards/edwards_pairing.hpp" +#include "algebra/curves/edwards/edwards_init.hpp" +#include +#include "algebra/curves/edwards/edwards_g1.hpp" +#include "algebra/curves/edwards/edwards_g2.hpp" +#include "common/profiling.hpp" + +namespace libsnark { + +bool edwards_Fq_conic_coefficients::operator==(const edwards_Fq_conic_coefficients &other) const +{ + return (this->c_ZZ == other.c_ZZ && + this->c_XY == other.c_XY && + this->c_XZ == other.c_XZ); +} + +std::ostream& operator<<(std::ostream &out, const edwards_Fq_conic_coefficients &cc) +{ + out << cc.c_ZZ << OUTPUT_SEPARATOR << cc.c_XY << OUTPUT_SEPARATOR << cc.c_XZ; + return out; +} + +std::istream& operator>>(std::istream &in, edwards_Fq_conic_coefficients &cc) +{ + in >> cc.c_ZZ; + consume_OUTPUT_SEPARATOR(in); + in >> cc.c_XY; + consume_OUTPUT_SEPARATOR(in); + in >> cc.c_XZ; + return in; +} + +std::ostream& operator<<(std::ostream& out, const edwards_tate_G1_precomp &prec_P) +{ + out << prec_P.size() << "\n"; + for (const edwards_Fq_conic_coefficients &cc : prec_P) + { + out << cc << OUTPUT_NEWLINE; + } + + return out; +} + +std::istream& operator>>(std::istream& in, edwards_tate_G1_precomp &prec_P) +{ + prec_P.clear(); + + size_t s; + in >> s; + + consume_newline(in); + prec_P.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + edwards_Fq_conic_coefficients cc; + in >> cc; + consume_OUTPUT_NEWLINE(in); + prec_P.emplace_back(cc); + } + + return in; +} + +bool edwards_tate_G2_precomp::operator==(const edwards_tate_G2_precomp &other) const +{ + return (this->y0 == other.y0 && + this->eta == other.eta); +} + +std::ostream& operator<<(std::ostream &out, const edwards_tate_G2_precomp &prec_Q) +{ + out << prec_Q.y0 << OUTPUT_SEPARATOR << prec_Q.eta; + return out; +} + +std::istream& operator>>(std::istream &in, edwards_tate_G2_precomp &prec_Q) +{ + in >> prec_Q.y0; + consume_OUTPUT_SEPARATOR(in); + in >> prec_Q.eta; + return in; +} + +bool edwards_Fq3_conic_coefficients::operator==(const edwards_Fq3_conic_coefficients &other) const +{ + return (this->c_ZZ == other.c_ZZ && + this->c_XY == other.c_XY && + this->c_XZ == other.c_XZ); +} + +std::ostream& operator<<(std::ostream &out, const edwards_Fq3_conic_coefficients &cc) +{ + out << cc.c_ZZ << OUTPUT_SEPARATOR << cc.c_XY << OUTPUT_SEPARATOR << cc.c_XZ; + return out; +} + +std::istream& operator>>(std::istream &in, edwards_Fq3_conic_coefficients &cc) +{ + in >> cc.c_ZZ; + consume_OUTPUT_SEPARATOR(in); + in >> cc.c_XY; + consume_OUTPUT_SEPARATOR(in); + in >> cc.c_XZ; + return in; +} + +std::ostream& operator<<(std::ostream& out, const edwards_ate_G2_precomp &prec_Q) +{ + out << prec_Q.size() << "\n"; + for (const edwards_Fq3_conic_coefficients &cc : prec_Q) + { + out << cc << OUTPUT_NEWLINE; + } + + return out; +} + +std::istream& operator>>(std::istream& in, edwards_ate_G2_precomp &prec_Q) +{ + prec_Q.clear(); + + size_t s; + in >> s; + + consume_newline(in); + + prec_Q.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + edwards_Fq3_conic_coefficients cc; + in >> cc; + consume_OUTPUT_NEWLINE(in); + prec_Q.emplace_back(cc); + } + + return in; +} + +bool edwards_ate_G1_precomp::operator==(const edwards_ate_G1_precomp &other) const +{ + return (this->P_XY == other.P_XY && + this->P_XZ == other.P_XZ && + this->P_ZZplusYZ == other.P_ZZplusYZ); +} + +std::ostream& operator<<(std::ostream &out, const edwards_ate_G1_precomp &prec_P) +{ + out << prec_P.P_XY << OUTPUT_SEPARATOR << prec_P.P_XZ << OUTPUT_SEPARATOR << prec_P.P_ZZplusYZ; + + return out; +} + +std::istream& operator>>(std::istream &in, edwards_ate_G1_precomp &prec_P) +{ + in >> prec_P.P_XY >> prec_P.P_XZ >> prec_P.P_ZZplusYZ; + + return in; +} + +/* final exponentiations */ +edwards_Fq6 edwards_final_exponentiation_last_chunk(const edwards_Fq6 &elt, const edwards_Fq6 &elt_inv) +{ + enter_block("Call to edwards_final_exponentiation_last_chunk"); + const edwards_Fq6 elt_q = elt.Frobenius_map(1); + edwards_Fq6 w1_part = elt_q.cyclotomic_exp(edwards_final_exponent_last_chunk_w1); + edwards_Fq6 w0_part; + if (edwards_final_exponent_last_chunk_is_w0_neg) + { + w0_part = elt_inv.cyclotomic_exp(edwards_final_exponent_last_chunk_abs_of_w0); + } else { + w0_part = elt.cyclotomic_exp(edwards_final_exponent_last_chunk_abs_of_w0); + } + edwards_Fq6 result = w1_part * w0_part; + leave_block("Call to edwards_final_exponentiation_last_chunk"); + + return result; +} + +edwards_Fq6 edwards_final_exponentiation_first_chunk(const edwards_Fq6 &elt, const edwards_Fq6 &elt_inv) +{ + enter_block("Call to edwards_final_exponentiation_first_chunk"); + + /* (q^3-1)*(q+1) */ + + /* elt_q3 = elt^(q^3) */ + const edwards_Fq6 elt_q3 = elt.Frobenius_map(3); + /* elt_q3_over_elt = elt^(q^3-1) */ + const edwards_Fq6 elt_q3_over_elt = elt_q3 * elt_inv; + /* alpha = elt^((q^3-1) * q) */ + const edwards_Fq6 alpha = elt_q3_over_elt.Frobenius_map(1); + /* beta = elt^((q^3-1)*(q+1) */ + const edwards_Fq6 beta = alpha * elt_q3_over_elt; + leave_block("Call to edwards_final_exponentiation_first_chunk"); + return beta; +} + +edwards_GT edwards_final_exponentiation(const edwards_Fq6 &elt) +{ + enter_block("Call to edwards_final_exponentiation"); + const edwards_Fq6 elt_inv = elt.inverse(); + const edwards_Fq6 elt_to_first_chunk = edwards_final_exponentiation_first_chunk(elt, elt_inv); + const edwards_Fq6 elt_inv_to_first_chunk = edwards_final_exponentiation_first_chunk(elt_inv, elt); + edwards_GT result = edwards_final_exponentiation_last_chunk(elt_to_first_chunk, elt_inv_to_first_chunk); + leave_block("Call to edwards_final_exponentiation"); + + return result; +} + +edwards_tate_G2_precomp edwards_tate_precompute_G2(const edwards_G2& Q) +{ + enter_block("Call to edwards_tate_precompute_G2"); + edwards_G2 Qcopy = Q; + Qcopy.to_affine_coordinates(); + edwards_tate_G2_precomp result; + result.y0 = Qcopy.Y * Qcopy.Z.inverse(); // Y/Z + result.eta = (Qcopy.Z+Qcopy.Y) * edwards_Fq6::mul_by_non_residue(Qcopy.X).inverse(); // (Z+Y)/(nqr*X) + leave_block("Call to edwards_tate_precompute_G2"); + + return result; +} + +struct extended_edwards_G1_projective { + edwards_Fq X; + edwards_Fq Y; + edwards_Fq Z; + edwards_Fq T; + + void print() const + { + printf("extended edwards_G1 projective X/Y/Z/T:\n"); + X.print(); + Y.print(); + Z.print(); + T.print(); + } + + void test_invariant() const + { + assert(T*Z == X*Y); + } +}; + +void doubling_step_for_miller_loop(extended_edwards_G1_projective ¤t, + edwards_Fq_conic_coefficients &cc) +{ + const edwards_Fq &X = current.X, &Y = current.Y, &Z = current.Z, &T = current.T; + const edwards_Fq A = X.squared(); // A = X1^2 + const edwards_Fq B = Y.squared(); // B = Y1^2 + const edwards_Fq C = Z.squared(); // C = Z1^2 + const edwards_Fq D = (X+Y).squared(); // D = (X1+Y1)^2 + const edwards_Fq E = (Y+Z).squared(); // E = (Y1+Z1)^2 + const edwards_Fq F = D-(A+B); // F = D-(A+B) + const edwards_Fq G = E-(B+C); // G = E-(B+C) + const edwards_Fq &H = A; // H = A (edwards_a=1) + const edwards_Fq I = H+B; // I = H+B + const edwards_Fq J = C-I; // J = C-I + const edwards_Fq K = J+C; // K = J+C + + cc.c_ZZ = Y*(T-X); // c_ZZ = 2*Y1*(T1-X1) + cc.c_ZZ = cc.c_ZZ + cc.c_ZZ; + + cc.c_XY = J+J+G; // c_XY = 2*J+G + cc.c_XZ = X*T-B; // c_XZ = 2*(X1*T1-B) (edwards_a=1) + cc.c_XZ = cc.c_XZ + cc.c_XZ; + + current.X = F*K; // X3 = F*K + current.Y = I*(B-H); // Y3 = I*(B-H) + current.Z = I*K; // Z3 = I*K + current.T = F*(B-H); // T3 = F*(B-H) + +#ifdef DEBUG + current.test_invariant(); +#endif +} + +void full_addition_step_for_miller_loop(const extended_edwards_G1_projective &base, + extended_edwards_G1_projective ¤t, + edwards_Fq_conic_coefficients &cc) +{ + const edwards_Fq &X1 = current.X, &Y1 = current.Y, &Z1 = current.Z, &T1 = current.T; + const edwards_Fq &X2 = base.X, &Y2 = base.Y, &Z2 = base.Z, &T2 = base.T; + + const edwards_Fq A = X1*X2; // A = X1*X2 + const edwards_Fq B = Y1*Y2; // B = Y1*Y2 + const edwards_Fq C = Z1*T2; // C = Z1*T2 + const edwards_Fq D = T1*Z2; // D = T1*Z2 + const edwards_Fq E = D+C; // E = D+C + const edwards_Fq F = (X1-Y1)*(X2+Y2)+B-A; // F = (X1-Y1)*(X2+Y2)+B-A + const edwards_Fq G = B + A; // G = B + A (edwards_a=1) + const edwards_Fq H = D-C; // H = D-C + const edwards_Fq I = T1*T2; // I = T1*T2 + + cc.c_ZZ = (T1-X1)*(T2+X2)-I+A; // c_ZZ = (T1-X1)*(T2+X2)-I+A + cc.c_XY = X1*Z2-X2*Z1+F; // c_XY = X1*Z2-X2*Z1+F + cc.c_XZ = (Y1-T1)*(Y2+T2)-B+I-H; // c_XZ = (Y1-T1)*(Y2+T2)-B+I-H + current.X = E*F; // X3 = E*F + current.Y = G*H; // Y3 = G*H + current.Z = F*G; // Z3 = F*G + current.T = E*H; // T3 = E*H + +#ifdef DEBUG + current.test_invariant(); +#endif +} + +void mixed_addition_step_for_miller_loop(const extended_edwards_G1_projective &base, + extended_edwards_G1_projective ¤t, + edwards_Fq_conic_coefficients &cc) +{ + const edwards_Fq &X1 = current.X, &Y1 = current.Y, &Z1 = current.Z, &T1 = current.T; + const edwards_Fq &X2 = base.X, &Y2 = base.Y, &T2 = base.T; + + const edwards_Fq A = X1*X2; // A = X1*X2 + const edwards_Fq B = Y1*Y2; // B = Y1*Y2 + const edwards_Fq C = Z1*T2; // C = Z1*T2 + const edwards_Fq D = T1; // D = T1*Z2 + const edwards_Fq E = D+C; // E = D+C + const edwards_Fq F = (X1-Y1)*(X2+Y2)+B-A; // F = (X1-Y1)*(X2+Y2)+B-A + const edwards_Fq G = B + A; // G = B + A (edwards_a=1) + const edwards_Fq H = D-C; // H = D-C + const edwards_Fq I = T1*T2; // I = T1*T2 + + cc.c_ZZ = (T1-X1)*(T2+X2)-I+A; // c_ZZ = (T1-X1)*(T2+X2)-I+A + cc.c_XY = X1-X2*Z1+F; // c_XY = X1*Z2-X2*Z1+F + cc.c_XZ = (Y1-T1)*(Y2+T2)-B+I-H; // c_XZ = (Y1-T1)*(Y2+T2)-B+I-H + current.X = E*F; // X3 = E*F + current.Y = G*H; // Y3 = G*H + current.Z = F*G; // Z3 = F*G + current.T = E*H; // T3 = E*H + +#ifdef DEBUG + current.test_invariant(); +#endif +} + +edwards_tate_G1_precomp edwards_tate_precompute_G1(const edwards_G1& P) +{ + enter_block("Call to edwards_tate_precompute_G1"); + edwards_tate_G1_precomp result; + + edwards_G1 Pcopy = P; + Pcopy.to_affine_coordinates(); + + extended_edwards_G1_projective P_ext; + P_ext.X = Pcopy.X; + P_ext.Y = Pcopy.Y; + P_ext.Z = Pcopy.Z; + P_ext.T = Pcopy.X*Pcopy.Y; + + extended_edwards_G1_projective R = P_ext; + + bool found_one = false; + for (long i = edwards_modulus_r.max_bits(); i >= 0; --i) + { + const bool bit = edwards_modulus_r.test_bit(i); + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + edwards_modulus_r (skipping leading zeros) in MSB to LSB + order */ + edwards_Fq_conic_coefficients cc; + doubling_step_for_miller_loop(R, cc); + result.push_back(cc); + + if (bit) + { + mixed_addition_step_for_miller_loop(P_ext, R, cc); + result.push_back(cc); + } + } + + leave_block("Call to edwards_tate_precompute_G1"); + return result; +} + +edwards_Fq6 edwards_tate_miller_loop(const edwards_tate_G1_precomp &prec_P, + const edwards_tate_G2_precomp &prec_Q) +{ + enter_block("Call to edwards_tate_miller_loop"); + + edwards_Fq6 f = edwards_Fq6::one(); + + bool found_one = false; + size_t idx = 0; + for (long i = edwards_modulus_r.max_bits()-1; i >= 0; --i) + { + const bool bit = edwards_modulus_r.test_bit(i); + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + edwards_modulus_r (skipping leading zeros) in MSB to LSB + order */ + edwards_Fq_conic_coefficients cc = prec_P[idx++]; + edwards_Fq6 g_RR_at_Q = edwards_Fq6(edwards_Fq3(cc.c_XZ, edwards_Fq(0l), edwards_Fq(0l)) + cc.c_XY * prec_Q.y0, + cc.c_ZZ * prec_Q.eta); + f = f.squared() * g_RR_at_Q; + if (bit) + { + cc = prec_P[idx++]; + + edwards_Fq6 g_RP_at_Q = edwards_Fq6(edwards_Fq3(cc.c_XZ, edwards_Fq(0l), edwards_Fq(0l)) + cc.c_XY * prec_Q.y0, + cc.c_ZZ * prec_Q.eta); + f = f * g_RP_at_Q; + } + } + leave_block("Call to edwards_tate_miller_loop"); + + return f; +} + +edwards_Fq6 edwards_tate_pairing(const edwards_G1& P, const edwards_G2 &Q) +{ + enter_block("Call to edwards_tate_pairing"); + edwards_tate_G1_precomp prec_P = edwards_tate_precompute_G1(P); + edwards_tate_G2_precomp prec_Q = edwards_tate_precompute_G2(Q); + edwards_Fq6 result = edwards_tate_miller_loop(prec_P, prec_Q); + leave_block("Call to edwards_tate_pairing"); + return result; +} + +edwards_GT edwards_tate_reduced_pairing(const edwards_G1 &P, const edwards_G2 &Q) +{ + enter_block("Call to edwards_tate_reduced_pairing"); + const edwards_Fq6 f = edwards_tate_pairing(P, Q); + const edwards_GT result = edwards_final_exponentiation(f); + leave_block("Call to edwards_tate_reduce_pairing"); + return result; +} + +struct extended_edwards_G2_projective { + edwards_Fq3 X; + edwards_Fq3 Y; + edwards_Fq3 Z; + edwards_Fq3 T; + + void print() const + { + printf("extended edwards_G2 projective X/Y/Z/T:\n"); + X.print(); + Y.print(); + Z.print(); + T.print(); + } + + void test_invariant() const + { + assert(T*Z == X*Y); + } +}; + +void doubling_step_for_flipped_miller_loop(extended_edwards_G2_projective ¤t, + edwards_Fq3_conic_coefficients &cc) +{ + const edwards_Fq3 &X = current.X, &Y = current.Y, &Z = current.Z, &T = current.T; + const edwards_Fq3 A = X.squared(); // A = X1^2 + const edwards_Fq3 B = Y.squared(); // B = Y1^2 + const edwards_Fq3 C = Z.squared(); // C = Z1^2 + const edwards_Fq3 D = (X+Y).squared(); // D = (X1+Y1)^2 + const edwards_Fq3 E = (Y+Z).squared(); // E = (Y1+Z1)^2 + const edwards_Fq3 F = D-(A+B); // F = D-(A+B) + const edwards_Fq3 G = E-(B+C); // G = E-(B+C) + const edwards_Fq3 H = edwards_G2::mul_by_a(A); // edwards_param_twist_coeff_a is 1 * X for us + // H = twisted_a * A + const edwards_Fq3 I = H+B; // I = H+B + const edwards_Fq3 J = C-I; // J = C-I + const edwards_Fq3 K = J+C; // K = J+C + + cc.c_ZZ = Y*(T-X); // c_ZZ = 2*Y1*(T1-X1) + cc.c_ZZ = cc.c_ZZ + cc.c_ZZ; + + // c_XY = 2*(C-edwards_a * A * delta_3-B)+G (edwards_a = 1 for us) + cc.c_XY = C - edwards_G2::mul_by_a(A) - B; // edwards_param_twist_coeff_a is 1 * X for us + cc.c_XY = cc.c_XY + cc.c_XY + G; + + // c_XZ = 2*(edwards_a*X1*T1*delta_3-B) (edwards_a = 1 for us) + cc.c_XZ = edwards_G2::mul_by_a(X * T) - B; // edwards_param_twist_coeff_a is 1 * X for us + cc.c_XZ = cc.c_XZ + cc.c_XZ; + + current.X = F*K; // X3 = F*K + current.Y = I*(B-H); // Y3 = I*(B-H) + current.Z = I*K; // Z3 = I*K + current.T = F*(B-H); // T3 = F*(B-H) +#ifdef DEBUG + current.test_invariant(); +#endif +} + +void full_addition_step_for_flipped_miller_loop(const extended_edwards_G2_projective &base, + extended_edwards_G2_projective ¤t, + edwards_Fq3_conic_coefficients &cc) +{ + const edwards_Fq3 &X1 = current.X, &Y1 = current.Y, &Z1 = current.Z, &T1 = current.T; + const edwards_Fq3 &X2 = base.X, &Y2 = base.Y, &Z2 = base.Z, &T2 = base.T; + + const edwards_Fq3 A = X1*X2; // A = X1*X2 + const edwards_Fq3 B = Y1*Y2; // B = Y1*Y2 + const edwards_Fq3 C = Z1*T2; // C = Z1*T2 + const edwards_Fq3 D = T1*Z2; // D = T1*Z2 + const edwards_Fq3 E = D+C; // E = D+C + const edwards_Fq3 F = (X1-Y1)*(X2+Y2)+B-A; // F = (X1-Y1)*(X2+Y2)+B-A + // G = B + twisted_edwards_a * A + const edwards_Fq3 G = B + edwards_G2::mul_by_a(A); // edwards_param_twist_coeff_a is 1*X for us + const edwards_Fq3 H = D-C; // H = D-C + const edwards_Fq3 I = T1*T2; // I = T1*T2 + + // c_ZZ = delta_3* ((T1-X1)*(T2+X2)-I+A) + cc.c_ZZ = edwards_G2::mul_by_a((T1-X1)*(T2+X2)-I+A); // edwards_param_twist_coeff_a is 1*X for us + + cc.c_XY = X1*Z2-X2*Z1+F; // c_XY = X1*Z2-X2*Z1+F + cc.c_XZ = (Y1-T1)*(Y2+T2)-B+I-H; // c_XZ = (Y1-T1)*(Y2+T2)-B+I-H + current.X = E*F; // X3 = E*F + current.Y = G*H; // Y3 = G*H + current.Z = F*G; // Z3 = F*G + current.T = E*H; // T3 = E*H + +#ifdef DEBUG + current.test_invariant(); +#endif +} + +void mixed_addition_step_for_flipped_miller_loop(const extended_edwards_G2_projective &base, + extended_edwards_G2_projective ¤t, + edwards_Fq3_conic_coefficients &cc) +{ + const edwards_Fq3 &X1 = current.X, &Y1 = current.Y, &Z1 = current.Z, &T1 = current.T; + const edwards_Fq3 &X2 = base.X, &Y2 = base.Y, &T2 = base.T; + + const edwards_Fq3 A = X1*X2; // A = X1*X2 + const edwards_Fq3 B = Y1*Y2; // B = Y1*Y2 + const edwards_Fq3 C = Z1*T2; // C = Z1*T2 + const edwards_Fq3 E = T1+C; // E = T1+C + const edwards_Fq3 F = (X1-Y1)*(X2+Y2)+B-A; // F = (X1-Y1)*(X2+Y2)+B-A + // G = B + twisted_edwards_a * A + const edwards_Fq3 G = B + edwards_G2::mul_by_a(A); // edwards_param_twist_coeff_a is 1*X for us + const edwards_Fq3 H = T1-C; // H = T1-C + const edwards_Fq3 I = T1*T2; // I = T1*T2 + + // c_ZZ = delta_3* ((T1-X1)*(T2+X2)-I+A) + cc.c_ZZ = edwards_G2::mul_by_a((T1-X1)*(T2+X2)-I+A); // edwards_param_twist_coeff_a is 1*X for us + + cc.c_XY = X1-X2*Z1+F; // c_XY = X1*Z2-X2*Z1+F + cc.c_XZ = (Y1-T1)*(Y2+T2)-B+I-H; // c_XZ = (Y1-T1)*(Y2+T2)-B+I-H + current.X = E*F; // X3 = E*F + current.Y = G*H; // Y3 = G*H + current.Z = F*G; // Z3 = F*G + current.T = E*H; // T3 = E*H + +#ifdef DEBUG + current.test_invariant(); +#endif +} + +edwards_ate_G1_precomp edwards_ate_precompute_G1(const edwards_G1& P) +{ + enter_block("Call to edwards_ate_precompute_G1"); + edwards_G1 Pcopy = P; + Pcopy.to_affine_coordinates(); + edwards_ate_G1_precomp result; + result.P_XY = Pcopy.X*Pcopy.Y; + result.P_XZ = Pcopy.X; // P.X * P.Z but P.Z = 1 + result.P_ZZplusYZ = (edwards_Fq::one() + Pcopy.Y); // (P.Z + P.Y) * P.Z but P.Z = 1 + leave_block("Call to edwards_ate_precompute_G1"); + return result; +} + +edwards_ate_G2_precomp edwards_ate_precompute_G2(const edwards_G2& Q) +{ + enter_block("Call to edwards_ate_precompute_G2"); + const bigint &loop_count = edwards_ate_loop_count; + edwards_ate_G2_precomp result; + + edwards_G2 Qcopy(Q); + Qcopy.to_affine_coordinates(); + + extended_edwards_G2_projective Q_ext; + Q_ext.X = Qcopy.X; + Q_ext.Y = Qcopy.Y; + Q_ext.Z = Qcopy.Z; + Q_ext.T = Qcopy.X*Qcopy.Y; + + extended_edwards_G2_projective R = Q_ext; + + bool found_one = false; + for (long i = loop_count.max_bits()-1; i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + edwards_Fq3_conic_coefficients cc; + doubling_step_for_flipped_miller_loop(R, cc); + result.push_back(cc); + if (bit) + { + mixed_addition_step_for_flipped_miller_loop(Q_ext, R, cc); + result.push_back(cc); + } + } + + leave_block("Call to edwards_ate_precompute_G2"); + return result; +} + +edwards_Fq6 edwards_ate_miller_loop(const edwards_ate_G1_precomp &prec_P, + const edwards_ate_G2_precomp &prec_Q) +{ + enter_block("Call to edwards_ate_miller_loop"); + const bigint &loop_count = edwards_ate_loop_count; + + edwards_Fq6 f = edwards_Fq6::one(); + + bool found_one = false; + size_t idx = 0; + for (long i = loop_count.max_bits()-1; i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + edwards_param_p (skipping leading zeros) in MSB to LSB + order */ + edwards_Fq3_conic_coefficients cc = prec_Q[idx++]; + + edwards_Fq6 g_RR_at_P = edwards_Fq6(prec_P.P_XY * cc.c_XY + prec_P.P_XZ * cc.c_XZ, + prec_P.P_ZZplusYZ * cc.c_ZZ); + f = f.squared() * g_RR_at_P; + if (bit) + { + cc = prec_Q[idx++]; + edwards_Fq6 g_RQ_at_P = edwards_Fq6(prec_P.P_ZZplusYZ * cc.c_ZZ, + prec_P.P_XY * cc.c_XY + prec_P.P_XZ * cc.c_XZ); + f = f * g_RQ_at_P; + } + } + leave_block("Call to edwards_ate_miller_loop"); + + return f; +} + +edwards_Fq6 edwards_ate_double_miller_loop(const edwards_ate_G1_precomp &prec_P1, + const edwards_ate_G2_precomp &prec_Q1, + const edwards_ate_G1_precomp &prec_P2, + const edwards_ate_G2_precomp &prec_Q2) +{ + enter_block("Call to edwards_ate_double_miller_loop"); + const bigint &loop_count = edwards_ate_loop_count; + + edwards_Fq6 f = edwards_Fq6::one(); + + bool found_one = false; + size_t idx = 0; + for (long i = loop_count.max_bits()-1; i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + edwards_param_p (skipping leading zeros) in MSB to LSB + order */ + edwards_Fq3_conic_coefficients cc1 = prec_Q1[idx]; + edwards_Fq3_conic_coefficients cc2 = prec_Q2[idx]; + ++idx; + + edwards_Fq6 g_RR_at_P1 = edwards_Fq6(prec_P1.P_XY * cc1.c_XY + prec_P1.P_XZ * cc1.c_XZ, + prec_P1.P_ZZplusYZ * cc1.c_ZZ); + + edwards_Fq6 g_RR_at_P2 = edwards_Fq6(prec_P2.P_XY * cc2.c_XY + prec_P2.P_XZ * cc2.c_XZ, + prec_P2.P_ZZplusYZ * cc2.c_ZZ); + f = f.squared() * g_RR_at_P1 * g_RR_at_P2; + + if (bit) + { + cc1 = prec_Q1[idx]; + cc2 = prec_Q2[idx]; + ++idx; + edwards_Fq6 g_RQ_at_P1 = edwards_Fq6(prec_P1.P_ZZplusYZ * cc1.c_ZZ, + prec_P1.P_XY * cc1.c_XY + prec_P1.P_XZ * cc1.c_XZ); + edwards_Fq6 g_RQ_at_P2 = edwards_Fq6(prec_P2.P_ZZplusYZ * cc2.c_ZZ, + prec_P2.P_XY * cc2.c_XY + prec_P2.P_XZ * cc2.c_XZ); + f = f * g_RQ_at_P1 * g_RQ_at_P2; + } + } + leave_block("Call to edwards_ate_double_miller_loop"); + + return f; +} + +edwards_Fq6 edwards_ate_pairing(const edwards_G1& P, const edwards_G2 &Q) +{ + enter_block("Call to edwards_ate_pairing"); + edwards_ate_G1_precomp prec_P = edwards_ate_precompute_G1(P); + edwards_ate_G2_precomp prec_Q = edwards_ate_precompute_G2(Q); + edwards_Fq6 result = edwards_ate_miller_loop(prec_P, prec_Q); + leave_block("Call to edwards_ate_pairing"); + return result; +} + +edwards_GT edwards_ate_reduced_pairing(const edwards_G1 &P, const edwards_G2 &Q) +{ + enter_block("Call to edwards_ate_reduced_pairing"); + const edwards_Fq6 f = edwards_ate_pairing(P, Q); + const edwards_GT result = edwards_final_exponentiation(f); + leave_block("Call to edwards_ate_reduced_pairing"); + return result; +} + +edwards_G1_precomp edwards_precompute_G1(const edwards_G1& P) +{ + return edwards_ate_precompute_G1(P); +} + +edwards_G2_precomp edwards_precompute_G2(const edwards_G2& Q) +{ + return edwards_ate_precompute_G2(Q); +} + +edwards_Fq6 edwards_miller_loop(const edwards_G1_precomp &prec_P, + const edwards_G2_precomp &prec_Q) +{ + return edwards_ate_miller_loop(prec_P, prec_Q); +} + +edwards_Fq6 edwards_double_miller_loop(const edwards_G1_precomp &prec_P1, + const edwards_G2_precomp &prec_Q1, + const edwards_G1_precomp &prec_P2, + const edwards_G2_precomp &prec_Q2) +{ + return edwards_ate_double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); +} + +edwards_Fq6 edwards_pairing(const edwards_G1& P, + const edwards_G2 &Q) +{ + return edwards_ate_pairing(P, Q); +} + +edwards_GT edwards_reduced_pairing(const edwards_G1 &P, + const edwards_G2 &Q) +{ + return edwards_ate_reduced_pairing(P, Q); +} +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/edwards/edwards_pairing.d b/privacy/zsl/zsl/algebra/curves/edwards/edwards_pairing.d new file mode 100644 index 0000000..355afc7 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/edwards/edwards_pairing.d @@ -0,0 +1,20 @@ +src/algebra/curves/edwards/edwards_pairing.o: \ + src/algebra/curves/edwards/edwards_pairing.cpp \ + src/algebra/curves/edwards/edwards_pairing.hpp \ + src/algebra/curves/edwards/edwards_init.hpp \ + src/algebra/curves/public_params.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc src/algebra/fields/fp3.hpp \ + src/algebra/fields/fp3.tcc src/algebra/fields/fp6_2over3.hpp \ + src/algebra/fields/fp2.hpp src/algebra/fields/fp2.tcc \ + src/algebra/fields/fp6_2over3.tcc \ + src/algebra/scalar_multiplication/wnaf.hpp \ + src/algebra/scalar_multiplication/wnaf.tcc \ + src/algebra/curves/edwards/edwards_g1.hpp \ + src/algebra/curves/curve_utils.hpp src/algebra/curves/curve_utils.tcc \ + src/algebra/curves/edwards/edwards_g2.hpp src/common/profiling.hpp diff --git a/privacy/zsl/zsl/algebra/curves/edwards/edwards_pairing.hpp b/privacy/zsl/zsl/algebra/curves/edwards/edwards_pairing.hpp new file mode 100644 index 0000000..f838ae3 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/edwards/edwards_pairing.hpp @@ -0,0 +1,122 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EDWARDS_PAIRING_HPP_ +#define EDWARDS_PAIRING_HPP_ +#include +#include "algebra/curves/edwards/edwards_init.hpp" + +namespace libsnark { + +/* final exponentiation */ + +edwards_Fq6 edwards_final_exponentiation_last_chunk(const edwards_Fq6 &elt, + const edwards_Fq6 &elt_inv); +edwards_Fq6 edwards_final_exponentiation_first_chunk(const edwards_Fq6 &elt, + const edwards_Fq6 &elt_inv); +edwards_GT edwards_final_exponentiation(const edwards_Fq6 &elt); + +/* Tate pairing */ + +struct edwards_Fq_conic_coefficients { + edwards_Fq c_ZZ; + edwards_Fq c_XY; + edwards_Fq c_XZ; + + bool operator==(const edwards_Fq_conic_coefficients &other) const; + friend std::ostream& operator<<(std::ostream &out, const edwards_Fq_conic_coefficients &cc); + friend std::istream& operator>>(std::istream &in, edwards_Fq_conic_coefficients &cc); +}; +typedef std::vector edwards_tate_G1_precomp; + +std::ostream& operator<<(std::ostream& out, const edwards_tate_G1_precomp &prec_P); +std::istream& operator>>(std::istream& in, edwards_tate_G1_precomp &prec_P); + +struct edwards_tate_G2_precomp { + edwards_Fq3 y0, eta; + + bool operator==(const edwards_tate_G2_precomp &other) const; + friend std::ostream& operator<<(std::ostream &out, const edwards_tate_G2_precomp &prec_Q); + friend std::istream& operator>>(std::istream &in, edwards_tate_G2_precomp &prec_Q); +}; + +edwards_tate_G1_precomp edwards_tate_precompute_G1(const edwards_G1& P); +edwards_tate_G2_precomp edwards_tate_precompute_G2(const edwards_G2& Q); + +edwards_Fq6 edwards_tate_miller_loop(const edwards_tate_G1_precomp &prec_P, + const edwards_tate_G2_precomp &prec_Q); + +edwards_Fq6 edwards_tate_pairing(const edwards_G1& P, + const edwards_G2 &Q); +edwards_GT edwards_tate_reduced_pairing(const edwards_G1 &P, + const edwards_G2 &Q); + +/* ate pairing */ + +struct edwards_Fq3_conic_coefficients { + edwards_Fq3 c_ZZ; + edwards_Fq3 c_XY; + edwards_Fq3 c_XZ; + + bool operator==(const edwards_Fq3_conic_coefficients &other) const; + friend std::ostream& operator<<(std::ostream &out, const edwards_Fq3_conic_coefficients &cc); + friend std::istream& operator>>(std::istream &in, edwards_Fq3_conic_coefficients &cc); +}; +typedef std::vector edwards_ate_G2_precomp; + +std::ostream& operator<<(std::ostream& out, const edwards_ate_G2_precomp &prec_Q); +std::istream& operator>>(std::istream& in, edwards_ate_G2_precomp &prec_Q); + +struct edwards_ate_G1_precomp { + edwards_Fq P_XY; + edwards_Fq P_XZ; + edwards_Fq P_ZZplusYZ; + + bool operator==(const edwards_ate_G1_precomp &other) const; + friend std::ostream& operator<<(std::ostream &out, const edwards_ate_G1_precomp &prec_P); + friend std::istream& operator>>(std::istream &in, edwards_ate_G1_precomp &prec_P); +}; + +edwards_ate_G1_precomp edwards_ate_precompute_G1(const edwards_G1& P); +edwards_ate_G2_precomp edwards_ate_precompute_G2(const edwards_G2& Q); + +edwards_Fq6 edwards_ate_miller_loop(const edwards_ate_G1_precomp &prec_P, + const edwards_ate_G2_precomp &prec_Q); +edwards_Fq6 edwards_ate_double_miller_loop(const edwards_ate_G1_precomp &prec_P1, + const edwards_ate_G2_precomp &prec_Q1, + const edwards_ate_G1_precomp &prec_P2, + const edwards_ate_G2_precomp &prec_Q2); + +edwards_Fq6 edwards_ate_pairing(const edwards_G1& P, + const edwards_G2 &Q); +edwards_GT edwards_ate_reduced_pairing(const edwards_G1 &P, + const edwards_G2 &Q); + +/* choice of pairing */ + +typedef edwards_ate_G1_precomp edwards_G1_precomp; +typedef edwards_ate_G2_precomp edwards_G2_precomp; + +edwards_G1_precomp edwards_precompute_G1(const edwards_G1& P); +edwards_G2_precomp edwards_precompute_G2(const edwards_G2& Q); + +edwards_Fq6 edwards_miller_loop(const edwards_G1_precomp &prec_P, + const edwards_G2_precomp &prec_Q); + +edwards_Fq6 edwards_double_miller_loop(const edwards_G1_precomp &prec_P1, + const edwards_G2_precomp &prec_Q1, + const edwards_G1_precomp &prec_P2, + const edwards_G2_precomp &prec_Q2); + +edwards_Fq6 edwards_pairing(const edwards_G1& P, + const edwards_G2 &Q); + +edwards_GT edwards_reduced_pairing(const edwards_G1 &P, + const edwards_G2 &Q); + +} // libsnark +#endif // EDWARDS_PAIRING_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/edwards/edwards_pp.cpp b/privacy/zsl/zsl/algebra/curves/edwards/edwards_pp.cpp new file mode 100644 index 0000000..5af4010 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/edwards/edwards_pp.cpp @@ -0,0 +1,58 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/edwards/edwards_pp.hpp" + +namespace libsnark { + +void edwards_pp::init_public_params() +{ + init_edwards_params(); +} + +edwards_GT edwards_pp::final_exponentiation(const edwards_Fq6 &elt) +{ + return edwards_final_exponentiation(elt); +} + +edwards_G1_precomp edwards_pp::precompute_G1(const edwards_G1 &P) +{ + return edwards_precompute_G1(P); +} + +edwards_G2_precomp edwards_pp::precompute_G2(const edwards_G2 &Q) +{ + return edwards_precompute_G2(Q); +} + +edwards_Fq6 edwards_pp::miller_loop(const edwards_G1_precomp &prec_P, + const edwards_G2_precomp &prec_Q) +{ + return edwards_miller_loop(prec_P, prec_Q); +} + +edwards_Fq6 edwards_pp::double_miller_loop(const edwards_G1_precomp &prec_P1, + const edwards_G2_precomp &prec_Q1, + const edwards_G1_precomp &prec_P2, + const edwards_G2_precomp &prec_Q2) +{ + return edwards_double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); +} + +edwards_Fq6 edwards_pp::pairing(const edwards_G1 &P, + const edwards_G2 &Q) +{ + return edwards_pairing(P, Q); +} + +edwards_Fq6 edwards_pp::reduced_pairing(const edwards_G1 &P, + const edwards_G2 &Q) +{ + return edwards_reduced_pairing(P, Q); +} + +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/edwards/edwards_pp.d b/privacy/zsl/zsl/algebra/curves/edwards/edwards_pp.d new file mode 100644 index 0000000..1391b36 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/edwards/edwards_pp.d @@ -0,0 +1,21 @@ +src/algebra/curves/edwards/edwards_pp.o: \ + src/algebra/curves/edwards/edwards_pp.cpp \ + src/algebra/curves/edwards/edwards_pp.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/edwards/edwards_init.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc src/algebra/fields/fp3.hpp \ + src/algebra/fields/fp3.tcc src/algebra/fields/fp6_2over3.hpp \ + src/algebra/fields/fp2.hpp src/algebra/fields/fp2.tcc \ + src/algebra/fields/fp6_2over3.tcc \ + src/algebra/scalar_multiplication/wnaf.hpp \ + src/algebra/scalar_multiplication/wnaf.tcc \ + src/algebra/curves/edwards/edwards_g1.hpp \ + src/algebra/curves/curve_utils.hpp src/algebra/curves/curve_utils.tcc \ + src/algebra/curves/edwards/edwards_g2.hpp \ + src/algebra/curves/edwards/edwards_pairing.hpp diff --git a/privacy/zsl/zsl/algebra/curves/edwards/edwards_pp.hpp b/privacy/zsl/zsl/algebra/curves/edwards/edwards_pp.hpp new file mode 100644 index 0000000..32ca85d --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/edwards/edwards_pp.hpp @@ -0,0 +1,50 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EDWARDS_PP_HPP_ +#define EDWARDS_PP_HPP_ +#include "algebra/curves/public_params.hpp" +#include "algebra/curves/edwards/edwards_init.hpp" +#include "algebra/curves/edwards/edwards_g1.hpp" +#include "algebra/curves/edwards/edwards_g2.hpp" +#include "algebra/curves/edwards/edwards_pairing.hpp" + +namespace libsnark { + +class edwards_pp { +public: + typedef edwards_Fr Fp_type; + typedef edwards_G1 G1_type; + typedef edwards_G2 G2_type; + typedef edwards_G1_precomp G1_precomp_type; + typedef edwards_G2_precomp G2_precomp_type; + typedef edwards_Fq Fq_type; + typedef edwards_Fq3 Fqe_type; + typedef edwards_Fq6 Fqk_type; + typedef edwards_GT GT_type; + + static const bool has_affine_pairing = false; + + static void init_public_params(); + static edwards_GT final_exponentiation(const edwards_Fq6 &elt); + static edwards_G1_precomp precompute_G1(const edwards_G1 &P); + static edwards_G2_precomp precompute_G2(const edwards_G2 &Q); + static edwards_Fq6 miller_loop(const edwards_G1_precomp &prec_P, + const edwards_G2_precomp &prec_Q); + static edwards_Fq6 double_miller_loop(const edwards_G1_precomp &prec_P1, + const edwards_G2_precomp &prec_Q1, + const edwards_G1_precomp &prec_P2, + const edwards_G2_precomp &prec_Q2); + /* the following are used in test files */ + static edwards_Fq6 pairing(const edwards_G1 &P, + const edwards_G2 &Q); + static edwards_Fq6 reduced_pairing(const edwards_G1 &P, + const edwards_G2 &Q); +}; + +} // libsnark +#endif // EDWARDS_PP_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_g1.cpp b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_g1.cpp new file mode 100644 index 0000000..8c89b02 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_g1.cpp @@ -0,0 +1,505 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the MNT4 G1 group. + + See mnt4_g1.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/mnt/mnt4/mnt4_g1.hpp" + +namespace libsnark { + +#ifdef PROFILE_OP_COUNTS +long long mnt4_G1::add_cnt = 0; +long long mnt4_G1::dbl_cnt = 0; +#endif + +std::vector mnt4_G1::wnaf_window_table; +std::vector mnt4_G1::fixed_base_exp_window_table; +mnt4_G1 mnt4_G1::G1_zero; +mnt4_G1 mnt4_G1::G1_one; +mnt4_Fq mnt4_G1::coeff_a; +mnt4_Fq mnt4_G1::coeff_b; + +mnt4_G1::mnt4_G1() +{ + this->X_ = G1_zero.X_; + this->Y_ = G1_zero.Y_; + this->Z_ = G1_zero.Z_; +} + +void mnt4_G1::print() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + mnt4_G1 copy(*this); + copy.to_affine_coordinates(); + gmp_printf("(%Nd , %Nd)\n", + copy.X_.as_bigint().data, mnt4_Fq::num_limbs, + copy.Y_.as_bigint().data, mnt4_Fq::num_limbs); + } +} + +void mnt4_G1::print_coordinates() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + gmp_printf("(%Nd : %Nd : %Nd)\n", + this->X_.as_bigint().data, mnt4_Fq::num_limbs, + this->Y_.as_bigint().data, mnt4_Fq::num_limbs, + this->Z_.as_bigint().data, mnt4_Fq::num_limbs); + } +} + +void mnt4_G1::to_affine_coordinates() +{ + if (this->is_zero()) + { + this->X_ = mnt4_Fq::zero(); + this->Y_ = mnt4_Fq::one(); + this->Z_ = mnt4_Fq::zero(); + } + else + { + const mnt4_Fq Z_inv = Z_.inverse(); + this->X_ = this->X_ * Z_inv; + this->Y_ = this->Y_ * Z_inv; + this->Z_ = mnt4_Fq::one(); + } +} + +void mnt4_G1::to_special() +{ + this->to_affine_coordinates(); +} + +bool mnt4_G1::is_special() const +{ + return (this->is_zero() || this->Z_ == mnt4_Fq::one()); +} + +bool mnt4_G1::is_zero() const +{ + return (this->X_.is_zero() && this->Z_.is_zero()); +} + +bool mnt4_G1::operator==(const mnt4_G1 &other) const +{ + if (this->is_zero()) + { + return other.is_zero(); + } + + if (other.is_zero()) + { + return false; + } + + /* now neither is O */ + + // X1/Z1 = X2/Z2 <=> X1*Z2 = X2*Z1 + if ((this->X_ * other.Z_) != (other.X_ * this->Z_)) + { + return false; + } + + // Y1/Z1 = Y2/Z2 <=> Y1*Z2 = Y2*Z1 + if ((this->Y_ * other.Z_) != (other.Y_ * this->Z_)) + { + return false; + } + + return true; +} + +bool mnt4_G1::operator!=(const mnt4_G1& other) const +{ + return !(operator==(other)); +} + +mnt4_G1 mnt4_G1::operator+(const mnt4_G1 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case, and then all the rest + /* + The code below is equivalent to (but faster than) the snippet below: + + if (this->operator==(other)) + { + return this->dbl(); + } + else + { + return this->add(other); + } + */ + + const mnt4_Fq X1Z2 = (this->X_) * (other.Z_); // X1Z2 = X1*Z2 + const mnt4_Fq X2Z1 = (this->Z_) * (other.X_); // X2Z1 = X2*Z1 + + // (used both in add and double checks) + + const mnt4_Fq Y1Z2 = (this->Y_) * (other.Z_); // Y1Z2 = Y1*Z2 + const mnt4_Fq Y2Z1 = (this->Z_) * (other.Y_); // Y2Z1 = Y2*Z1 + + if (X1Z2 == X2Z1 && Y1Z2 == Y2Z1) + { + // perform dbl case + const mnt4_Fq XX = (this->X_).squared(); // XX = X1^2 + const mnt4_Fq ZZ = (this->Z_).squared(); // ZZ = Z1^2 + const mnt4_Fq w = mnt4_G1::coeff_a * ZZ + (XX + XX + XX); // w = a*ZZ + 3*XX + const mnt4_Fq Y1Z1 = (this->Y_) * (this->Z_); + const mnt4_Fq s = Y1Z1 + Y1Z1; // s = 2*Y1*Z1 + const mnt4_Fq ss = s.squared(); // ss = s^2 + const mnt4_Fq sss = s * ss; // sss = s*ss + const mnt4_Fq R = (this->Y_) * s; // R = Y1*s + const mnt4_Fq RR = R.squared(); // RR = R^2 + const mnt4_Fq B = ((this->X_)+R).squared()-XX-RR; // B = (X1+R)^2 - XX - RR + const mnt4_Fq h = w.squared() - (B+B); // h = w^2 - 2*B + const mnt4_Fq X3 = h * s; // X3 = h*s + const mnt4_Fq Y3 = w * (B-h)-(RR+RR); // Y3 = w*(B-h) - 2*RR + const mnt4_Fq Z3 = sss; // Z3 = sss + + return mnt4_G1(X3, Y3, Z3); + } + + // if we have arrived here we are in the add case + const mnt4_Fq Z1Z2 = (this->Z_) * (other.Z_); // Z1Z2 = Z1*Z2 + const mnt4_Fq u = Y2Z1 - Y1Z2; // u = Y2*Z1-Y1Z2 + const mnt4_Fq uu = u.squared(); // uu = u^2 + const mnt4_Fq v = X2Z1 - X1Z2; // v = X2*Z1-X1Z2 + const mnt4_Fq vv = v.squared(); // vv = v^2 + const mnt4_Fq vvv = v * vv; // vvv = v*vv + const mnt4_Fq R = vv * X1Z2; // R = vv*X1Z2 + const mnt4_Fq A = uu * Z1Z2 - (vvv + R + R); // A = uu*Z1Z2 - vvv - 2*R + const mnt4_Fq X3 = v * A; // X3 = v*A + const mnt4_Fq Y3 = u * (R-A) - vvv * Y1Z2; // Y3 = u*(R-A) - vvv*Y1Z2 + const mnt4_Fq Z3 = vvv * Z1Z2; // Z3 = vvv*Z1Z2 + + return mnt4_G1(X3, Y3, Z3); +} + +mnt4_G1 mnt4_G1::operator-() const +{ + return mnt4_G1(this->X_, -(this->Y_), this->Z_); +} + + +mnt4_G1 mnt4_G1::operator-(const mnt4_G1 &other) const +{ + return (*this) + (-other); +} + +mnt4_G1 mnt4_G1::add(const mnt4_G1 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return (*this); + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case + if (this->operator==(other)) + { + return this->dbl(); + } + +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#addition-add-1998-cmo-2 + + const mnt4_Fq Y1Z2 = (this->Y_) * (other.Z_); // Y1Z2 = Y1*Z2 + const mnt4_Fq X1Z2 = (this->X_) * (other.Z_); // X1Z2 = X1*Z2 + const mnt4_Fq Z1Z2 = (this->Z_) * (other.Z_); // Z1Z2 = Z1*Z2 + const mnt4_Fq u = (other.Y_) * (this->Z_) - Y1Z2; // u = Y2*Z1-Y1Z2 + const mnt4_Fq uu = u.squared(); // uu = u^2 + const mnt4_Fq v = (other.X_) * (this->Z_) - X1Z2; // v = X2*Z1-X1Z2 + const mnt4_Fq vv = v.squared(); // vv = v^2 + const mnt4_Fq vvv = v * vv; // vvv = v*vv + const mnt4_Fq R = vv * X1Z2; // R = vv*X1Z2 + const mnt4_Fq A = uu * Z1Z2 - (vvv + R + R); // A = uu*Z1Z2 - vvv - 2*R + const mnt4_Fq X3 = v * A; // X3 = v*A + const mnt4_Fq Y3 = u * (R-A) - vvv * Y1Z2; // Y3 = u*(R-A) - vvv*Y1Z2 + const mnt4_Fq Z3 = vvv * Z1Z2; // Z3 = vvv*Z1Z2 + + return mnt4_G1(X3, Y3, Z3); +} + +mnt4_G1 mnt4_G1::mixed_add(const mnt4_G1 &other) const +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#addition-add-1998-cmo-2 + //assert(other.Z == mnt4_Fq::one()); + + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return (*this); + } + +#ifdef DEBUG + assert(other.is_special()); +#endif + + const mnt4_Fq &X1Z2 = (this->X_); // X1Z2 = X1*Z2 (but other is special and not zero) + const mnt4_Fq X2Z1 = (this->Z_) * (other.X_); // X2Z1 = X2*Z1 + + // (used both in add and double checks) + + const mnt4_Fq &Y1Z2 = (this->Y_); // Y1Z2 = Y1*Z2 (but other is special and not zero) + const mnt4_Fq Y2Z1 = (this->Z_) * (other.Y_); // Y2Z1 = Y2*Z1 + + if (X1Z2 == X2Z1 && Y1Z2 == Y2Z1) + { + return this->dbl(); + } + + const mnt4_Fq u = Y2Z1 - this->Y_; // u = Y2*Z1-Y1 + const mnt4_Fq uu = u.squared(); // uu = u2 + const mnt4_Fq v = X2Z1 - this->X_; // v = X2*Z1-X1 + const mnt4_Fq vv = v.squared(); // vv = v2 + const mnt4_Fq vvv = v*vv; // vvv = v*vv + const mnt4_Fq R = vv * this->X_; // R = vv*X1 + const mnt4_Fq A = uu * this->Z_ - vvv - R - R; // A = uu*Z1-vvv-2*R + const mnt4_Fq X3 = v * A; // X3 = v*A + const mnt4_Fq Y3 = u*(R-A) - vvv * this->Y_; // Y3 = u*(R-A)-vvv*Y1 + const mnt4_Fq Z3 = vvv * this->Z_; // Z3 = vvv*Z1 + + return mnt4_G1(X3, Y3, Z3); +} + +mnt4_G1 mnt4_G1::dbl() const +{ +#ifdef PROFILE_OP_COUNTS + this->dbl_cnt++; +#endif + if (this->is_zero()) + { + return (*this); + } + else + { + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#doubling-dbl-2007-bl + + const mnt4_Fq XX = (this->X_).squared(); // XX = X1^2 + const mnt4_Fq ZZ = (this->Z_).squared(); // ZZ = Z1^2 + const mnt4_Fq w = mnt4_G1::coeff_a * ZZ + (XX + XX + XX); // w = a*ZZ + 3*XX + const mnt4_Fq Y1Z1 = (this->Y_) * (this->Z_); + const mnt4_Fq s = Y1Z1 + Y1Z1; // s = 2*Y1*Z1 + const mnt4_Fq ss = s.squared(); // ss = s^2 + const mnt4_Fq sss = s * ss; // sss = s*ss + const mnt4_Fq R = (this->Y_) * s; // R = Y1*s + const mnt4_Fq RR = R.squared(); // RR = R^2 + const mnt4_Fq B = ((this->X_)+R).squared()-XX-RR; // B = (X1+R)^2 - XX - RR + const mnt4_Fq h = w.squared() - (B+B); // h = w^2 - 2*B + const mnt4_Fq X3 = h * s; // X3 = h*s + const mnt4_Fq Y3 = w * (B-h)-(RR+RR); // Y3 = w*(B-h) - 2*RR + const mnt4_Fq Z3 = sss; // Z3 = sss + + return mnt4_G1(X3, Y3, Z3); + } +} + +bool mnt4_G1::is_well_formed() const +{ + if (this->is_zero()) + { + return true; + } + else + { + /* + y^2 = x^3 + ax + b + + We are using projective, so equation we need to check is actually + + (y/z)^2 = (x/z)^3 + a (x/z) + b + z y^2 = x^3 + a z^2 x + b z^3 + + z (y^2 - b z^2) = x ( x^2 + a z^2) + */ + const mnt4_Fq X2 = this->X_.squared(); + const mnt4_Fq Y2 = this->Y_.squared(); + const mnt4_Fq Z2 = this->Z_.squared(); + + return (this->Z_ * (Y2 - mnt4_G1::coeff_b * Z2) == this->X_ * (X2 + mnt4_G1::coeff_a * Z2)); + } +} + +mnt4_G1 mnt4_G1::zero() +{ + return G1_zero; +} + +mnt4_G1 mnt4_G1::one() +{ + return G1_one; +} + +mnt4_G1 mnt4_G1::random_element() +{ + return (scalar_field::random_element().as_bigint()) * G1_one; +} + +std::ostream& operator<<(std::ostream &out, const mnt4_G1 &g) +{ + mnt4_G1 copy(g); + copy.to_affine_coordinates(); + + out << (copy.is_zero() ? 1 : 0) << OUTPUT_SEPARATOR; +#ifdef NO_PT_COMPRESSION + out << copy.X_ << OUTPUT_SEPARATOR << copy.Y_; +#else + /* storing LSB of Y */ + out << copy.X_ << OUTPUT_SEPARATOR << (copy.Y_.as_bigint().data[0] & 1); +#endif + + return out; +} + +std::istream& operator>>(std::istream &in, mnt4_G1 &g) +{ + char is_zero; + mnt4_Fq tX, tY; + +#ifdef NO_PT_COMPRESSION + in >> is_zero >> tX >> tY; + is_zero -= '0'; +#else + in.read((char*)&is_zero, 1); + is_zero -= '0'; + consume_OUTPUT_SEPARATOR(in); + + unsigned char Y_lsb; + in >> tX; + consume_OUTPUT_SEPARATOR(in); + in.read((char*)&Y_lsb, 1); + Y_lsb -= '0'; + + // y = +/- sqrt(x^3 + a*x + b) + if (!is_zero) + { + mnt4_Fq tX2 = tX.squared(); + mnt4_Fq tY2 = (tX2 + mnt4_G1::coeff_a) * tX + mnt4_G1::coeff_b; + tY = tY2.sqrt(); + + if ((tY.as_bigint().data[0] & 1) != Y_lsb) + { + tY = -tY; + } + } +#endif + // using projective coordinates + if (!is_zero) + { + g.X_ = tX; + g.Y_ = tY; + g.Z_ = mnt4_Fq::one(); + } + else + { + g = mnt4_G1::zero(); + } + + return in; +} + +std::ostream& operator<<(std::ostream& out, const std::vector &v) +{ + out << v.size() << "\n"; + for (const mnt4_G1& t : v) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +std::istream& operator>>(std::istream& in, std::vector &v) +{ + v.clear(); + + size_t s; + in >> s; + + consume_newline(in); + + v.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + mnt4_G1 g; + in >> g; + consume_OUTPUT_NEWLINE(in); + v.emplace_back(g); + } + + return in; +} + +template<> +void batch_to_special_all_non_zeros(std::vector &vec) +{ + std::vector Z_vec; + Z_vec.reserve(vec.size()); + + for (auto &el: vec) + { + Z_vec.emplace_back(el.Z()); + } + batch_invert(Z_vec); + + const mnt4_Fq one = mnt4_Fq::one(); + + for (size_t i = 0; i < vec.size(); ++i) + { + vec[i] = mnt4_G1(vec[i].X() * Z_vec[i], vec[i].Y() * Z_vec[i], one); + } +} + +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_g1.d b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_g1.d new file mode 100644 index 0000000..1bc0c91 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_g1.d @@ -0,0 +1,17 @@ +src/algebra/curves/mnt/mnt4/mnt4_g1.o: \ + src/algebra/curves/mnt/mnt4/mnt4_g1.cpp \ + src/algebra/curves/mnt/mnt4/mnt4_g1.hpp \ + src/algebra/curves/curve_utils.hpp src/algebra/fields/bigint.hpp \ + src/common/serialization.hpp src/common/serialization.tcc \ + src/common/utils.hpp src/common/utils.tcc src/algebra/fields/bigint.tcc \ + src/algebra/curves/curve_utils.tcc \ + src/algebra/curves/mnt/mnt4/mnt4_init.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/mnt/mnt46_common.hpp src/algebra/fields/fp.hpp \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc src/algebra/fields/fp2.hpp \ + src/algebra/fields/fp2.tcc src/algebra/fields/fp4.hpp \ + src/algebra/fields/fp4.tcc src/algebra/scalar_multiplication/wnaf.hpp \ + src/algebra/scalar_multiplication/wnaf.tcc diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_g1.hpp b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_g1.hpp new file mode 100644 index 0000000..19e77bd --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_g1.hpp @@ -0,0 +1,109 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the MNT4 G1 group. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT4_G1_HPP_ +#define MNT4_G1_HPP_ + +#include + +#include "algebra/curves/curve_utils.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_init.hpp" + +namespace libsnark { + +class mnt4_G1; +std::ostream& operator<<(std::ostream &, const mnt4_G1&); +std::istream& operator>>(std::istream &, mnt4_G1&); + +class mnt4_G1 { +private: + mnt4_Fq X_, Y_, Z_; +public: +#ifdef PROFILE_OP_COUNTS + static long long add_cnt; + static long long dbl_cnt; +#endif + static std::vector wnaf_window_table; + static std::vector fixed_base_exp_window_table; + static mnt4_G1 G1_zero; + static mnt4_G1 G1_one; + static mnt4_Fq coeff_a; + static mnt4_Fq coeff_b; + + typedef mnt4_Fq base_field; + typedef mnt4_Fr scalar_field; + + // using projective coordinates + mnt4_G1(); + mnt4_G1(const mnt4_Fq& X, const mnt4_Fq& Y) : X_(X), Y_(Y), Z_(base_field::one()) {} + mnt4_G1(const mnt4_Fq& X, const mnt4_Fq& Y, const mnt4_Fq& Z) : X_(X), Y_(Y), Z_(Z) {} + + mnt4_Fq X() const { return X_; } + mnt4_Fq Y() const { return Y_; } + mnt4_Fq Z() const { return Z_; } + + void print() const; + void print_coordinates() const; + + void to_affine_coordinates(); + void to_special(); + bool is_special() const; + + bool is_zero() const; + + bool operator==(const mnt4_G1 &other) const; + bool operator!=(const mnt4_G1 &other) const; + + mnt4_G1 operator+(const mnt4_G1 &other) const; + mnt4_G1 operator-() const; + mnt4_G1 operator-(const mnt4_G1 &other) const; + + mnt4_G1 add(const mnt4_G1 &other) const; + mnt4_G1 mixed_add(const mnt4_G1 &other) const; + mnt4_G1 dbl() const; + + bool is_well_formed() const; + + static mnt4_G1 zero(); + static mnt4_G1 one(); + static mnt4_G1 random_element(); + + static size_t size_in_bits() { return mnt4_Fq::size_in_bits() + 1; } + static bigint base_field_char() { return mnt4_Fq::field_char(); } + static bigint order() { return mnt4_Fr::field_char(); } + + friend std::ostream& operator<<(std::ostream &out, const mnt4_G1 &g); + friend std::istream& operator>>(std::istream &in, mnt4_G1 &g); +}; + +template +mnt4_G1 operator*(const bigint &lhs, const mnt4_G1 &rhs) +{ + return scalar_mul(rhs, lhs); +} + +template& modulus_p> +mnt4_G1 operator*(const Fp_model &lhs, const mnt4_G1 &rhs) +{ + return scalar_mul(rhs, lhs.as_bigint()); +} + +std::ostream& operator<<(std::ostream& out, const std::vector &v); +std::istream& operator>>(std::istream& in, std::vector &v); + +template +void batch_to_special_all_non_zeros(std::vector &vec); +template<> +void batch_to_special_all_non_zeros(std::vector &vec); + +} // libsnark + +#endif // MNT4_G1_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_g2.cpp b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_g2.cpp new file mode 100644 index 0000000..d1da1fc --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_g2.cpp @@ -0,0 +1,496 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the MNT4 G2 group. + + See mnt4_g2.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/mnt/mnt4/mnt4_g2.hpp" + +namespace libsnark { + +#ifdef PROFILE_OP_COUNTS +long long mnt4_G2::add_cnt = 0; +long long mnt4_G2::dbl_cnt = 0; +#endif + +std::vector mnt4_G2::wnaf_window_table; +std::vector mnt4_G2::fixed_base_exp_window_table; +mnt4_Fq2 mnt4_G2::twist; +mnt4_Fq2 mnt4_G2::coeff_a; +mnt4_Fq2 mnt4_G2::coeff_b; +mnt4_G2 mnt4_G2::G2_zero; +mnt4_G2 mnt4_G2::G2_one; + +mnt4_Fq2 mnt4_G2::mul_by_a(const mnt4_Fq2 &elt) +{ + return mnt4_Fq2(mnt4_twist_mul_by_a_c0 * elt.c0, mnt4_twist_mul_by_a_c1 * elt.c1); +} + +mnt4_Fq2 mnt4_G2::mul_by_b(const mnt4_Fq2 &elt) +{ + return mnt4_Fq2(mnt4_twist_mul_by_b_c0 * elt.c1, mnt4_twist_mul_by_b_c1 * elt.c0); +} + +mnt4_G2::mnt4_G2() +{ + this->X_ = G2_zero.X_; + this->Y_ = G2_zero.Y_; + this->Z_ = G2_zero.Z_; +} + +void mnt4_G2::print() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + mnt4_G2 copy(*this); + copy.to_affine_coordinates(); + gmp_printf("(%Nd*z + %Nd , %Nd*z + %Nd)\n", + copy.X_.c1.as_bigint().data, mnt4_Fq::num_limbs, + copy.X_.c0.as_bigint().data, mnt4_Fq::num_limbs, + copy.Y_.c1.as_bigint().data, mnt4_Fq::num_limbs, + copy.Y_.c0.as_bigint().data, mnt4_Fq::num_limbs); + } +} + +void mnt4_G2::print_coordinates() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + gmp_printf("(%Nd*z + %Nd : %Nd*z + %Nd : %Nd*z + %Nd)\n", + this->X_.c1.as_bigint().data, mnt4_Fq::num_limbs, + this->X_.c0.as_bigint().data, mnt4_Fq::num_limbs, + this->Y_.c1.as_bigint().data, mnt4_Fq::num_limbs, + this->Y_.c0.as_bigint().data, mnt4_Fq::num_limbs, + this->Z_.c1.as_bigint().data, mnt4_Fq::num_limbs, + this->Z_.c0.as_bigint().data, mnt4_Fq::num_limbs); + } +} + +void mnt4_G2::to_affine_coordinates() +{ + if (this->is_zero()) + { + this->X_ = mnt4_Fq2::zero(); + this->Y_ = mnt4_Fq2::one(); + this->Z_ = mnt4_Fq2::zero(); + } + else + { + const mnt4_Fq2 Z_inv = Z_.inverse(); + X_ = X_ * Z_inv; + Y_ = Y_ * Z_inv; + Z_ = mnt4_Fq2::one(); + } +} + +void mnt4_G2::to_special() +{ + this->to_affine_coordinates(); +} + +bool mnt4_G2::is_special() const +{ + return (this->is_zero() || this->Z_ == mnt4_Fq2::one()); +} + +bool mnt4_G2::is_zero() const +{ + return (this->X_.is_zero() && this->Z_.is_zero()); +} + +bool mnt4_G2::operator==(const mnt4_G2 &other) const +{ + if (this->is_zero()) + { + return other.is_zero(); + } + + if (other.is_zero()) + { + return false; + } + + /* now neither is O */ + + // X1/Z1 = X2/Z2 <=> X1*Z2 = X2*Z1 + if ((this->X_ * other.Z_) != (other.X_ * this->Z_)) + { + return false; + } + + // Y1/Z1 = Y2/Z2 <=> Y1*Z2 = Y2*Z1 + if ((this->Y_ * other.Z_) != (other.Y_ * this->Z_)) + { + return false; + } + + return true; +} + +bool mnt4_G2::operator!=(const mnt4_G2& other) const +{ + return !(operator==(other)); +} + +mnt4_G2 mnt4_G2::operator+(const mnt4_G2 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case, and then all the rest + /* + The code below is equivalent to (but faster than) the snippet below: + + if (this->operator==(other)) + { + return this->dbl(); + } + else + { + return this->add(other); + } + */ + + const mnt4_Fq2 X1Z2 = (this->X_) * (other.Z_); // X1Z2 = X1*Z2 + const mnt4_Fq2 X2Z1 = (this->Z_) * (other.X_); // X2Z1 = X2*Z1 + + // (used both in add and double checks) + + const mnt4_Fq2 Y1Z2 = (this->Y_) * (other.Z_); // Y1Z2 = Y1*Z2 + const mnt4_Fq2 Y2Z1 = (this->Z_) * (other.Y_); // Y2Z1 = Y2*Z1 + + if (X1Z2 == X2Z1 && Y1Z2 == Y2Z1) + { + // perform dbl case + const mnt4_Fq2 XX = (this->X_).squared(); // XX = X1^2 + const mnt4_Fq2 ZZ = (this->Z_).squared(); // ZZ = Z1^2 + const mnt4_Fq2 w = mnt4_G2::mul_by_a(ZZ) + (XX + XX + XX); // w = a*ZZ + 3*XX + const mnt4_Fq2 Y1Z1 = (this->Y_) * (this->Z_); + const mnt4_Fq2 s = Y1Z1 + Y1Z1; // s = 2*Y1*Z1 + const mnt4_Fq2 ss = s.squared(); // ss = s^2 + const mnt4_Fq2 sss = s * ss; // sss = s*ss + const mnt4_Fq2 R = (this->Y_) * s; // R = Y1*s + const mnt4_Fq2 RR = R.squared(); // RR = R^2 + const mnt4_Fq2 B = ((this->X_)+R).squared()-XX-RR; // B = (X1+R)^2 - XX - RR + const mnt4_Fq2 h = w.squared() - (B+B); // h = w^2 - 2*B + const mnt4_Fq2 X3 = h * s; // X3 = h*s + const mnt4_Fq2 Y3 = w * (B-h)-(RR+RR); // Y3 = w*(B-h) - 2*RR + const mnt4_Fq2 Z3 = sss; // Z3 = sss + + return mnt4_G2(X3, Y3, Z3); + } + + // if we have arrived here we are in the add case + const mnt4_Fq2 Z1Z2 = (this->Z_) * (other.Z_); // Z1Z2 = Z1*Z2 + const mnt4_Fq2 u = Y2Z1 - Y1Z2; // u = Y2*Z1-Y1Z2 + const mnt4_Fq2 uu = u.squared(); // uu = u^2 + const mnt4_Fq2 v = X2Z1 - X1Z2; // v = X2*Z1-X1Z2 + const mnt4_Fq2 vv = v.squared(); // vv = v^2 + const mnt4_Fq2 vvv = v * vv; // vvv = v*vv + const mnt4_Fq2 R = vv * X1Z2; // R = vv*X1Z2 + const mnt4_Fq2 A = uu * Z1Z2 - (vvv + R + R); // A = uu*Z1Z2 - vvv - 2*R + const mnt4_Fq2 X3 = v * A; // X3 = v*A + const mnt4_Fq2 Y3 = u * (R-A) - vvv * Y1Z2; // Y3 = u*(R-A) - vvv*Y1Z2 + const mnt4_Fq2 Z3 = vvv * Z1Z2; // Z3 = vvv*Z1Z2 + + return mnt4_G2(X3, Y3, Z3); +} + +mnt4_G2 mnt4_G2::operator-() const +{ + return mnt4_G2(this->X_, -(this->Y_), this->Z_); +} + + +mnt4_G2 mnt4_G2::operator-(const mnt4_G2 &other) const +{ + return (*this) + (-other); +} + +mnt4_G2 mnt4_G2::add(const mnt4_G2 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return (*this); + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case + if (this->operator==(other)) + { + return this->dbl(); + } + +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#addition-add-1998-cmo-2 + + const mnt4_Fq2 Y1Z2 = (this->Y_) * (other.Z_); // Y1Z2 = Y1*Z2 + const mnt4_Fq2 X1Z2 = (this->X_) * (other.Z_); // X1Z2 = X1*Z2 + const mnt4_Fq2 Z1Z2 = (this->Z_) * (other.Z_); // Z1Z2 = Z1*Z2 + const mnt4_Fq2 u = (other.Y_) * (this->Z_) - Y1Z2; // u = Y2*Z1-Y1Z2 + const mnt4_Fq2 uu = u.squared(); // uu = u^2 + const mnt4_Fq2 v = (other.X_) * (this->Z_) - X1Z2; // v = X2*Z1-X1Z2 + const mnt4_Fq2 vv = v.squared(); // vv = v^2 + const mnt4_Fq2 vvv = v * vv; // vvv = v*vv + const mnt4_Fq2 R = vv * X1Z2; // R = vv*X1Z2 + const mnt4_Fq2 A = uu * Z1Z2 - (vvv + R + R); // A = uu*Z1Z2 - vvv - 2*R + const mnt4_Fq2 X3 = v * A; // X3 = v*A + const mnt4_Fq2 Y3 = u * (R-A) - vvv * Y1Z2; // Y3 = u*(R-A) - vvv*Y1Z2 + const mnt4_Fq2 Z3 = vvv * Z1Z2; // Z3 = vvv*Z1Z2 + + return mnt4_G2(X3, Y3, Z3); +} + +mnt4_G2 mnt4_G2::mixed_add(const mnt4_G2 &other) const +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#addition-add-1998-cmo-2 + //assert(other.Z == mnt4_Fq2::one()); + + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return (*this); + } + +#ifdef DEBUG + assert(other.is_special()); +#endif + + const mnt4_Fq2 &X1Z2 = (this->X_); // X1Z2 = X1*Z2 (but other is special and not zero) + const mnt4_Fq2 X2Z1 = (this->Z_) * (other.X_); // X2Z1 = X2*Z1 + + // (used both in add and double checks) + + const mnt4_Fq2 &Y1Z2 = (this->Y_); // Y1Z2 = Y1*Z2 (but other is special and not zero) + const mnt4_Fq2 Y2Z1 = (this->Z_) * (other.Y_); // Y2Z1 = Y2*Z1 + + if (X1Z2 == X2Z1 && Y1Z2 == Y2Z1) + { + return this->dbl(); + } + + const mnt4_Fq2 u = Y2Z1 - this->Y_; // u = Y2*Z1-Y1 + const mnt4_Fq2 uu = u.squared(); // uu = u2 + const mnt4_Fq2 v = X2Z1 - this->X_; // v = X2*Z1-X1 + const mnt4_Fq2 vv = v.squared(); // vv = v2 + const mnt4_Fq2 vvv = v*vv; // vvv = v*vv + const mnt4_Fq2 R = vv * this->X_; // R = vv*X1 + const mnt4_Fq2 A = uu * this->Z_ - vvv - R - R; // A = uu*Z1-vvv-2*R + const mnt4_Fq2 X3 = v * A; // X3 = v*A + const mnt4_Fq2 Y3 = u*(R-A) - vvv * this->Y_; // Y3 = u*(R-A)-vvv*Y1 + const mnt4_Fq2 Z3 = vvv * this->Z_; // Z3 = vvv*Z1 + + return mnt4_G2(X3, Y3, Z3); +} + +mnt4_G2 mnt4_G2::dbl() const +{ +#ifdef PROFILE_OP_COUNTS + this->dbl_cnt++; +#endif + if (this->is_zero()) + { + return (*this); + } + else + { + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#doubling-dbl-2007-bl + + const mnt4_Fq2 XX = (this->X_).squared(); // XX = X1^2 + const mnt4_Fq2 ZZ = (this->Z_).squared(); // ZZ = Z1^2 + const mnt4_Fq2 w = mnt4_G2::mul_by_a(ZZ) + (XX + XX + XX); // w = a*ZZ + 3*XX + const mnt4_Fq2 Y1Z1 = (this->Y_) * (this->Z_); + const mnt4_Fq2 s = Y1Z1 + Y1Z1; // s = 2*Y1*Z1 + const mnt4_Fq2 ss = s.squared(); // ss = s^2 + const mnt4_Fq2 sss = s * ss; // sss = s*ss + const mnt4_Fq2 R = (this->Y_) * s; // R = Y1*s + const mnt4_Fq2 RR = R.squared(); // RR = R^2 + const mnt4_Fq2 B = ((this->X_)+R).squared()-XX-RR; // B = (X1+R)^2 - XX - RR + const mnt4_Fq2 h = w.squared() - (B+B); // h = w^2-2*B + const mnt4_Fq2 X3 = h * s; // X3 = h*s + const mnt4_Fq2 Y3 = w * (B-h)-(RR+RR); // Y3 = w*(B-h) - 2*RR + const mnt4_Fq2 Z3 = sss; // Z3 = sss + + return mnt4_G2(X3, Y3, Z3); + } +} + +mnt4_G2 mnt4_G2::mul_by_q() const +{ + return mnt4_G2(mnt4_twist_mul_by_q_X * (this->X_).Frobenius_map(1), + mnt4_twist_mul_by_q_Y * (this->Y_).Frobenius_map(1), + (this->Z_).Frobenius_map(1)); +} + +bool mnt4_G2::is_well_formed() const +{ + if (this->is_zero()) + { + return true; + } + else + { + /* + y^2 = x^3 + ax + b + + We are using projective, so equation we need to check is actually + + (y/z)^2 = (x/z)^3 + a (x/z) + b + z y^2 = x^3 + a z^2 x + b z^3 + + z (y^2 - b z^2) = x ( x^2 + a z^2) + */ + const mnt4_Fq2 X2 = this->X_.squared(); + const mnt4_Fq2 Y2 = this->Y_.squared(); + const mnt4_Fq2 Z2 = this->Z_.squared(); + const mnt4_Fq2 aZ2 = mnt4_twist_coeff_a * Z2; + + return (this->Z_ * (Y2 - mnt4_twist_coeff_b * Z2) == this->X_ * (X2 + aZ2)); + } +} + +mnt4_G2 mnt4_G2::zero() +{ + return G2_zero; +} + +mnt4_G2 mnt4_G2::one() +{ + return G2_one; +} + +mnt4_G2 mnt4_G2::random_element() +{ + return (mnt4_Fr::random_element().as_bigint()) * G2_one; +} + +std::ostream& operator<<(std::ostream &out, const mnt4_G2 &g) +{ + mnt4_G2 copy(g); + copy.to_affine_coordinates(); + + out << (copy.is_zero() ? 1 : 0) << OUTPUT_SEPARATOR; +#ifdef NO_PT_COMPRESSION + out << copy.X_ << OUTPUT_SEPARATOR << copy.Y_; +#else + /* storing LSB of Y */ + out << copy.X_ << OUTPUT_SEPARATOR << (copy.Y_.c0.as_bigint().data[0] & 1); +#endif + + return out; +} + +std::istream& operator>>(std::istream &in, mnt4_G2 &g) +{ + char is_zero; + mnt4_Fq2 tX, tY; + +#ifdef NO_PT_COMPRESSION + in >> is_zero >> tX >> tY; + is_zero -= '0'; +#else + in.read((char*)&is_zero, 1); // this reads is_zero; + is_zero -= '0'; + consume_OUTPUT_SEPARATOR(in); + + unsigned char Y_lsb; + in >> tX; + consume_OUTPUT_SEPARATOR(in); + in.read((char*)&Y_lsb, 1); + Y_lsb -= '0'; + + // y = +/- sqrt(x^3 + a*x + b) + if (!is_zero) + { + mnt4_Fq2 tX2 = tX.squared(); + mnt4_Fq2 tY2 = (tX2 + mnt4_twist_coeff_a ) * tX + mnt4_twist_coeff_b; + tY = tY2.sqrt(); + + if ((tY.c0.as_bigint().data[0] & 1) != Y_lsb) + { + tY = -tY; + } + } +#endif + // using projective coordinates + if (!is_zero) + { + g.X_ = tX; + g.Y_ = tY; + g.Z_ = mnt4_Fq2::one(); + } + else + { + g = mnt4_G2::zero(); + } + + return in; +} + +template<> +void batch_to_special_all_non_zeros(std::vector &vec) +{ + std::vector Z_vec; + Z_vec.reserve(vec.size()); + + for (auto &el: vec) + { + Z_vec.emplace_back(el.Z()); + } + batch_invert(Z_vec); + + const mnt4_Fq2 one = mnt4_Fq2::one(); + + for (size_t i = 0; i < vec.size(); ++i) + { + vec[i] = mnt4_G2(vec[i].X() * Z_vec[i], vec[i].Y() * Z_vec[i], one); + } +} + +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_g2.d b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_g2.d new file mode 100644 index 0000000..46cf0ad --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_g2.d @@ -0,0 +1,17 @@ +src/algebra/curves/mnt/mnt4/mnt4_g2.o: \ + src/algebra/curves/mnt/mnt4/mnt4_g2.cpp \ + src/algebra/curves/mnt/mnt4/mnt4_g2.hpp \ + src/algebra/curves/curve_utils.hpp src/algebra/fields/bigint.hpp \ + src/common/serialization.hpp src/common/serialization.tcc \ + src/common/utils.hpp src/common/utils.tcc src/algebra/fields/bigint.tcc \ + src/algebra/curves/curve_utils.tcc \ + src/algebra/curves/mnt/mnt4/mnt4_init.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/mnt/mnt46_common.hpp src/algebra/fields/fp.hpp \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc src/algebra/fields/fp2.hpp \ + src/algebra/fields/fp2.tcc src/algebra/fields/fp4.hpp \ + src/algebra/fields/fp4.tcc src/algebra/scalar_multiplication/wnaf.hpp \ + src/algebra/scalar_multiplication/wnaf.tcc diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_g2.hpp b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_g2.hpp new file mode 100644 index 0000000..47fccca --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_g2.hpp @@ -0,0 +1,111 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the MNT4 G2 group. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT4_G2_HPP_ +#define MNT4_G2_HPP_ + +#include + +#include "algebra/curves/curve_utils.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_init.hpp" + +namespace libsnark { + +class mnt4_G2; +std::ostream& operator<<(std::ostream &, const mnt4_G2&); +std::istream& operator>>(std::istream &, mnt4_G2&); + +class mnt4_G2 { +private: + mnt4_Fq2 X_, Y_, Z_; +public: +#ifdef PROFILE_OP_COUNTS + static long long add_cnt; + static long long dbl_cnt; +#endif + static std::vector wnaf_window_table; + static std::vector fixed_base_exp_window_table; + static mnt4_G2 G2_zero; + static mnt4_G2 G2_one; + static mnt4_Fq2 twist; + static mnt4_Fq2 coeff_a; + static mnt4_Fq2 coeff_b; + + typedef mnt4_Fq base_field; + typedef mnt4_Fq2 twist_field; + typedef mnt4_Fr scalar_field; + + // using projective coordinates + mnt4_G2(); + mnt4_G2(const mnt4_Fq2& X, const mnt4_Fq2& Y, const mnt4_Fq2& Z) : X_(X), Y_(Y), Z_(Z) {}; + + mnt4_Fq2 X() const { return X_; } + mnt4_Fq2 Y() const { return Y_; } + mnt4_Fq2 Z() const { return Z_; } + + static mnt4_Fq2 mul_by_a(const mnt4_Fq2 &elt); + static mnt4_Fq2 mul_by_b(const mnt4_Fq2 &elt); + + void print() const; + void print_coordinates() const; + + void to_affine_coordinates(); + void to_special(); + bool is_special() const; + + bool is_zero() const; + + bool operator==(const mnt4_G2 &other) const; + bool operator!=(const mnt4_G2 &other) const; + + mnt4_G2 operator+(const mnt4_G2 &other) const; + mnt4_G2 operator-() const; + mnt4_G2 operator-(const mnt4_G2 &other) const; + + mnt4_G2 add(const mnt4_G2 &other) const; + mnt4_G2 mixed_add(const mnt4_G2 &other) const; + mnt4_G2 dbl() const; + mnt4_G2 mul_by_q() const; + + bool is_well_formed() const; + + static mnt4_G2 zero(); + static mnt4_G2 one(); + static mnt4_G2 random_element(); + + static size_t size_in_bits() { return mnt4_Fq2::size_in_bits() + 1; } + static bigint base_field_char() { return mnt4_Fq::field_char(); } + static bigint order() { return mnt4_Fr::field_char(); } + + friend std::ostream& operator<<(std::ostream &out, const mnt4_G2 &g); + friend std::istream& operator>>(std::istream &in, mnt4_G2 &g); +}; + +template +mnt4_G2 operator*(const bigint &lhs, const mnt4_G2 &rhs) +{ + return scalar_mul(rhs, lhs); +} + +template& modulus_p> +mnt4_G2 operator*(const Fp_model &lhs, const mnt4_G2 &rhs) +{ + return scalar_mul(rhs, lhs.as_bigint()); +} + +template +void batch_to_special_all_non_zeros(std::vector &vec); +template<> +void batch_to_special_all_non_zeros(std::vector &vec); + +} // libsnark + +#endif // MNT4_G2_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_init.cpp b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_init.cpp new file mode 100644 index 0000000..4d480ed --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_init.cpp @@ -0,0 +1,265 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for initializing MNT4. + + See mnt4_init.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/mnt/mnt4/mnt4_init.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_g1.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_g2.hpp" + +namespace libsnark { + +// bigint mnt4_modulus_r = mnt46_modulus_A; +// bigint mnt4_modulus_q = mnt46_modulus_B; + +mnt4_Fq2 mnt4_twist; +mnt4_Fq2 mnt4_twist_coeff_a; +mnt4_Fq2 mnt4_twist_coeff_b; +mnt4_Fq mnt4_twist_mul_by_a_c0; +mnt4_Fq mnt4_twist_mul_by_a_c1; +mnt4_Fq mnt4_twist_mul_by_b_c0; +mnt4_Fq mnt4_twist_mul_by_b_c1; +mnt4_Fq mnt4_twist_mul_by_q_X; +mnt4_Fq mnt4_twist_mul_by_q_Y; + +bigint mnt4_ate_loop_count; +bool mnt4_ate_is_loop_count_neg; +bigint<4*mnt4_q_limbs> mnt4_final_exponent; +bigint mnt4_final_exponent_last_chunk_abs_of_w0; +bool mnt4_final_exponent_last_chunk_is_w0_neg; +bigint mnt4_final_exponent_last_chunk_w1; + +void init_mnt4_params() +{ + typedef bigint bigint_r; + typedef bigint bigint_q; + + assert(sizeof(mp_limb_t) == 8 || sizeof(mp_limb_t) == 4); // Montgomery assumes this + + /* parameters for scalar field Fr */ + mnt4_modulus_r = bigint_r("475922286169261325753349249653048451545124878552823515553267735739164647307408490559963137"); + assert(mnt4_Fr::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + mnt4_Fr::Rsquared = bigint_r("163983144722506446826715124368972380525894397127205577781234305496325861831001705438796139"); + mnt4_Fr::Rcubed = bigint_r("207236281459091063710247635236340312578688659363066707916716212805695955118593239854980171"); + mnt4_Fr::inv = 0xbb4334a3ffffffff; + } + if (sizeof(mp_limb_t) == 4) + { + mnt4_Fr::Rsquared = bigint_r("163983144722506446826715124368972380525894397127205577781234305496325861831001705438796139"); + mnt4_Fr::Rcubed = bigint_r("207236281459091063710247635236340312578688659363066707916716212805695955118593239854980171"); + mnt4_Fr::inv = 0xffffffff; + } + mnt4_Fr::num_bits = 298; + mnt4_Fr::euler = bigint_r("237961143084630662876674624826524225772562439276411757776633867869582323653704245279981568"); + mnt4_Fr::s = 34; + mnt4_Fr::t = bigint_r("27702323054502562488973446286577291993024111641153199339359284829066871159442729"); + mnt4_Fr::t_minus_1_over_2 = bigint_r("13851161527251281244486723143288645996512055820576599669679642414533435579721364"); + mnt4_Fr::multiplicative_generator = mnt4_Fr("10"); + mnt4_Fr::root_of_unity = mnt4_Fr("120638817826913173458768829485690099845377008030891618010109772937363554409782252579816313"); + mnt4_Fr::nqr = mnt4_Fr("5"); + mnt4_Fr::nqr_to_t = mnt4_Fr("406220604243090401056429458730298145937262552508985450684842547562990900634752279902740880"); + + /* parameters for base field Fq */ + mnt4_modulus_q = bigint_q("475922286169261325753349249653048451545124879242694725395555128576210262817955800483758081"); + assert(mnt4_Fq::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + mnt4_Fq::Rsquared = bigint_q("273000478523237720910981655601160860640083126627235719712980612296263966512828033847775776"); + mnt4_Fq::Rcubed = bigint_q("427298980065529822574935274648041073124704261331681436071990730954930769758106792920349077"); + mnt4_Fq::inv = 0xb071a1b67165ffff; + } + if (sizeof(mp_limb_t) == 4) + { + mnt4_Fq::Rsquared = bigint_q("273000478523237720910981655601160860640083126627235719712980612296263966512828033847775776"); + mnt4_Fq::Rcubed = bigint_q("427298980065529822574935274648041073124704261331681436071990730954930769758106792920349077"); + mnt4_Fq::inv = 0x7165ffff; + } + mnt4_Fq::num_bits = 298; + mnt4_Fq::euler = bigint_q("237961143084630662876674624826524225772562439621347362697777564288105131408977900241879040"); + mnt4_Fq::s = 17; + mnt4_Fq::t = bigint_q("3630998887399759870554727551674258816109656366292531779446068791017229177993437198515"); + mnt4_Fq::t_minus_1_over_2 = bigint_q("1815499443699879935277363775837129408054828183146265889723034395508614588996718599257"); + mnt4_Fq::multiplicative_generator = mnt4_Fq("17"); + mnt4_Fq::root_of_unity = mnt4_Fq("264706250571800080758069302369654305530125675521263976034054878017580902343339784464690243"); + mnt4_Fq::nqr = mnt4_Fq("17"); + mnt4_Fq::nqr_to_t = mnt4_Fq("264706250571800080758069302369654305530125675521263976034054878017580902343339784464690243"); + + /* parameters for twist field Fq2 */ + mnt4_Fq2::euler = bigint<2*mnt4_q_limbs>("113251011236288135098249345249154230895914381858788918106847214243419142422924133497460817468249854833067260038985710370091920860837014281886963086681184370139950267830740466401280"); + mnt4_Fq2::s = 18; + mnt4_Fq2::t = bigint<2*mnt4_q_limbs>("864036645784668999467844736092790457885088972921668381552484239528039111503022258739172496553419912972009735404859240494475714575477709059806542104196047745818712370534824115"); + mnt4_Fq2::t_minus_1_over_2 = bigint<2*mnt4_q_limbs>("432018322892334499733922368046395228942544486460834190776242119764019555751511129369586248276709956486004867702429620247237857287738854529903271052098023872909356185267412057"); + mnt4_Fq2::non_residue = mnt4_Fq("17"); + mnt4_Fq2::nqr = mnt4_Fq2(mnt4_Fq("8"),mnt4_Fq("1")); + mnt4_Fq2::nqr_to_t = mnt4_Fq2(mnt4_Fq("0"),mnt4_Fq("29402818985595053196743631544512156561638230562612542604956687802791427330205135130967658")); + mnt4_Fq2::Frobenius_coeffs_c1[0] = mnt4_Fq("1"); + mnt4_Fq2::Frobenius_coeffs_c1[1] = mnt4_Fq("475922286169261325753349249653048451545124879242694725395555128576210262817955800483758080"); + + /* parameters for Fq4 */ + mnt4_Fq4::non_residue = mnt4_Fq("17"); + mnt4_Fq4::Frobenius_coeffs_c1[0] = mnt4_Fq("1"); + mnt4_Fq4::Frobenius_coeffs_c1[1] = mnt4_Fq("7684163245453501615621351552473337069301082060976805004625011694147890954040864167002308"); + mnt4_Fq4::Frobenius_coeffs_c1[2] = mnt4_Fq("475922286169261325753349249653048451545124879242694725395555128576210262817955800483758080"); + mnt4_Fq4::Frobenius_coeffs_c1[3] = mnt4_Fq("468238122923807824137727898100575114475823797181717920390930116882062371863914936316755773"); + + /* choice of short Weierstrass curve and its twist */ + mnt4_G1::coeff_a = mnt4_Fq("2"); + mnt4_G1::coeff_b = mnt4_Fq("423894536526684178289416011533888240029318103673896002803341544124054745019340795360841685"); + mnt4_twist = mnt4_Fq2(mnt4_Fq::zero(), mnt4_Fq::one()); + mnt4_twist_coeff_a = mnt4_Fq2(mnt4_G1::coeff_a * mnt4_Fq2::non_residue, mnt4_Fq::zero()); + mnt4_twist_coeff_b = mnt4_Fq2(mnt4_Fq::zero(), mnt4_G1::coeff_b * mnt4_Fq2::non_residue); + mnt4_G2::twist = mnt4_twist; + mnt4_G2::coeff_a = mnt4_twist_coeff_a; + mnt4_G2::coeff_b = mnt4_twist_coeff_b; + mnt4_twist_mul_by_a_c0 = mnt4_G1::coeff_a * mnt4_Fq2::non_residue; + mnt4_twist_mul_by_a_c1 = mnt4_G1::coeff_a * mnt4_Fq2::non_residue; + mnt4_twist_mul_by_b_c0 = mnt4_G1::coeff_b * mnt4_Fq2::non_residue.squared(); + mnt4_twist_mul_by_b_c1 = mnt4_G1::coeff_b * mnt4_Fq2::non_residue; + mnt4_twist_mul_by_q_X = mnt4_Fq("475922286169261325753349249653048451545124879242694725395555128576210262817955800483758080"); + mnt4_twist_mul_by_q_Y = mnt4_Fq("7684163245453501615621351552473337069301082060976805004625011694147890954040864167002308"); + + /* choice of group G1 */ + mnt4_G1::G1_zero = mnt4_G1(mnt4_Fq::zero(), + mnt4_Fq::one(), + mnt4_Fq::zero()); + + + mnt4_G1::G1_one = mnt4_G1(mnt4_Fq("60760244141852568949126569781626075788424196370144486719385562369396875346601926534016838"), + mnt4_Fq("363732850702582978263902770815145784459747722357071843971107674179038674942891694705904306"), + mnt4_Fq::one()); + + mnt4_G1::wnaf_window_table.resize(0); + mnt4_G1::wnaf_window_table.push_back(11); + mnt4_G1::wnaf_window_table.push_back(24); + mnt4_G1::wnaf_window_table.push_back(60); + mnt4_G1::wnaf_window_table.push_back(127); + + mnt4_G1::fixed_base_exp_window_table.resize(0); + // window 1 is unbeaten in [-inf, 5.09] + mnt4_G1::fixed_base_exp_window_table.push_back(1); + // window 2 is unbeaten in [5.09, 9.64] + mnt4_G1::fixed_base_exp_window_table.push_back(5); + // window 3 is unbeaten in [9.64, 24.79] + mnt4_G1::fixed_base_exp_window_table.push_back(10); + // window 4 is unbeaten in [24.79, 60.29] + mnt4_G1::fixed_base_exp_window_table.push_back(25); + // window 5 is unbeaten in [60.29, 144.37] + mnt4_G1::fixed_base_exp_window_table.push_back(60); + // window 6 is unbeaten in [144.37, 344.90] + mnt4_G1::fixed_base_exp_window_table.push_back(144); + // window 7 is unbeaten in [344.90, 855.00] + mnt4_G1::fixed_base_exp_window_table.push_back(345); + // window 8 is unbeaten in [855.00, 1804.62] + mnt4_G1::fixed_base_exp_window_table.push_back(855); + // window 9 is unbeaten in [1804.62, 3912.30] + mnt4_G1::fixed_base_exp_window_table.push_back(1805); + // window 10 is unbeaten in [3912.30, 11264.50] + mnt4_G1::fixed_base_exp_window_table.push_back(3912); + // window 11 is unbeaten in [11264.50, 27897.51] + mnt4_G1::fixed_base_exp_window_table.push_back(11265); + // window 12 is unbeaten in [27897.51, 57596.79] + mnt4_G1::fixed_base_exp_window_table.push_back(27898); + // window 13 is unbeaten in [57596.79, 145298.71] + mnt4_G1::fixed_base_exp_window_table.push_back(57597); + // window 14 is unbeaten in [145298.71, 157204.59] + mnt4_G1::fixed_base_exp_window_table.push_back(145299); + // window 15 is unbeaten in [157204.59, 601600.62] + mnt4_G1::fixed_base_exp_window_table.push_back(157205); + // window 16 is unbeaten in [601600.62, 1107377.25] + mnt4_G1::fixed_base_exp_window_table.push_back(601601); + // window 17 is unbeaten in [1107377.25, 1789646.95] + mnt4_G1::fixed_base_exp_window_table.push_back(1107377); + // window 18 is unbeaten in [1789646.95, 4392626.92] + mnt4_G1::fixed_base_exp_window_table.push_back(1789647); + // window 19 is unbeaten in [4392626.92, 8221210.60] + mnt4_G1::fixed_base_exp_window_table.push_back(4392627); + // window 20 is unbeaten in [8221210.60, 42363731.19] + mnt4_G1::fixed_base_exp_window_table.push_back(8221211); + // window 21 is never the best + mnt4_G1::fixed_base_exp_window_table.push_back(0); + // window 22 is unbeaten in [42363731.19, inf] + mnt4_G1::fixed_base_exp_window_table.push_back(42363731); + + /* choice of group G2 */ + mnt4_G2::G2_zero = mnt4_G2(mnt4_Fq2::zero(), + mnt4_Fq2::one(), + mnt4_Fq2::zero()); + + mnt4_G2::G2_one = mnt4_G2(mnt4_Fq2(mnt4_Fq("438374926219350099854919100077809681842783509163790991847867546339851681564223481322252708"), + mnt4_Fq("37620953615500480110935514360923278605464476459712393277679280819942849043649216370485641")), + mnt4_Fq2(mnt4_Fq("37437409008528968268352521034936931842973546441370663118543015118291998305624025037512482"), + mnt4_Fq("424621479598893882672393190337420680597584695892317197646113820787463109735345923009077489")), + mnt4_Fq2::one()); + + mnt4_G2::wnaf_window_table.resize(0); + mnt4_G2::wnaf_window_table.push_back(5); + mnt4_G2::wnaf_window_table.push_back(15); + mnt4_G2::wnaf_window_table.push_back(39); + mnt4_G2::wnaf_window_table.push_back(109); + + mnt4_G2::fixed_base_exp_window_table.resize(0); + // window 1 is unbeaten in [-inf, 4.17] + mnt4_G2::fixed_base_exp_window_table.push_back(1); + // window 2 is unbeaten in [4.17, 10.12] + mnt4_G2::fixed_base_exp_window_table.push_back(4); + // window 3 is unbeaten in [10.12, 24.65] + mnt4_G2::fixed_base_exp_window_table.push_back(10); + // window 4 is unbeaten in [24.65, 60.03] + mnt4_G2::fixed_base_exp_window_table.push_back(25); + // window 5 is unbeaten in [60.03, 143.16] + mnt4_G2::fixed_base_exp_window_table.push_back(60); + // window 6 is unbeaten in [143.16, 344.73] + mnt4_G2::fixed_base_exp_window_table.push_back(143); + // window 7 is unbeaten in [344.73, 821.24] + mnt4_G2::fixed_base_exp_window_table.push_back(345); + // window 8 is unbeaten in [821.24, 1793.92] + mnt4_G2::fixed_base_exp_window_table.push_back(821); + // window 9 is unbeaten in [1793.92, 3919.59] + mnt4_G2::fixed_base_exp_window_table.push_back(1794); + // window 10 is unbeaten in [3919.59, 11301.46] + mnt4_G2::fixed_base_exp_window_table.push_back(3920); + // window 11 is unbeaten in [11301.46, 18960.09] + mnt4_G2::fixed_base_exp_window_table.push_back(11301); + // window 12 is unbeaten in [18960.09, 44198.62] + mnt4_G2::fixed_base_exp_window_table.push_back(18960); + // window 13 is unbeaten in [44198.62, 150799.57] + mnt4_G2::fixed_base_exp_window_table.push_back(44199); + // window 14 is never the best + mnt4_G2::fixed_base_exp_window_table.push_back(0); + // window 15 is unbeaten in [150799.57, 548694.81] + mnt4_G2::fixed_base_exp_window_table.push_back(150800); + // window 16 is unbeaten in [548694.81, 1051769.08] + mnt4_G2::fixed_base_exp_window_table.push_back(548695); + // window 17 is unbeaten in [1051769.08, 2023925.59] + mnt4_G2::fixed_base_exp_window_table.push_back(1051769); + // window 18 is unbeaten in [2023925.59, 3787108.68] + mnt4_G2::fixed_base_exp_window_table.push_back(2023926); + // window 19 is unbeaten in [3787108.68, 7107480.30] + mnt4_G2::fixed_base_exp_window_table.push_back(3787109); + // window 20 is unbeaten in [7107480.30, 38760027.14] + mnt4_G2::fixed_base_exp_window_table.push_back(7107480); + // window 21 is never the best + mnt4_G2::fixed_base_exp_window_table.push_back(0); + // window 22 is unbeaten in [38760027.14, inf] + mnt4_G2::fixed_base_exp_window_table.push_back(38760027); + + /* pairing parameters */ + mnt4_ate_loop_count = bigint_q("689871209842287392837045615510547309923794944"); + mnt4_ate_is_loop_count_neg = false; + mnt4_final_exponent = bigint<4*mnt4_q_limbs>("107797360357109903430794490309592072278927783803031854357910908121903439838772861497177116410825586743089760869945394610511917274977971559062689561855016270594656570874331111995170645233717143416875749097203441437192367065467706065411650403684877366879441766585988546560"); + mnt4_final_exponent_last_chunk_abs_of_w0 = bigint_q("689871209842287392837045615510547309923794945"); + mnt4_final_exponent_last_chunk_is_w0_neg = false; + mnt4_final_exponent_last_chunk_w1 = bigint_q("1"); +} + +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_init.d b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_init.d new file mode 100644 index 0000000..a266f2b --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_init.d @@ -0,0 +1,17 @@ +src/algebra/curves/mnt/mnt4/mnt4_init.o: \ + src/algebra/curves/mnt/mnt4/mnt4_init.cpp \ + src/algebra/curves/mnt/mnt4/mnt4_init.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/mnt/mnt46_common.hpp src/algebra/fields/bigint.hpp \ + src/common/serialization.hpp src/common/serialization.tcc \ + src/common/utils.hpp src/common/utils.tcc src/algebra/fields/bigint.tcc \ + src/algebra/fields/fp.hpp src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc src/algebra/fields/fp2.hpp \ + src/algebra/fields/fp2.tcc src/algebra/fields/fp4.hpp \ + src/algebra/fields/fp4.tcc src/algebra/scalar_multiplication/wnaf.hpp \ + src/algebra/scalar_multiplication/wnaf.tcc \ + src/algebra/curves/mnt/mnt4/mnt4_g1.hpp \ + src/algebra/curves/curve_utils.hpp src/algebra/curves/curve_utils.tcc \ + src/algebra/curves/mnt/mnt4/mnt4_g2.hpp diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_init.hpp b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_init.hpp new file mode 100644 index 0000000..79f449a --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_init.hpp @@ -0,0 +1,67 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for initializing MNT4. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT4_INIT_HPP_ +#define MNT4_INIT_HPP_ + +#include "algebra/curves/public_params.hpp" +#include "algebra/curves/mnt/mnt46_common.hpp" +#include "algebra/fields/fp.hpp" +#include "algebra/fields/fp2.hpp" +#include "algebra/fields/fp4.hpp" + +namespace libsnark { + +#define mnt4_modulus_r mnt46_modulus_A +#define mnt4_modulus_q mnt46_modulus_B + +const mp_size_t mnt4_r_bitcount = mnt46_A_bitcount; +const mp_size_t mnt4_q_bitcount = mnt46_B_bitcount; + +const mp_size_t mnt4_r_limbs = mnt46_A_limbs; +const mp_size_t mnt4_q_limbs = mnt46_B_limbs; + +extern bigint mnt4_modulus_r; +extern bigint mnt4_modulus_q; + +typedef Fp_model mnt4_Fr; +typedef Fp_model mnt4_Fq; +typedef Fp2_model mnt4_Fq2; +typedef Fp4_model mnt4_Fq4; +typedef mnt4_Fq4 mnt4_GT; + +// parameters for twisted short Weierstrass curve E'/Fq2 : y^2 = x^3 + (a * twist^2) * x + (b * twist^3) +extern mnt4_Fq2 mnt4_twist; +extern mnt4_Fq2 mnt4_twist_coeff_a; +extern mnt4_Fq2 mnt4_twist_coeff_b; +extern mnt4_Fq mnt4_twist_mul_by_a_c0; +extern mnt4_Fq mnt4_twist_mul_by_a_c1; +extern mnt4_Fq mnt4_twist_mul_by_b_c0; +extern mnt4_Fq mnt4_twist_mul_by_b_c1; +extern mnt4_Fq mnt4_twist_mul_by_q_X; +extern mnt4_Fq mnt4_twist_mul_by_q_Y; + +// parameters for pairing +extern bigint mnt4_ate_loop_count; +extern bool mnt4_ate_is_loop_count_neg; +extern bigint<4*mnt4_q_limbs> mnt4_final_exponent; +extern bigint mnt4_final_exponent_last_chunk_abs_of_w0; +extern bool mnt4_final_exponent_last_chunk_is_w0_neg; +extern bigint mnt4_final_exponent_last_chunk_w1; + +void init_mnt4_params(); + +class mnt4_G1; +class mnt4_G2; + +} // libsnark + +#endif // MNT4_INIT_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_pairing.cpp b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_pairing.cpp new file mode 100644 index 0000000..6334283 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_pairing.cpp @@ -0,0 +1,742 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for pairing operations on MNT4. + + See mnt4_pairing.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include + +#include "algebra/curves/mnt/mnt4/mnt4_pairing.hpp" + +#include "algebra/curves/mnt/mnt4/mnt4_init.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_g1.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_g2.hpp" +#include "algebra/scalar_multiplication/wnaf.hpp" +#include "common/profiling.hpp" + +namespace libsnark { + +bool mnt4_ate_G1_precomp::operator==(const mnt4_ate_G1_precomp &other) const +{ + return (this->PX == other.PX && + this->PY == other.PY && + this->PX_twist == other.PX_twist && + this->PY_twist == other.PY_twist); +} + +std::ostream& operator<<(std::ostream &out, const mnt4_ate_G1_precomp &prec_P) +{ + out << prec_P.PX << OUTPUT_SEPARATOR << prec_P.PY << OUTPUT_SEPARATOR << prec_P.PX_twist << OUTPUT_SEPARATOR << prec_P.PY_twist; + + return out; +} + +std::istream& operator>>(std::istream &in, mnt4_ate_G1_precomp &prec_P) +{ + in >> prec_P.PX; + consume_OUTPUT_SEPARATOR(in); + in >> prec_P.PY; + consume_OUTPUT_SEPARATOR(in); + in >> prec_P.PX_twist; + consume_OUTPUT_SEPARATOR(in); + in >> prec_P.PY_twist; + + return in; +} + +bool mnt4_ate_dbl_coeffs::operator==(const mnt4_ate_dbl_coeffs &other) const +{ + return (this->c_H == other.c_H && + this->c_4C == other.c_4C && + this->c_J == other.c_J && + this->c_L == other.c_L); +} + +std::ostream& operator<<(std::ostream &out, const mnt4_ate_dbl_coeffs &dc) +{ + out << dc.c_H << OUTPUT_SEPARATOR << dc.c_4C << OUTPUT_SEPARATOR << dc.c_J << OUTPUT_SEPARATOR << dc.c_L; + return out; +} + +std::istream& operator>>(std::istream &in, mnt4_ate_dbl_coeffs &dc) +{ + in >> dc.c_H; + consume_OUTPUT_SEPARATOR(in); + in >> dc.c_4C; + consume_OUTPUT_SEPARATOR(in); + in >> dc.c_J; + consume_OUTPUT_SEPARATOR(in); + in >> dc.c_L; + + return in; +} + +bool mnt4_ate_add_coeffs::operator==(const mnt4_ate_add_coeffs &other) const +{ + return (this->c_L1 == other.c_L1 && + this->c_RZ == other.c_RZ); +} + +std::ostream& operator<<(std::ostream &out, const mnt4_ate_add_coeffs &ac) +{ + out << ac.c_L1 << OUTPUT_SEPARATOR << ac.c_RZ; + return out; +} + +std::istream& operator>>(std::istream &in, mnt4_ate_add_coeffs &ac) +{ + in >> ac.c_L1; + consume_OUTPUT_SEPARATOR(in); + in >> ac.c_RZ; + return in; +} + +bool mnt4_ate_G2_precomp::operator==(const mnt4_ate_G2_precomp &other) const +{ + return (this->QX == other.QX && + this->QY == other.QY && + this->QY2 == other.QY2 && + this->QX_over_twist == other.QX_over_twist && + this->QY_over_twist == other.QY_over_twist && + this->dbl_coeffs == other.dbl_coeffs && + this->add_coeffs == other.add_coeffs); +} + +std::ostream& operator<<(std::ostream& out, const mnt4_ate_G2_precomp &prec_Q) +{ + out << prec_Q.QX << OUTPUT_SEPARATOR + << prec_Q.QY << OUTPUT_SEPARATOR + << prec_Q.QY2 << OUTPUT_SEPARATOR + << prec_Q.QX_over_twist << OUTPUT_SEPARATOR + << prec_Q.QY_over_twist << "\n"; + out << prec_Q.dbl_coeffs.size() << "\n"; + for (const mnt4_ate_dbl_coeffs &dc : prec_Q.dbl_coeffs) + { + out << dc << OUTPUT_NEWLINE; + } + out << prec_Q.add_coeffs.size() << "\n"; + for (const mnt4_ate_add_coeffs &ac : prec_Q.add_coeffs) + { + out << ac << OUTPUT_NEWLINE; + } + + return out; +} + +std::istream& operator>>(std::istream& in, mnt4_ate_G2_precomp &prec_Q) +{ + in >> prec_Q.QX; + consume_OUTPUT_SEPARATOR(in); + in >> prec_Q.QY; + consume_OUTPUT_SEPARATOR(in); + in >> prec_Q.QY2; + consume_OUTPUT_SEPARATOR(in); + in >> prec_Q.QX_over_twist; + consume_OUTPUT_SEPARATOR(in); + in >> prec_Q.QY_over_twist; + consume_newline(in); + + prec_Q.dbl_coeffs.clear(); + size_t dbl_s; + in >> dbl_s; + consume_newline(in); + + prec_Q.dbl_coeffs.reserve(dbl_s); + + for (size_t i = 0; i < dbl_s; ++i) + { + mnt4_ate_dbl_coeffs dc; + in >> dc; + consume_OUTPUT_NEWLINE(in); + prec_Q.dbl_coeffs.emplace_back(dc); + } + + prec_Q.add_coeffs.clear(); + size_t add_s; + in >> add_s; + consume_newline(in); + + prec_Q.add_coeffs.reserve(add_s); + + for (size_t i = 0; i < add_s; ++i) + { + mnt4_ate_add_coeffs ac; + in >> ac; + consume_OUTPUT_NEWLINE(in); + prec_Q.add_coeffs.emplace_back(ac); + } + + return in; +} + +/* final exponentiations */ + +mnt4_Fq4 mnt4_final_exponentiation_last_chunk(const mnt4_Fq4 &elt, const mnt4_Fq4 &elt_inv) +{ + enter_block("Call to mnt4_final_exponentiation_last_chunk"); + const mnt4_Fq4 elt_q = elt.Frobenius_map(1); + mnt4_Fq4 w1_part = elt_q.cyclotomic_exp(mnt4_final_exponent_last_chunk_w1); + mnt4_Fq4 w0_part; + if (mnt4_final_exponent_last_chunk_is_w0_neg) + { + w0_part = elt_inv.cyclotomic_exp(mnt4_final_exponent_last_chunk_abs_of_w0); + } else { + w0_part = elt.cyclotomic_exp(mnt4_final_exponent_last_chunk_abs_of_w0); + } + mnt4_Fq4 result = w1_part * w0_part; + leave_block("Call to mnt4_final_exponentiation_last_chunk"); + + return result; +} + +mnt4_Fq4 mnt4_final_exponentiation_first_chunk(const mnt4_Fq4 &elt, const mnt4_Fq4 &elt_inv) +{ + enter_block("Call to mnt4_final_exponentiation_first_chunk"); + + /* (q^2-1) */ + + /* elt_q2 = elt^(q^2) */ + const mnt4_Fq4 elt_q2 = elt.Frobenius_map(2); + /* elt_q3_over_elt = elt^(q^2-1) */ + const mnt4_Fq4 elt_q2_over_elt = elt_q2 * elt_inv; + + leave_block("Call to mnt4_final_exponentiation_first_chunk"); + return elt_q2_over_elt; +} + +mnt4_GT mnt4_final_exponentiation(const mnt4_Fq4 &elt) +{ + enter_block("Call to mnt4_final_exponentiation"); + const mnt4_Fq4 elt_inv = elt.inverse(); + const mnt4_Fq4 elt_to_first_chunk = mnt4_final_exponentiation_first_chunk(elt, elt_inv); + const mnt4_Fq4 elt_inv_to_first_chunk = mnt4_final_exponentiation_first_chunk(elt_inv, elt); + mnt4_GT result = mnt4_final_exponentiation_last_chunk(elt_to_first_chunk, elt_inv_to_first_chunk); + leave_block("Call to mnt4_final_exponentiation"); + + return result; +} + +/* affine ate miller loop */ + +mnt4_affine_ate_G1_precomputation mnt4_affine_ate_precompute_G1(const mnt4_G1& P) +{ + enter_block("Call to mnt4_affine_ate_precompute_G1"); + + mnt4_G1 Pcopy = P; + Pcopy.to_affine_coordinates(); + + mnt4_affine_ate_G1_precomputation result; + result.PX = Pcopy.X(); + result.PY = Pcopy.Y(); + result.PY_twist_squared = Pcopy.Y() * mnt4_twist.squared(); + + leave_block("Call to mnt4_affine_ate_precompute_G1"); + return result; +} + +mnt4_affine_ate_G2_precomputation mnt4_affine_ate_precompute_G2(const mnt4_G2& Q) +{ + enter_block("Call to mnt4_affine_ate_precompute_G2"); + + mnt4_G2 Qcopy(Q); + Qcopy.to_affine_coordinates(); + + mnt4_affine_ate_G2_precomputation result; + result.QX = Qcopy.X(); + result.QY = Qcopy.Y(); + + mnt4_Fq2 RX = Qcopy.X(); + mnt4_Fq2 RY = Qcopy.Y(); + + const bigint &loop_count = mnt4_ate_loop_count; + bool found_nonzero = false; + + std::vector NAF = find_wnaf(1, loop_count); + for (long i = NAF.size() - 1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + mnt4_affine_ate_coeffs c; + c.old_RX = RX; + c.old_RY = RY; + mnt4_Fq2 old_RX_2 = c.old_RX.squared(); + c.gamma = (old_RX_2 + old_RX_2 + old_RX_2 + mnt4_twist_coeff_a) * (c.old_RY + c.old_RY).inverse(); + c.gamma_twist = c.gamma * mnt4_twist; + c.gamma_X = c.gamma * c.old_RX; + result.coeffs.push_back(c); + + RX = c.gamma.squared() - (c.old_RX+c.old_RX); + RY = c.gamma * (c.old_RX - RX) - c.old_RY; + + if (NAF[i] != 0) + { + mnt4_affine_ate_coeffs c; + c.old_RX = RX; + c.old_RY = RY; + if (NAF[i] > 0) + { + c.gamma = (c.old_RY - result.QY) * (c.old_RX - result.QX).inverse(); + } + else + { + c.gamma = (c.old_RY + result.QY) * (c.old_RX - result.QX).inverse(); + } + c.gamma_twist = c.gamma * mnt4_twist; + c.gamma_X = c.gamma * result.QX; + result.coeffs.push_back(c); + + RX = c.gamma.squared() - (c.old_RX+result.QX); + RY = c.gamma * (c.old_RX - RX) - c.old_RY; + } + } + + /* TODO: maybe handle neg + if (mnt4_ate_is_loop_count_neg) + { + mnt4_ate_add_coeffs ac; + mnt4_affine_ate_dbl_coeffs c; + c.old_RX = RX; + c.old_RY = -RY; + old_RX_2 = c.old_RY.squared(); + c.gamma = (old_RX_2 + old_RX_2 + old_RX_2 + mnt4_coeff_a) * (c.old_RY + c.old_RY).inverse(); + c.gamma_twist = c.gamma * mnt4_twist; + c.gamma_X = c.gamma * c.old_RX; + result.coeffs.push_back(c); + } + */ + + leave_block("Call to mnt4_affine_ate_precompute_G2"); + return result; +} + +mnt4_Fq4 mnt4_affine_ate_miller_loop(const mnt4_affine_ate_G1_precomputation &prec_P, + const mnt4_affine_ate_G2_precomputation &prec_Q) +{ + enter_block("Call to mnt4_affine_ate_miller_loop"); + + mnt4_Fq4 f = mnt4_Fq4::one(); + + bool found_nonzero = false; + size_t idx = 0; + const bigint &loop_count = mnt4_ate_loop_count; + + std::vector NAF = find_wnaf(1, loop_count); + for (long i = NAF.size() - 1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + mnt4_param_p (skipping leading zeros) in MSB to LSB + order */ + mnt4_affine_ate_coeffs c = prec_Q.coeffs[idx++]; + + mnt4_Fq4 g_RR_at_P = mnt4_Fq4(prec_P.PY_twist_squared, + - prec_P.PX * c.gamma_twist + c.gamma_X - c.old_RY); + f = f.squared().mul_by_023(g_RR_at_P); + + if (NAF[i] != 0) + { + mnt4_affine_ate_coeffs c = prec_Q.coeffs[idx++]; + mnt4_Fq4 g_RQ_at_P; + if (NAF[i] > 0) + { + g_RQ_at_P = mnt4_Fq4(prec_P.PY_twist_squared, + - prec_P.PX * c.gamma_twist + c.gamma_X - prec_Q.QY); + } + else + { + g_RQ_at_P = mnt4_Fq4(prec_P.PY_twist_squared, + - prec_P.PX * c.gamma_twist + c.gamma_X + prec_Q.QY); + } + f = f.mul_by_023(g_RQ_at_P); + } + } + + /* TODO: maybe handle neg + if (mnt4_ate_is_loop_count_neg) + { + // TODO: + mnt4_affine_ate_coeffs ac = prec_Q.coeffs[idx++]; + mnt4_Fq4 g_RnegR_at_P = mnt4_Fq4(prec_P.PY_twist_squared, + - prec_P.PX * c.gamma_twist + c.gamma_X - c.old_RY); + f = (f * g_RnegR_at_P).inverse(); + } + */ + + leave_block("Call to mnt4_affine_ate_miller_loop"); + + return f; +} + +/* ate pairing */ + +struct extended_mnt4_G2_projective { + mnt4_Fq2 X; + mnt4_Fq2 Y; + mnt4_Fq2 Z; + mnt4_Fq2 T; + + void print() const + { + printf("extended mnt4_G2 projective X/Y/Z/T:\n"); + X.print(); + Y.print(); + Z.print(); + T.print(); + } + + void test_invariant() const + { + assert(T == Z.squared()); + } +}; + +void doubling_step_for_flipped_miller_loop(extended_mnt4_G2_projective ¤t, + mnt4_ate_dbl_coeffs &dc) +{ + const mnt4_Fq2 X = current.X, Y = current.Y, Z = current.Z, T = current.T; + + const mnt4_Fq2 A = T.squared(); // A = T1^2 + const mnt4_Fq2 B = X.squared(); // B = X1^2 + const mnt4_Fq2 C = Y.squared(); // C = Y1^2 + const mnt4_Fq2 D = C.squared(); // D = C^2 + const mnt4_Fq2 E = (X+C).squared() - B - D; // E = (X1+C)^2-B-D + const mnt4_Fq2 F = (B+B+B) + mnt4_twist_coeff_a * A; // F = 3*B + a *A + const mnt4_Fq2 G = F.squared(); // G = F^2 + + current.X = -(E+E+E+E) + G; // X3 = -4*E+G + current.Y = -mnt4_Fq("8")*D + F*(E+E-current.X); // Y3 = -8*D+F*(2*E-X3) + current.Z = (Y+Z).squared() - C - Z.squared(); // Z3 = (Y1+Z1)^2-C-Z1^2 + current.T = current.Z.squared(); // T3 = Z3^2 + + dc.c_H = (current.Z + T).squared() - current.T - A; // H = (Z3+T1)^2-T3-A + dc.c_4C = C+C+C+C; // fourC = 4*C + dc.c_J = (F+T).squared() - G - A; // J = (F+T1)^2-G-A + dc.c_L = (F+X).squared() - G - B; // L = (F+X1)^2-G-B + +#ifdef DEBUG + current.test_invariant(); +#endif +} + +void mixed_addition_step_for_flipped_miller_loop(const mnt4_Fq2 base_X, const mnt4_Fq2 base_Y, const mnt4_Fq2 base_Y_squared, + extended_mnt4_G2_projective ¤t, + mnt4_ate_add_coeffs &ac) +{ + const mnt4_Fq2 X1 = current.X, Y1 = current.Y, Z1 = current.Z, T1 = current.T; + const mnt4_Fq2 &x2 = base_X, &y2 = base_Y, &y2_squared = base_Y_squared; + + const mnt4_Fq2 B = x2 * T1; // B = x2 * T1 + const mnt4_Fq2 D = ((y2 + Z1).squared() - y2_squared - T1) * T1; // D = ((y2 + Z1)^2 - y2squared - T1) * T1 + const mnt4_Fq2 H = B - X1; // H = B - X1 + const mnt4_Fq2 I = H.squared(); // I = H^2 + const mnt4_Fq2 E = I + I + I + I; // E = 4*I + const mnt4_Fq2 J = H * E; // J = H * E + const mnt4_Fq2 V = X1 * E; // V = X1 * E + const mnt4_Fq2 L1 = D - (Y1 + Y1); // L1 = D - 2 * Y1 + + current.X = L1.squared() - J - (V+V); // X3 = L1^2 - J - 2*V + current.Y = L1 * (V-current.X) - (Y1+Y1) * J; // Y3 = L1 * (V-X3) - 2*Y1 * J + current.Z = (Z1+H).squared() - T1 - I; // Z3 = (Z1 + H)^2 - T1 - I + current.T = current.Z.squared(); // T3 = Z3^2 + + ac.c_L1 = L1; + ac.c_RZ = current.Z; +#ifdef DEBUG + current.test_invariant(); +#endif +} + +mnt4_ate_G1_precomp mnt4_ate_precompute_G1(const mnt4_G1& P) +{ + enter_block("Call to mnt4_ate_precompute_G1"); + + mnt4_G1 Pcopy = P; + Pcopy.to_affine_coordinates(); + + mnt4_ate_G1_precomp result; + result.PX = Pcopy.X(); + result.PY = Pcopy.Y(); + result.PX_twist = Pcopy.X() * mnt4_twist; + result.PY_twist = Pcopy.Y() * mnt4_twist; + + leave_block("Call to mnt4_ate_precompute_G1"); + return result; +} + +mnt4_ate_G2_precomp mnt4_ate_precompute_G2(const mnt4_G2& Q) +{ + enter_block("Call to mnt4_ate_precompute_G2"); + + mnt4_G2 Qcopy(Q); + Qcopy.to_affine_coordinates(); + + mnt4_ate_G2_precomp result; + result.QX = Qcopy.X(); + result.QY = Qcopy.Y(); + result.QY2 = Qcopy.Y().squared(); + result.QX_over_twist = Qcopy.X() * mnt4_twist.inverse(); + result.QY_over_twist = Qcopy.Y() * mnt4_twist.inverse(); + + extended_mnt4_G2_projective R; + R.X = Qcopy.X(); + R.Y = Qcopy.Y(); + R.Z = mnt4_Fq2::one(); + R.T = mnt4_Fq2::one(); + + const bigint &loop_count = mnt4_ate_loop_count; + bool found_one = false; + + for (long i = loop_count.max_bits() - 1; i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + mnt4_ate_dbl_coeffs dc; + doubling_step_for_flipped_miller_loop(R, dc); + result.dbl_coeffs.push_back(dc); + if (bit) + { + mnt4_ate_add_coeffs ac; + mixed_addition_step_for_flipped_miller_loop(result.QX, result.QY, result.QY2, R, ac); + result.add_coeffs.push_back(ac); + } + } + + if (mnt4_ate_is_loop_count_neg) + { + mnt4_Fq2 RZ_inv = R.Z.inverse(); + mnt4_Fq2 RZ2_inv = RZ_inv.squared(); + mnt4_Fq2 RZ3_inv = RZ2_inv * RZ_inv; + mnt4_Fq2 minus_R_affine_X = R.X * RZ2_inv; + mnt4_Fq2 minus_R_affine_Y = - R.Y * RZ3_inv; + mnt4_Fq2 minus_R_affine_Y2 = minus_R_affine_Y.squared(); + mnt4_ate_add_coeffs ac; + mixed_addition_step_for_flipped_miller_loop(minus_R_affine_X, minus_R_affine_Y, minus_R_affine_Y2, R, ac); + result.add_coeffs.push_back(ac); + } + + leave_block("Call to mnt4_ate_precompute_G2"); + return result; +} + +mnt4_Fq4 mnt4_ate_miller_loop(const mnt4_ate_G1_precomp &prec_P, + const mnt4_ate_G2_precomp &prec_Q) +{ + enter_block("Call to mnt4_ate_miller_loop"); + + mnt4_Fq2 L1_coeff = mnt4_Fq2(prec_P.PX, mnt4_Fq::zero()) - prec_Q.QX_over_twist; + + mnt4_Fq4 f = mnt4_Fq4::one(); + + bool found_one = false; + size_t dbl_idx = 0; + size_t add_idx = 0; + + const bigint &loop_count = mnt4_ate_loop_count; + for (long i = loop_count.max_bits() - 1; i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + mnt4_param_p (skipping leading zeros) in MSB to LSB + order */ + mnt4_ate_dbl_coeffs dc = prec_Q.dbl_coeffs[dbl_idx++]; + + mnt4_Fq4 g_RR_at_P = mnt4_Fq4(- dc.c_4C - dc.c_J * prec_P.PX_twist + dc.c_L, + dc.c_H * prec_P.PY_twist); + f = f.squared() * g_RR_at_P; + if (bit) + { + mnt4_ate_add_coeffs ac = prec_Q.add_coeffs[add_idx++]; + + mnt4_Fq4 g_RQ_at_P = mnt4_Fq4(ac.c_RZ * prec_P.PY_twist, + -(prec_Q.QY_over_twist * ac.c_RZ + L1_coeff * ac.c_L1)); + f = f * g_RQ_at_P; + } + } + + if (mnt4_ate_is_loop_count_neg) + { + mnt4_ate_add_coeffs ac = prec_Q.add_coeffs[add_idx++]; + mnt4_Fq4 g_RnegR_at_P = mnt4_Fq4(ac.c_RZ * prec_P.PY_twist, + -(prec_Q.QY_over_twist * ac.c_RZ + L1_coeff * ac.c_L1)); + f = (f * g_RnegR_at_P).inverse(); + } + + leave_block("Call to mnt4_ate_miller_loop"); + + return f; +} + +mnt4_Fq4 mnt4_ate_double_miller_loop(const mnt4_ate_G1_precomp &prec_P1, + const mnt4_ate_G2_precomp &prec_Q1, + const mnt4_ate_G1_precomp &prec_P2, + const mnt4_ate_G2_precomp &prec_Q2) +{ + enter_block("Call to mnt4_ate_double_miller_loop"); + + mnt4_Fq2 L1_coeff1 = mnt4_Fq2(prec_P1.PX, mnt4_Fq::zero()) - prec_Q1.QX_over_twist; + mnt4_Fq2 L1_coeff2 = mnt4_Fq2(prec_P2.PX, mnt4_Fq::zero()) - prec_Q2.QX_over_twist; + + mnt4_Fq4 f = mnt4_Fq4::one(); + + bool found_one = false; + size_t dbl_idx = 0; + size_t add_idx = 0; + + const bigint &loop_count = mnt4_ate_loop_count; + for (long i = loop_count.max_bits() - 1; i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + mnt4_param_p (skipping leading zeros) in MSB to LSB + order */ + mnt4_ate_dbl_coeffs dc1 = prec_Q1.dbl_coeffs[dbl_idx]; + mnt4_ate_dbl_coeffs dc2 = prec_Q2.dbl_coeffs[dbl_idx]; + ++dbl_idx; + + mnt4_Fq4 g_RR_at_P1 = mnt4_Fq4(- dc1.c_4C - dc1.c_J * prec_P1.PX_twist + dc1.c_L, + dc1.c_H * prec_P1.PY_twist); + + mnt4_Fq4 g_RR_at_P2 = mnt4_Fq4(- dc2.c_4C - dc2.c_J * prec_P2.PX_twist + dc2.c_L, + dc2.c_H * prec_P2.PY_twist); + + f = f.squared() * g_RR_at_P1 * g_RR_at_P2; + + if (bit) + { + mnt4_ate_add_coeffs ac1 = prec_Q1.add_coeffs[add_idx]; + mnt4_ate_add_coeffs ac2 = prec_Q2.add_coeffs[add_idx]; + ++add_idx; + + mnt4_Fq4 g_RQ_at_P1 = mnt4_Fq4(ac1.c_RZ * prec_P1.PY_twist, + -(prec_Q1.QY_over_twist * ac1.c_RZ + L1_coeff1 * ac1.c_L1)); + mnt4_Fq4 g_RQ_at_P2 = mnt4_Fq4(ac2.c_RZ * prec_P2.PY_twist, + -(prec_Q2.QY_over_twist * ac2.c_RZ + L1_coeff2 * ac2.c_L1)); + + f = f * g_RQ_at_P1 * g_RQ_at_P2; + } + } + + if (mnt4_ate_is_loop_count_neg) + { + mnt4_ate_add_coeffs ac1 = prec_Q1.add_coeffs[add_idx]; + mnt4_ate_add_coeffs ac2 = prec_Q2.add_coeffs[add_idx]; + ++add_idx; + mnt4_Fq4 g_RnegR_at_P1 = mnt4_Fq4(ac1.c_RZ * prec_P1.PY_twist, + -(prec_Q1.QY_over_twist * ac1.c_RZ + L1_coeff1 * ac1.c_L1)); + mnt4_Fq4 g_RnegR_at_P2 = mnt4_Fq4(ac2.c_RZ * prec_P2.PY_twist, + -(prec_Q2.QY_over_twist * ac2.c_RZ + L1_coeff2 * ac2.c_L1)); + + f = (f * g_RnegR_at_P1 * g_RnegR_at_P2).inverse(); + } + + leave_block("Call to mnt4_ate_double_miller_loop"); + + return f; +} + +mnt4_Fq4 mnt4_ate_pairing(const mnt4_G1& P, const mnt4_G2 &Q) +{ + enter_block("Call to mnt4_ate_pairing"); + mnt4_ate_G1_precomp prec_P = mnt4_ate_precompute_G1(P); + mnt4_ate_G2_precomp prec_Q = mnt4_ate_precompute_G2(Q); + mnt4_Fq4 result = mnt4_ate_miller_loop(prec_P, prec_Q); + leave_block("Call to mnt4_ate_pairing"); + return result; +} + +mnt4_GT mnt4_ate_reduced_pairing(const mnt4_G1 &P, const mnt4_G2 &Q) +{ + enter_block("Call to mnt4_ate_reduced_pairing"); + const mnt4_Fq4 f = mnt4_ate_pairing(P, Q); + const mnt4_GT result = mnt4_final_exponentiation(f); + leave_block("Call to mnt4_ate_reduced_pairing"); + return result; +} + +mnt4_G1_precomp mnt4_precompute_G1(const mnt4_G1& P) +{ + return mnt4_ate_precompute_G1(P); +} + +mnt4_G2_precomp mnt4_precompute_G2(const mnt4_G2& Q) +{ + return mnt4_ate_precompute_G2(Q); +} + +mnt4_Fq4 mnt4_miller_loop(const mnt4_G1_precomp &prec_P, + const mnt4_G2_precomp &prec_Q) +{ + return mnt4_ate_miller_loop(prec_P, prec_Q); +} + +mnt4_Fq4 mnt4_double_miller_loop(const mnt4_G1_precomp &prec_P1, + const mnt4_G2_precomp &prec_Q1, + const mnt4_G1_precomp &prec_P2, + const mnt4_G2_precomp &prec_Q2) +{ + return mnt4_ate_double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); +} + +mnt4_Fq4 mnt4_pairing(const mnt4_G1& P, + const mnt4_G2 &Q) +{ + return mnt4_ate_pairing(P, Q); +} + +mnt4_GT mnt4_reduced_pairing(const mnt4_G1 &P, + const mnt4_G2 &Q) +{ + return mnt4_ate_reduced_pairing(P, Q); +} + +mnt4_GT mnt4_affine_reduced_pairing(const mnt4_G1 &P, + const mnt4_G2 &Q) +{ + const mnt4_affine_ate_G1_precomputation prec_P = mnt4_affine_ate_precompute_G1(P); + const mnt4_affine_ate_G2_precomputation prec_Q = mnt4_affine_ate_precompute_G2(Q); + const mnt4_Fq4 f = mnt4_affine_ate_miller_loop(prec_P, prec_Q); + const mnt4_GT result = mnt4_final_exponentiation(f); + return result; +} + +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_pairing.d b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_pairing.d new file mode 100644 index 0000000..3c0089b --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_pairing.d @@ -0,0 +1,18 @@ +src/algebra/curves/mnt/mnt4/mnt4_pairing.o: \ + src/algebra/curves/mnt/mnt4/mnt4_pairing.cpp \ + src/algebra/curves/mnt/mnt4/mnt4_pairing.hpp \ + src/algebra/curves/mnt/mnt4/mnt4_init.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/mnt/mnt46_common.hpp src/algebra/fields/bigint.hpp \ + src/common/serialization.hpp src/common/serialization.tcc \ + src/common/utils.hpp src/common/utils.tcc src/algebra/fields/bigint.tcc \ + src/algebra/fields/fp.hpp src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc src/algebra/fields/fp2.hpp \ + src/algebra/fields/fp2.tcc src/algebra/fields/fp4.hpp \ + src/algebra/fields/fp4.tcc src/algebra/scalar_multiplication/wnaf.hpp \ + src/algebra/scalar_multiplication/wnaf.tcc \ + src/algebra/curves/mnt/mnt4/mnt4_g1.hpp \ + src/algebra/curves/curve_utils.hpp src/algebra/curves/curve_utils.tcc \ + src/algebra/curves/mnt/mnt4/mnt4_g2.hpp src/common/profiling.hpp diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_pairing.hpp b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_pairing.hpp new file mode 100644 index 0000000..0047115 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_pairing.hpp @@ -0,0 +1,148 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for pairing operations on MNT4. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT4_PAIRING_HPP_ +#define MNT4_PAIRING_HPP_ + +#include + +#include "algebra/curves/mnt/mnt4/mnt4_init.hpp" + +namespace libsnark { + +/* final exponentiation */ + +mnt4_Fq4 mnt4_final_exponentiation_last_chunk(const mnt4_Fq4 &elt, + const mnt4_Fq4 &elt_inv); +mnt4_Fq4 mnt4_final_exponentiation_first_chunk(const mnt4_Fq4 &elt, + const mnt4_Fq4 &elt_inv); +mnt4_GT mnt4_final_exponentiation(const mnt4_Fq4 &elt); + +/* affine ate miller loop */ + +struct mnt4_affine_ate_G1_precomputation { + mnt4_Fq PX; + mnt4_Fq PY; + mnt4_Fq2 PY_twist_squared; +}; + +struct mnt4_affine_ate_coeffs { + // TODO: trim (not all of them are needed) + mnt4_Fq2 old_RX; + mnt4_Fq2 old_RY; + mnt4_Fq2 gamma; + mnt4_Fq2 gamma_twist; + mnt4_Fq2 gamma_X; +}; + +struct mnt4_affine_ate_G2_precomputation { + mnt4_Fq2 QX; + mnt4_Fq2 QY; + std::vector coeffs; +}; + +mnt4_affine_ate_G1_precomputation mnt4_affine_ate_precompute_G1(const mnt4_G1& P); +mnt4_affine_ate_G2_precomputation mnt4_affine_ate_precompute_G2(const mnt4_G2& Q); + +mnt4_Fq4 mnt4_affine_ate_miller_loop(const mnt4_affine_ate_G1_precomputation &prec_P, + const mnt4_affine_ate_G2_precomputation &prec_Q); + +/* ate pairing */ + +struct mnt4_ate_G1_precomp { + mnt4_Fq PX; + mnt4_Fq PY; + mnt4_Fq2 PX_twist; + mnt4_Fq2 PY_twist; + + bool operator==(const mnt4_ate_G1_precomp &other) const; + friend std::ostream& operator<<(std::ostream &out, const mnt4_ate_G1_precomp &prec_P); + friend std::istream& operator>>(std::istream &in, mnt4_ate_G1_precomp &prec_P); +}; + +struct mnt4_ate_dbl_coeffs { + mnt4_Fq2 c_H; + mnt4_Fq2 c_4C; + mnt4_Fq2 c_J; + mnt4_Fq2 c_L; + + bool operator==(const mnt4_ate_dbl_coeffs &other) const; + friend std::ostream& operator<<(std::ostream &out, const mnt4_ate_dbl_coeffs &dc); + friend std::istream& operator>>(std::istream &in, mnt4_ate_dbl_coeffs &dc); +}; + +struct mnt4_ate_add_coeffs { + mnt4_Fq2 c_L1; + mnt4_Fq2 c_RZ; + + bool operator==(const mnt4_ate_add_coeffs &other) const; + friend std::ostream& operator<<(std::ostream &out, const mnt4_ate_add_coeffs &dc); + friend std::istream& operator>>(std::istream &in, mnt4_ate_add_coeffs &dc); +}; + +struct mnt4_ate_G2_precomp { + mnt4_Fq2 QX; + mnt4_Fq2 QY; + mnt4_Fq2 QY2; + mnt4_Fq2 QX_over_twist; + mnt4_Fq2 QY_over_twist; + std::vector dbl_coeffs; + std::vector add_coeffs; + + bool operator==(const mnt4_ate_G2_precomp &other) const; + friend std::ostream& operator<<(std::ostream &out, const mnt4_ate_G2_precomp &prec_Q); + friend std::istream& operator>>(std::istream &in, mnt4_ate_G2_precomp &prec_Q); +}; + +mnt4_ate_G1_precomp mnt4_ate_precompute_G1(const mnt4_G1& P); +mnt4_ate_G2_precomp mnt4_ate_precompute_G2(const mnt4_G2& Q); + +mnt4_Fq4 mnt4_ate_miller_loop(const mnt4_ate_G1_precomp &prec_P, + const mnt4_ate_G2_precomp &prec_Q); +mnt4_Fq4 mnt4_ate_double_miller_loop(const mnt4_ate_G1_precomp &prec_P1, + const mnt4_ate_G2_precomp &prec_Q1, + const mnt4_ate_G1_precomp &prec_P2, + const mnt4_ate_G2_precomp &prec_Q2); + +mnt4_Fq4 mnt4_ate_pairing(const mnt4_G1& P, + const mnt4_G2 &Q); +mnt4_GT mnt4_ate_reduced_pairing(const mnt4_G1 &P, + const mnt4_G2 &Q); + +/* choice of pairing */ + +typedef mnt4_ate_G1_precomp mnt4_G1_precomp; +typedef mnt4_ate_G2_precomp mnt4_G2_precomp; + +mnt4_G1_precomp mnt4_precompute_G1(const mnt4_G1& P); + +mnt4_G2_precomp mnt4_precompute_G2(const mnt4_G2& Q); + +mnt4_Fq4 mnt4_miller_loop(const mnt4_G1_precomp &prec_P, + const mnt4_G2_precomp &prec_Q); + +mnt4_Fq4 mnt4_double_miller_loop(const mnt4_G1_precomp &prec_P1, + const mnt4_G2_precomp &prec_Q1, + const mnt4_G1_precomp &prec_P2, + const mnt4_G2_precomp &prec_Q2); + +mnt4_Fq4 mnt4_pairing(const mnt4_G1& P, + const mnt4_G2 &Q); + +mnt4_GT mnt4_reduced_pairing(const mnt4_G1 &P, + const mnt4_G2 &Q); + +mnt4_GT mnt4_affine_reduced_pairing(const mnt4_G1 &P, + const mnt4_G2 &Q); + +} // libsnark + +#endif // MNT4_PAIRING_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_pp.cpp b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_pp.cpp new file mode 100644 index 0000000..17eccab --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_pp.cpp @@ -0,0 +1,105 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for public parameters of MNT4. + + See mnt4_pp.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" + +namespace libsnark { + +void mnt4_pp::init_public_params() +{ + init_mnt4_params(); +} + +mnt4_GT mnt4_pp::final_exponentiation(const mnt4_Fq4 &elt) +{ + return mnt4_final_exponentiation(elt); +} + +mnt4_G1_precomp mnt4_pp::precompute_G1(const mnt4_G1 &P) +{ + return mnt4_precompute_G1(P); +} + +mnt4_G2_precomp mnt4_pp::precompute_G2(const mnt4_G2 &Q) +{ + return mnt4_precompute_G2(Q); +} + +mnt4_Fq4 mnt4_pp::miller_loop(const mnt4_G1_precomp &prec_P, + const mnt4_G2_precomp &prec_Q) +{ + return mnt4_miller_loop(prec_P, prec_Q); +} + +mnt4_affine_ate_G1_precomputation mnt4_pp::affine_ate_precompute_G1(const mnt4_G1 &P) +{ + return mnt4_affine_ate_precompute_G1(P); +} + +mnt4_affine_ate_G2_precomputation mnt4_pp::affine_ate_precompute_G2(const mnt4_G2 &Q) +{ + return mnt4_affine_ate_precompute_G2(Q); +} + +mnt4_Fq4 mnt4_pp::affine_ate_miller_loop(const mnt4_affine_ate_G1_precomputation &prec_P, + const mnt4_affine_ate_G2_precomputation &prec_Q) +{ + return mnt4_affine_ate_miller_loop(prec_P, prec_Q); +} + +mnt4_Fq4 mnt4_pp::affine_ate_e_over_e_miller_loop(const mnt4_affine_ate_G1_precomputation &prec_P1, + const mnt4_affine_ate_G2_precomputation &prec_Q1, + const mnt4_affine_ate_G1_precomputation &prec_P2, + const mnt4_affine_ate_G2_precomputation &prec_Q2) +{ + return mnt4_affine_ate_miller_loop(prec_P1, prec_Q1) * mnt4_affine_ate_miller_loop(prec_P2, prec_Q2).unitary_inverse(); +} + +mnt4_Fq4 mnt4_pp::affine_ate_e_times_e_over_e_miller_loop(const mnt4_affine_ate_G1_precomputation &prec_P1, + const mnt4_affine_ate_G2_precomputation &prec_Q1, + const mnt4_affine_ate_G1_precomputation &prec_P2, + const mnt4_affine_ate_G2_precomputation &prec_Q2, + const mnt4_affine_ate_G1_precomputation &prec_P3, + const mnt4_affine_ate_G2_precomputation &prec_Q3) +{ + return ((mnt4_affine_ate_miller_loop(prec_P1, prec_Q1) * mnt4_affine_ate_miller_loop(prec_P2, prec_Q2)) * + mnt4_affine_ate_miller_loop(prec_P3, prec_Q3).unitary_inverse()); +} + +mnt4_Fq4 mnt4_pp::double_miller_loop(const mnt4_G1_precomp &prec_P1, + const mnt4_G2_precomp &prec_Q1, + const mnt4_G1_precomp &prec_P2, + const mnt4_G2_precomp &prec_Q2) +{ + return mnt4_double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); +} + +mnt4_Fq4 mnt4_pp::pairing(const mnt4_G1 &P, + const mnt4_G2 &Q) +{ + return mnt4_pairing(P, Q); +} + +mnt4_Fq4 mnt4_pp::reduced_pairing(const mnt4_G1 &P, + const mnt4_G2 &Q) +{ + return mnt4_reduced_pairing(P, Q); +} + +mnt4_Fq4 mnt4_pp::affine_reduced_pairing(const mnt4_G1 &P, + const mnt4_G2 &Q) +{ + return mnt4_affine_reduced_pairing(P, Q); +} + +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_pp.d b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_pp.d new file mode 100644 index 0000000..7748758 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_pp.d @@ -0,0 +1,19 @@ +src/algebra/curves/mnt/mnt4/mnt4_pp.o: \ + src/algebra/curves/mnt/mnt4/mnt4_pp.cpp \ + src/algebra/curves/mnt/mnt4/mnt4_pp.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/mnt/mnt4/mnt4_init.hpp \ + src/algebra/curves/mnt/mnt46_common.hpp src/algebra/fields/bigint.hpp \ + src/common/serialization.hpp src/common/serialization.tcc \ + src/common/utils.hpp src/common/utils.tcc src/algebra/fields/bigint.tcc \ + src/algebra/fields/fp.hpp src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc src/algebra/fields/fp2.hpp \ + src/algebra/fields/fp2.tcc src/algebra/fields/fp4.hpp \ + src/algebra/fields/fp4.tcc src/algebra/scalar_multiplication/wnaf.hpp \ + src/algebra/scalar_multiplication/wnaf.tcc \ + src/algebra/curves/mnt/mnt4/mnt4_g1.hpp \ + src/algebra/curves/curve_utils.hpp src/algebra/curves/curve_utils.tcc \ + src/algebra/curves/mnt/mnt4/mnt4_g2.hpp \ + src/algebra/curves/mnt/mnt4/mnt4_pairing.hpp diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_pp.hpp b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_pp.hpp new file mode 100644 index 0000000..f93fc31 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt4/mnt4_pp.hpp @@ -0,0 +1,80 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for public parameters of MNT4. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT4_PP_HPP_ +#define MNT4_PP_HPP_ + +#include "algebra/curves/public_params.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_init.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_g1.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_g2.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_pairing.hpp" + +namespace libsnark { + +class mnt4_pp { +public: + typedef mnt4_Fr Fp_type; + typedef mnt4_G1 G1_type; + typedef mnt4_G2 G2_type; + typedef mnt4_G1_precomp G1_precomp_type; + typedef mnt4_G2_precomp G2_precomp_type; + typedef mnt4_affine_ate_G1_precomputation affine_ate_G1_precomp_type; + typedef mnt4_affine_ate_G2_precomputation affine_ate_G2_precomp_type; + typedef mnt4_Fq Fq_type; + typedef mnt4_Fq2 Fqe_type; + typedef mnt4_Fq4 Fqk_type; + typedef mnt4_GT GT_type; + + static const bool has_affine_pairing = true; + + static void init_public_params(); + static mnt4_GT final_exponentiation(const mnt4_Fq4 &elt); + + static mnt4_G1_precomp precompute_G1(const mnt4_G1 &P); + static mnt4_G2_precomp precompute_G2(const mnt4_G2 &Q); + + static mnt4_Fq4 miller_loop(const mnt4_G1_precomp &prec_P, + const mnt4_G2_precomp &prec_Q); + + static mnt4_affine_ate_G1_precomputation affine_ate_precompute_G1(const mnt4_G1 &P); + static mnt4_affine_ate_G2_precomputation affine_ate_precompute_G2(const mnt4_G2 &Q); + static mnt4_Fq4 affine_ate_miller_loop(const mnt4_affine_ate_G1_precomputation &prec_P, + const mnt4_affine_ate_G2_precomputation &prec_Q); + + static mnt4_Fq4 affine_ate_e_over_e_miller_loop(const mnt4_affine_ate_G1_precomputation &prec_P1, + const mnt4_affine_ate_G2_precomputation &prec_Q1, + const mnt4_affine_ate_G1_precomputation &prec_P2, + const mnt4_affine_ate_G2_precomputation &prec_Q2); + static mnt4_Fq4 affine_ate_e_times_e_over_e_miller_loop(const mnt4_affine_ate_G1_precomputation &prec_P1, + const mnt4_affine_ate_G2_precomputation &prec_Q1, + const mnt4_affine_ate_G1_precomputation &prec_P2, + const mnt4_affine_ate_G2_precomputation &prec_Q2, + const mnt4_affine_ate_G1_precomputation &prec_P3, + const mnt4_affine_ate_G2_precomputation &prec_Q3); + + static mnt4_Fq4 double_miller_loop(const mnt4_G1_precomp &prec_P1, + const mnt4_G2_precomp &prec_Q1, + const mnt4_G1_precomp &prec_P2, + const mnt4_G2_precomp &prec_Q2); + + /* the following are used in test files */ + static mnt4_Fq4 pairing(const mnt4_G1 &P, + const mnt4_G2 &Q); + static mnt4_Fq4 reduced_pairing(const mnt4_G1 &P, + const mnt4_G2 &Q); + static mnt4_Fq4 affine_reduced_pairing(const mnt4_G1 &P, + const mnt4_G2 &Q); +}; + +} // libsnark + +#endif // MNT4_PP_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt46_common.cpp b/privacy/zsl/zsl/algebra/curves/mnt/mnt46_common.cpp new file mode 100644 index 0000000..50248f5 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt46_common.cpp @@ -0,0 +1,21 @@ +/** @file + ***************************************************************************** + + Implementation of functionality that is shared among MNT curves. + + See mnt46_common.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/mnt/mnt46_common.hpp" + +namespace libsnark { + +bigint mnt46_modulus_A; +bigint mnt46_modulus_B; + +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt46_common.d b/privacy/zsl/zsl/algebra/curves/mnt/mnt46_common.d new file mode 100644 index 0000000..4328c67 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt46_common.d @@ -0,0 +1,5 @@ +src/algebra/curves/mnt/mnt46_common.o: \ + src/algebra/curves/mnt/mnt46_common.cpp \ + src/algebra/curves/mnt/mnt46_common.hpp src/algebra/fields/bigint.hpp \ + src/common/serialization.hpp src/common/serialization.tcc \ + src/common/utils.hpp src/common/utils.tcc src/algebra/fields/bigint.tcc diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt46_common.hpp b/privacy/zsl/zsl/algebra/curves/mnt/mnt46_common.hpp new file mode 100644 index 0000000..b1e3080 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt46_common.hpp @@ -0,0 +1,30 @@ +/** @file + ***************************************************************************** + + Declaration of functionality that is shared among MNT curves. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT46_COMMON_HPP_ +#define MNT46_COMMON_HPP_ + +#include "algebra/fields/bigint.hpp" + +namespace libsnark { + +const mp_size_t mnt46_A_bitcount = 298; +const mp_size_t mnt46_B_bitcount = 298; + +const mp_size_t mnt46_A_limbs = (mnt46_A_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; +const mp_size_t mnt46_B_limbs = (mnt46_B_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; + +extern bigint mnt46_modulus_A; +extern bigint mnt46_modulus_B; + +} // libsnark + +#endif diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_g1.cpp b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_g1.cpp new file mode 100644 index 0000000..b0181de --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_g1.cpp @@ -0,0 +1,504 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the MNT6 G1 group. + + See mnt6_g1.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/mnt/mnt6/mnt6_g1.hpp" + +namespace libsnark { + +#ifdef PROFILE_OP_COUNTS +long long mnt6_G1::add_cnt = 0; +long long mnt6_G1::dbl_cnt = 0; +#endif + +std::vector mnt6_G1::wnaf_window_table; +std::vector mnt6_G1::fixed_base_exp_window_table; +mnt6_G1 mnt6_G1::G1_zero; +mnt6_G1 mnt6_G1::G1_one; +mnt6_Fq mnt6_G1::coeff_a; +mnt6_Fq mnt6_G1::coeff_b; + +mnt6_G1::mnt6_G1() +{ + this->X_ = G1_zero.X_; + this->Y_ = G1_zero.Y_; + this->Z_ = G1_zero.Z_; +} + +void mnt6_G1::print() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + mnt6_G1 copy(*this); + copy.to_affine_coordinates(); + gmp_printf("(%Nd , %Nd)\n", + copy.X_.as_bigint().data, mnt6_Fq::num_limbs, + copy.Y_.as_bigint().data, mnt6_Fq::num_limbs); + } +} + +void mnt6_G1::print_coordinates() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + gmp_printf("(%Nd : %Nd : %Nd)\n", + this->X_.as_bigint().data, mnt6_Fq::num_limbs, + this->Y_.as_bigint().data, mnt6_Fq::num_limbs, + this->Z_.as_bigint().data, mnt6_Fq::num_limbs); + } +} + +void mnt6_G1::to_affine_coordinates() +{ + if (this->is_zero()) + { + this->X_ = mnt6_Fq::zero(); + this->Y_ = mnt6_Fq::one(); + this->Z_ = mnt6_Fq::zero(); + } + else + { + const mnt6_Fq Z_inv = Z_.inverse(); + this->X_ = this->X_ * Z_inv; + this->Y_ = this->Y_ * Z_inv; + this->Z_ = mnt6_Fq::one(); + } +} + +void mnt6_G1::to_special() +{ + this->to_affine_coordinates(); +} + +bool mnt6_G1::is_special() const +{ + return (this->is_zero() || this->Z_ == mnt6_Fq::one()); +} + +bool mnt6_G1::is_zero() const +{ + return (this->X_.is_zero() && this->Z_.is_zero()); +} + +bool mnt6_G1::operator==(const mnt6_G1 &other) const +{ + if (this->is_zero()) + { + return other.is_zero(); + } + + if (other.is_zero()) + { + return false; + } + + /* now neither is O */ + + // X1/Z1 = X2/Z2 <=> X1*Z2 = X2*Z1 + if ((this->X_ * other.Z_) != (other.X_ * this->Z_)) + { + return false; + } + + // Y1/Z1 = Y2/Z2 <=> Y1*Z2 = Y2*Z1 + if ((this->Y_ * other.Z_) != (other.Y_ * this->Z_)) + { + return false; + } + + return true; +} + +bool mnt6_G1::operator!=(const mnt6_G1& other) const +{ + return !(operator==(other)); +} + +mnt6_G1 mnt6_G1::operator+(const mnt6_G1 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case, and then all the rest + /* + The code below is equivalent to (but faster than) the snippet below: + + if (this->operator==(other)) + { + return this->dbl(); + } + else + { + return this->add(other); + } + */ + + const mnt6_Fq X1Z2 = (this->X_) * (other.Z_); // X1Z2 = X1*Z2 + const mnt6_Fq X2Z1 = (this->Z_) * (other.X_); // X2Z1 = X2*Z1 + + // (used both in add and double checks) + + const mnt6_Fq Y1Z2 = (this->Y_) * (other.Z_); // Y1Z2 = Y1*Z2 + const mnt6_Fq Y2Z1 = (this->Z_) * (other.Y_); // Y2Z1 = Y2*Z1 + + if (X1Z2 == X2Z1 && Y1Z2 == Y2Z1) + { + // perform dbl case + const mnt6_Fq XX = (this->X_).squared(); // XX = X1^2 + const mnt6_Fq ZZ = (this->Z_).squared(); // ZZ = Z1^2 + const mnt6_Fq w = mnt6_G1::coeff_a * ZZ + (XX + XX + XX); // w = a*ZZ + 3*XX + const mnt6_Fq Y1Z1 = (this->Y_) * (this->Z_); + const mnt6_Fq s = Y1Z1 + Y1Z1; // s = 2*Y1*Z1 + const mnt6_Fq ss = s.squared(); // ss = s^2 + const mnt6_Fq sss = s * ss; // sss = s*ss + const mnt6_Fq R = (this->Y_) * s; // R = Y1*s + const mnt6_Fq RR = R.squared(); // RR = R^2 + const mnt6_Fq B = ((this->X_)+R).squared()-XX-RR; // B = (X1+R)^2 - XX - RR + const mnt6_Fq h = w.squared() - (B+B); // h = w^2 - 2*B + const mnt6_Fq X3 = h * s; // X3 = h*s + const mnt6_Fq Y3 = w * (B-h)-(RR+RR); // Y3 = w*(B-h) - 2*RR + const mnt6_Fq Z3 = sss; // Z3 = sss + + return mnt6_G1(X3, Y3, Z3); + } + + // if we have arrived here we are in the add case + const mnt6_Fq Z1Z2 = (this->Z_) * (other.Z_); // Z1Z2 = Z1*Z2 + const mnt6_Fq u = Y2Z1 - Y1Z2; // u = Y2*Z1-Y1Z2 + const mnt6_Fq uu = u.squared(); // uu = u^2 + const mnt6_Fq v = X2Z1 - X1Z2; // v = X2*Z1-X1Z2 + const mnt6_Fq vv = v.squared(); // vv = v^2 + const mnt6_Fq vvv = v * vv; // vvv = v*vv + const mnt6_Fq R = vv * X1Z2; // R = vv*X1Z2 + const mnt6_Fq A = uu * Z1Z2 - (vvv + R + R); // A = uu*Z1Z2 - vvv - 2*R + const mnt6_Fq X3 = v * A; // X3 = v*A + const mnt6_Fq Y3 = u * (R-A) - vvv * Y1Z2; // Y3 = u*(R-A) - vvv*Y1Z2 + const mnt6_Fq Z3 = vvv * Z1Z2; // Z3 = vvv*Z1Z2 + + return mnt6_G1(X3, Y3, Z3); +} + +mnt6_G1 mnt6_G1::operator-() const +{ + return mnt6_G1(this->X_, -(this->Y_), this->Z_); +} + + +mnt6_G1 mnt6_G1::operator-(const mnt6_G1 &other) const +{ + return (*this) + (-other); +} + +mnt6_G1 mnt6_G1::add(const mnt6_G1 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return (*this); + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case + if (this->operator==(other)) + { + return this->dbl(); + } + +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#addition-add-1998-cmo-2 + + const mnt6_Fq Y1Z2 = (this->Y_) * (other.Z_); // Y1Z2 = Y1*Z2 + const mnt6_Fq X1Z2 = (this->X_) * (other.Z_); // X1Z2 = X1*Z2 + const mnt6_Fq Z1Z2 = (this->Z_) * (other.Z_); // Z1Z2 = Z1*Z2 + const mnt6_Fq u = (other.Y_) * (this->Z_) - Y1Z2; // u = Y2*Z1-Y1Z2 + const mnt6_Fq uu = u.squared(); // uu = u^2 + const mnt6_Fq v = (other.X_) * (this->Z_) - X1Z2; // v = X2*Z1-X1Z2 + const mnt6_Fq vv = v.squared(); // vv = v^2 + const mnt6_Fq vvv = v * vv; // vvv = v*vv + const mnt6_Fq R = vv * X1Z2; // R = vv*X1Z2 + const mnt6_Fq A = uu * Z1Z2 - (vvv + R + R); // A = uu*Z1Z2 - vvv - 2*R + const mnt6_Fq X3 = v * A; // X3 = v*A + const mnt6_Fq Y3 = u * (R-A) - vvv * Y1Z2; // Y3 = u*(R-A) - vvv*Y1Z2 + const mnt6_Fq Z3 = vvv * Z1Z2; // Z3 = vvv*Z1Z2 + + return mnt6_G1(X3, Y3, Z3); +} + +mnt6_G1 mnt6_G1::mixed_add(const mnt6_G1 &other) const +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#addition-add-1998-cmo-2 + //assert(other.Z == mnt6_Fq::one()); + + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return (*this); + } + +#ifdef DEBUG + assert(other.is_special()); +#endif + + const mnt6_Fq &X1Z2 = (this->X_); // X1Z2 = X1*Z2 (but other is special and not zero) + const mnt6_Fq X2Z1 = (this->Z_) * (other.X_); // X2Z1 = X2*Z1 + + // (used both in add and double checks) + + const mnt6_Fq &Y1Z2 = (this->Y_); // Y1Z2 = Y1*Z2 (but other is special and not zero) + const mnt6_Fq Y2Z1 = (this->Z_) * (other.Y_); // Y2Z1 = Y2*Z1 + + if (X1Z2 == X2Z1 && Y1Z2 == Y2Z1) + { + return this->dbl(); + } + + mnt6_Fq u = Y2Z1 - this->Y_; // u = Y2*Z1-Y1 + mnt6_Fq uu = u.squared(); // uu = u2 + mnt6_Fq v = X2Z1 - this->X_; // v = X2*Z1-X1 + mnt6_Fq vv = v.squared(); // vv = v2 + mnt6_Fq vvv = v*vv; // vvv = v*vv + mnt6_Fq R = vv * this->X_; // R = vv*X1 + mnt6_Fq A = uu * this->Z_ - vvv - R - R; // A = uu*Z1-vvv-2*R + mnt6_Fq X3 = v * A; // X3 = v*A + mnt6_Fq Y3 = u*(R-A) - vvv * this->Y_; // Y3 = u*(R-A)-vvv*Y1 + mnt6_Fq Z3 = vvv * this->Z_; // Z3 = vvv*Z1 + + return mnt6_G1(X3, Y3, Z3); +} + +mnt6_G1 mnt6_G1::dbl() const +{ +#ifdef PROFILE_OP_COUNTS + this->dbl_cnt++; +#endif + if (this->is_zero()) + { + return (*this); + } + else + { + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#doubling-dbl-2007-bl + + const mnt6_Fq XX = (this->X_).squared(); // XX = X1^2 + const mnt6_Fq ZZ = (this->Z_).squared(); // ZZ = Z1^2 + const mnt6_Fq w = mnt6_G1::coeff_a * ZZ + (XX + XX + XX); // w = a*ZZ + 3*XX + const mnt6_Fq Y1Z1 = (this->Y_) * (this->Z_); + const mnt6_Fq s = Y1Z1 + Y1Z1; // s = 2*Y1*Z1 + const mnt6_Fq ss = s.squared(); // ss = s^2 + const mnt6_Fq sss = s * ss; // sss = s*ss + const mnt6_Fq R = (this->Y_) * s; // R = Y1*s + const mnt6_Fq RR = R.squared(); // RR = R^2 + const mnt6_Fq B = ((this->X_)+R).squared()-XX-RR; // B = (X1+R)^2 - XX - RR + const mnt6_Fq h = w.squared() - (B+B); // h = w^2 - 2*B + const mnt6_Fq X3 = h * s; // X3 = h*s + const mnt6_Fq Y3 = w * (B-h)-(RR+RR); // Y3 = w*(B-h) - 2*RR + const mnt6_Fq Z3 = sss; // Z3 = sss + + return mnt6_G1(X3, Y3, Z3); + } +} + +bool mnt6_G1::is_well_formed() const +{ + if (this->is_zero()) + { + return true; + } + else + { + /* + y^2 = x^3 + ax + b + + We are using projective, so equation we need to check is actually + + (y/z)^2 = (x/z)^3 + a (x/z) + b + z y^2 = x^3 + a z^2 x + b z^3 + + z (y^2 - b z^2) = x ( x^2 + a z^2) + */ + const mnt6_Fq X2 = this->X_.squared(); + const mnt6_Fq Y2 = this->Y_.squared(); + const mnt6_Fq Z2 = this->Z_.squared(); + + return (this->Z_ * (Y2 - mnt6_G1::coeff_b * Z2) == this->X_ * (X2 + mnt6_G1::coeff_a * Z2)); + } +} + +mnt6_G1 mnt6_G1::zero() +{ + return G1_zero; +} + +mnt6_G1 mnt6_G1::one() +{ + return G1_one; +} + +mnt6_G1 mnt6_G1::random_element() +{ + return (scalar_field::random_element().as_bigint()) * G1_one; +} + +std::ostream& operator<<(std::ostream &out, const mnt6_G1 &g) +{ + mnt6_G1 copy(g); + copy.to_affine_coordinates(); + + out << (copy.is_zero() ? 1 : 0) << OUTPUT_SEPARATOR; +#ifdef NO_PT_COMPRESSION + out << copy.X_ << OUTPUT_SEPARATOR << copy.Y_; +#else + /* storing LSB of Y */ + out << copy.X_ << OUTPUT_SEPARATOR << (copy.Y_.as_bigint().data[0] & 1); +#endif + + return out; +} + +std::istream& operator>>(std::istream &in, mnt6_G1 &g) +{ + char is_zero; + mnt6_Fq tX, tY; + +#ifdef NO_PT_COMPRESSION + in >> is_zero >> tX >> tY; + is_zero -= '0'; +#else + in.read((char*)&is_zero, 1); // this reads is_zero; + is_zero -= '0'; + consume_OUTPUT_SEPARATOR(in); + + unsigned char Y_lsb; + in >> tX; + consume_OUTPUT_SEPARATOR(in); + in.read((char*)&Y_lsb, 1); + Y_lsb -= '0'; + + // y = +/- sqrt(x^3 + a*x + b) + if (!is_zero) + { + mnt6_Fq tX2 = tX.squared(); + mnt6_Fq tY2 = (tX2 + mnt6_G1::coeff_a) * tX + mnt6_G1::coeff_b; + tY = tY2.sqrt(); + + if ((tY.as_bigint().data[0] & 1) != Y_lsb) + { + tY = -tY; + } + } +#endif + // using projective coordinates + if (!is_zero) + { + g.X_ = tX; + g.Y_ = tY; + g.Z_ = mnt6_Fq::one(); + } + else + { + g = mnt6_G1::zero(); + } + + return in; +} + +std::ostream& operator<<(std::ostream& out, const std::vector &v) +{ + out << v.size() << "\n"; + for (const mnt6_G1& t : v) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +std::istream& operator>>(std::istream& in, std::vector &v) +{ + v.clear(); + + size_t s; + in >> s; + consume_newline(in); + + v.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + mnt6_G1 g; + in >> g; + consume_OUTPUT_NEWLINE(in); + v.emplace_back(g); + } + + return in; +} + +template<> +void batch_to_special_all_non_zeros(std::vector &vec) +{ + std::vector Z_vec; + Z_vec.reserve(vec.size()); + + for (auto &el: vec) + { + Z_vec.emplace_back(el.Z()); + } + batch_invert(Z_vec); + + const mnt6_Fq one = mnt6_Fq::one(); + + for (size_t i = 0; i < vec.size(); ++i) + { + vec[i] = mnt6_G1(vec[i].X() * Z_vec[i], vec[i].Y() * Z_vec[i], one); + } +} + +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_g1.d b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_g1.d new file mode 100644 index 0000000..03c4c1f --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_g1.d @@ -0,0 +1,19 @@ +src/algebra/curves/mnt/mnt6/mnt6_g1.o: \ + src/algebra/curves/mnt/mnt6/mnt6_g1.cpp \ + src/algebra/curves/mnt/mnt6/mnt6_g1.hpp \ + src/algebra/curves/curve_utils.hpp src/algebra/fields/bigint.hpp \ + src/common/serialization.hpp src/common/serialization.tcc \ + src/common/utils.hpp src/common/utils.tcc src/algebra/fields/bigint.tcc \ + src/algebra/curves/curve_utils.tcc \ + src/algebra/curves/mnt/mnt6/mnt6_init.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/mnt/mnt46_common.hpp src/algebra/fields/fp.hpp \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc src/algebra/fields/fp3.hpp \ + src/algebra/fields/fp3.tcc src/algebra/fields/fp6_2over3.hpp \ + src/algebra/fields/fp2.hpp src/algebra/fields/fp2.tcc \ + src/algebra/fields/fp6_2over3.tcc \ + src/algebra/scalar_multiplication/wnaf.hpp \ + src/algebra/scalar_multiplication/wnaf.tcc diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_g1.hpp b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_g1.hpp new file mode 100644 index 0000000..e03b403 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_g1.hpp @@ -0,0 +1,109 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the MNT6 G1 group. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT6_G1_HPP_ +#define MNT6_G1_HPP_ + +#include + +#include "algebra/curves/curve_utils.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_init.hpp" + +namespace libsnark { + +class mnt6_G1; +std::ostream& operator<<(std::ostream &, const mnt6_G1&); +std::istream& operator>>(std::istream &, mnt6_G1&); + +class mnt6_G1 { +private: + mnt6_Fq X_, Y_, Z_; +public: +#ifdef PROFILE_OP_COUNTS + static long long add_cnt; + static long long dbl_cnt; +#endif + static std::vector wnaf_window_table; + static std::vector fixed_base_exp_window_table; + static mnt6_G1 G1_zero; + static mnt6_G1 G1_one; + static mnt6_Fq coeff_a; + static mnt6_Fq coeff_b; + + typedef mnt6_Fq base_field; + typedef mnt6_Fr scalar_field; + + // using projective coordinates + mnt6_G1(); + mnt6_G1(const mnt6_Fq& X, const mnt6_Fq& Y) : X_(X), Y_(Y), Z_(base_field::one()) {} + mnt6_G1(const mnt6_Fq& X, const mnt6_Fq& Y, const mnt6_Fq& Z) : X_(X), Y_(Y), Z_(Z) {} + + mnt6_Fq X() const { return X_; } + mnt6_Fq Y() const { return Y_; } + mnt6_Fq Z() const { return Z_; } + + void print() const; + void print_coordinates() const; + + void to_affine_coordinates(); + void to_special(); + bool is_special() const; + + bool is_zero() const; + + bool operator==(const mnt6_G1 &other) const; + bool operator!=(const mnt6_G1 &other) const; + + mnt6_G1 operator+(const mnt6_G1 &other) const; + mnt6_G1 operator-() const; + mnt6_G1 operator-(const mnt6_G1 &other) const; + + mnt6_G1 add(const mnt6_G1 &other) const; + mnt6_G1 mixed_add(const mnt6_G1 &other) const; + mnt6_G1 dbl() const; + + bool is_well_formed() const; + + static mnt6_G1 zero(); + static mnt6_G1 one(); + static mnt6_G1 random_element(); + + static size_t size_in_bits() { return base_field::size_in_bits() + 1; } + static bigint base_field_char() { return base_field::field_char(); } + static bigint order() { return scalar_field::field_char(); } + + friend std::ostream& operator<<(std::ostream &out, const mnt6_G1 &g); + friend std::istream& operator>>(std::istream &in, mnt6_G1 &g); +}; + +template +mnt6_G1 operator*(const bigint &lhs, const mnt6_G1 &rhs) +{ + return scalar_mul(rhs, lhs); +} + +template& modulus_p> +mnt6_G1 operator*(const Fp_model &lhs, const mnt6_G1 &rhs) +{ + return scalar_mul(rhs, lhs.as_bigint()); +} + +std::ostream& operator<<(std::ostream& out, const std::vector &v); +std::istream& operator>>(std::istream& in, std::vector &v); + +template +void batch_to_special_all_non_zeros(std::vector &vec); +template<> +void batch_to_special_all_non_zeros(std::vector &vec); + +} // libsnark + +#endif // MNT6_G1_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_g2.cpp b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_g2.cpp new file mode 100644 index 0000000..d39c6a7 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_g2.cpp @@ -0,0 +1,503 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the MNT6 G2 group. + + See mnt6_g2.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/mnt/mnt6/mnt6_g2.hpp" + +namespace libsnark { + +#ifdef PROFILE_OP_COUNTS +long long mnt6_G2::add_cnt = 0; +long long mnt6_G2::dbl_cnt = 0; +#endif + +std::vector mnt6_G2::wnaf_window_table; +std::vector mnt6_G2::fixed_base_exp_window_table; +mnt6_Fq3 mnt6_G2::twist; +mnt6_Fq3 mnt6_G2::coeff_a; +mnt6_Fq3 mnt6_G2::coeff_b; +mnt6_G2 mnt6_G2::G2_zero; +mnt6_G2 mnt6_G2::G2_one; + +mnt6_G2::mnt6_G2() +{ + this->X_ = G2_zero.X_; + this->Y_ = G2_zero.Y_; + this->Z_ = G2_zero.Z_; +} + +mnt6_Fq3 mnt6_G2::mul_by_a(const mnt6_Fq3 &elt) +{ + return mnt6_Fq3(mnt6_twist_mul_by_a_c0 * elt.c1, mnt6_twist_mul_by_a_c1 * elt.c2, mnt6_twist_mul_by_a_c2 * elt.c0); +} + +mnt6_Fq3 mnt6_G2::mul_by_b(const mnt6_Fq3 &elt) +{ + return mnt6_Fq3(mnt6_twist_mul_by_b_c0 * elt.c0, mnt6_twist_mul_by_b_c1 * elt.c1, mnt6_twist_mul_by_b_c2 * elt.c2); +} + +void mnt6_G2::print() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + mnt6_G2 copy(*this); + copy.to_affine_coordinates(); + gmp_printf("(%Nd*z^2 + %Nd*z + %Nd , %Nd*z^2 + %Nd*z + %Nd)\n", + copy.X_.c2.as_bigint().data, mnt6_Fq::num_limbs, + copy.X_.c1.as_bigint().data, mnt6_Fq::num_limbs, + copy.X_.c0.as_bigint().data, mnt6_Fq::num_limbs, + copy.Y_.c2.as_bigint().data, mnt6_Fq::num_limbs, + copy.Y_.c1.as_bigint().data, mnt6_Fq::num_limbs, + copy.Y_.c0.as_bigint().data, mnt6_Fq::num_limbs); + } +} + +void mnt6_G2::print_coordinates() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + gmp_printf("(%Nd*z^2 + %Nd*z + %Nd : %Nd*z^2 + %Nd*z + %Nd : %Nd*z^2 + %Nd*z + %Nd)\n", + this->X_.c2.as_bigint().data, mnt6_Fq::num_limbs, + this->X_.c1.as_bigint().data, mnt6_Fq::num_limbs, + this->X_.c0.as_bigint().data, mnt6_Fq::num_limbs, + this->Y_.c2.as_bigint().data, mnt6_Fq::num_limbs, + this->Y_.c1.as_bigint().data, mnt6_Fq::num_limbs, + this->Y_.c0.as_bigint().data, mnt6_Fq::num_limbs, + this->Z_.c2.as_bigint().data, mnt6_Fq::num_limbs, + this->Z_.c1.as_bigint().data, mnt6_Fq::num_limbs, + this->Z_.c0.as_bigint().data, mnt6_Fq::num_limbs); + } +} + +void mnt6_G2::to_affine_coordinates() +{ + if (this->is_zero()) + { + this->X_ = mnt6_Fq3::zero(); + this->Y_ = mnt6_Fq3::one(); + this->Z_ = mnt6_Fq3::zero(); + } + else + { + const mnt6_Fq3 Z_inv = Z_.inverse(); + this->X_ = this->X_ * Z_inv; + this->Y_ = this->Y_ * Z_inv; + this->Z_ = mnt6_Fq3::one(); + } +} + +void mnt6_G2::to_special() +{ + this->to_affine_coordinates(); +} + +bool mnt6_G2::is_special() const +{ + return (this->is_zero() || this->Z_ == mnt6_Fq3::one()); +} + +bool mnt6_G2::is_zero() const +{ + // TODO: use zero for here + return (this->X_.is_zero() && this->Z_.is_zero()); +} + +bool mnt6_G2::operator==(const mnt6_G2 &other) const +{ + if (this->is_zero()) + { + return other.is_zero(); + } + + if (other.is_zero()) + { + return false; + } + + /* now neither is O */ + + // X1/Z1 = X2/Z2 <=> X1*Z2 = X2*Z1 + if ((this->X_ * other.Z_) != (other.X_ * this->Z_)) + { + return false; + } + + // Y1/Z1 = Y2/Z2 <=> Y1*Z2 = Y2*Z1 + if ((this->Y_ * other.Z_) != (other.Y_ * this->Z_)) + { + return false; + } + + return true; +} + +bool mnt6_G2::operator!=(const mnt6_G2& other) const +{ + return !(operator==(other)); +} + +mnt6_G2 mnt6_G2::operator+(const mnt6_G2 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case, and then all the rest + /* + The code below is equivalent to (but faster than) the snippet below: + + if (this->operator==(other)) + { + return this->dbl(); + } + else + { + return this->add(other); + } + */ + + const mnt6_Fq3 X1Z2 = (this->X_) * (other.Z_); // X1Z2 = X1*Z2 + const mnt6_Fq3 X2Z1 = (this->Z_) * (other.X_); // X2Z1 = X2*Z1 + + // (used both in add and double checks) + + const mnt6_Fq3 Y1Z2 = (this->Y_) * (other.Z_); // Y1Z2 = Y1*Z2 + const mnt6_Fq3 Y2Z1 = (this->Z_) * (other.Y_); // Y2Z1 = Y2*Z1 + + if (X1Z2 == X2Z1 && Y1Z2 == Y2Z1) + { + // perform dbl case + const mnt6_Fq3 XX = (this->X_).squared(); // XX = X1^2 + const mnt6_Fq3 ZZ = (this->Z_).squared(); // ZZ = Z1^2 + const mnt6_Fq3 w = mnt6_G2::mul_by_a(ZZ) + (XX + XX + XX); // w = a*ZZ + 3*XX + const mnt6_Fq3 Y1Z1 = (this->Y_) * (this->Z_); + const mnt6_Fq3 s = Y1Z1 + Y1Z1; // s = 2*Y1*Z1 + const mnt6_Fq3 ss = s.squared(); // ss = s^2 + const mnt6_Fq3 sss = s * ss; // sss = s*ss + const mnt6_Fq3 R = (this->Y_) * s; // R = Y1*s + const mnt6_Fq3 RR = R.squared(); // RR = R^2 + const mnt6_Fq3 B = ((this->X_)+R).squared()-XX-RR; // B = (X1+R)^2 - XX - RR + const mnt6_Fq3 h = w.squared() - (B+B); // h = w^2 - 2*B + const mnt6_Fq3 X3 = h * s; // X3 = h*s + const mnt6_Fq3 Y3 = w * (B-h)-(RR+RR); // Y3 = w*(B-h) - 2*RR + const mnt6_Fq3 Z3 = sss; // Z3 = sss + + return mnt6_G2(X3, Y3, Z3); + } + + // if we have arrived here we are in the add case + const mnt6_Fq3 Z1Z2 = (this->Z_) * (other.Z_); // Z1Z2 = Z1*Z2 + const mnt6_Fq3 u = Y2Z1 - Y1Z2; // u = Y2*Z1-Y1Z2 + const mnt6_Fq3 uu = u.squared(); // uu = u^2 + const mnt6_Fq3 v = X2Z1 - X1Z2; // v = X2*Z1-X1Z2 + const mnt6_Fq3 vv = v.squared(); // vv = v^2 + const mnt6_Fq3 vvv = v * vv; // vvv = v*vv + const mnt6_Fq3 R = vv * X1Z2; // R = vv*X1Z2 + const mnt6_Fq3 A = uu * Z1Z2 - (vvv + R + R); // A = uu*Z1Z2 - vvv - 2*R + const mnt6_Fq3 X3 = v * A; // X3 = v*A + const mnt6_Fq3 Y3 = u * (R-A) - vvv * Y1Z2; // Y3 = u*(R-A) - vvv*Y1Z2 + const mnt6_Fq3 Z3 = vvv * Z1Z2; // Z3 = vvv*Z1Z2 + + return mnt6_G2(X3, Y3, Z3); +} + +mnt6_G2 mnt6_G2::operator-() const +{ + return mnt6_G2(this->X_, -(this->Y_), this->Z_); +} + + +mnt6_G2 mnt6_G2::operator-(const mnt6_G2 &other) const +{ + return (*this) + (-other); +} + +mnt6_G2 mnt6_G2::add(const mnt6_G2 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return (*this); + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case + if (this->operator==(other)) + { + return this->dbl(); + } + +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#addition-add-1998-cmo-2 + + const mnt6_Fq3 Y1Z2 = (this->Y_) * (other.Z_); // Y1Z2 = Y1*Z2 + const mnt6_Fq3 X1Z2 = (this->X_) * (other.Z_); // X1Z2 = X1*Z2 + const mnt6_Fq3 Z1Z2 = (this->Z_) * (other.Z_); // Z1Z2 = Z1*Z2 + const mnt6_Fq3 u = (other.Y_) * (this->Z_) - Y1Z2; // u = Y2*Z1-Y1Z2 + const mnt6_Fq3 uu = u.squared(); // uu = u^2 + const mnt6_Fq3 v = (other.X_) * (this->Z_) - X1Z2; // v = X2*Z1-X1Z2 + const mnt6_Fq3 vv = v.squared(); // vv = v^2 + const mnt6_Fq3 vvv = v * vv; // vvv = v*vv + const mnt6_Fq3 R = vv * X1Z2; // R = vv*X1Z2 + const mnt6_Fq3 A = uu * Z1Z2 - (vvv + R + R); // A = uu*Z1Z2 - vvv - 2*R + const mnt6_Fq3 X3 = v * A; // X3 = v*A + const mnt6_Fq3 Y3 = u * (R-A) - vvv * Y1Z2; // Y3 = u*(R-A) - vvv*Y1Z2 + const mnt6_Fq3 Z3 = vvv * Z1Z2; // Z3 = vvv*Z1Z2 + + return mnt6_G2(X3, Y3, Z3); +} + +mnt6_G2 mnt6_G2::mixed_add(const mnt6_G2 &other) const +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#addition-add-1998-cmo-2 + //assert(other.Z == mnt6_Fq3::one()); + + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return (*this); + } + +#ifdef DEBUG + assert(other.is_special()); +#endif + + const mnt6_Fq3 &X1Z2 = (this->X_); // X1Z2 = X1*Z2 (but other is special and not zero) + const mnt6_Fq3 X2Z1 = (this->Z_) * (other.X_); // X2Z1 = X2*Z1 + + // (used both in add and double checks) + + const mnt6_Fq3 &Y1Z2 = (this->Y_); // Y1Z2 = Y1*Z2 (but other is special and not zero) + const mnt6_Fq3 Y2Z1 = (this->Z_) * (other.Y_); // Y2Z1 = Y2*Z1 + + if (X1Z2 == X2Z1 && Y1Z2 == Y2Z1) + { + return this->dbl(); + } + + const mnt6_Fq3 u = Y2Z1 - this->Y_; // u = Y2*Z1-Y1 + const mnt6_Fq3 uu = u.squared(); // uu = u2 + const mnt6_Fq3 v = X2Z1 - this->X_; // v = X2*Z1-X1 + const mnt6_Fq3 vv = v.squared(); // vv = v2 + const mnt6_Fq3 vvv = v*vv; // vvv = v*vv + const mnt6_Fq3 R = vv * this->X_; // R = vv*X1 + const mnt6_Fq3 A = uu * this->Z_ - vvv - R - R; // A = uu*Z1-vvv-2*R + const mnt6_Fq3 X3 = v * A; // X3 = v*A + const mnt6_Fq3 Y3 = u*(R-A) - vvv * this->Y_; // Y3 = u*(R-A)-vvv*Y1 + const mnt6_Fq3 Z3 = vvv * this->Z_; // Z3 = vvv*Z1 + + return mnt6_G2(X3, Y3, Z3); +} + +mnt6_G2 mnt6_G2::dbl() const +{ +#ifdef PROFILE_OP_COUNTS + this->dbl_cnt++; +#endif + if (this->is_zero()) + { + return (*this); + } + else + { + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#doubling-dbl-2007-bl + + const mnt6_Fq3 XX = (this->X_).squared(); // XX = X1^2 + const mnt6_Fq3 ZZ = (this->Z_).squared(); // ZZ = Z1^2 + const mnt6_Fq3 w = mnt6_G2::mul_by_a(ZZ) + (XX + XX + XX); // w = a*ZZ + 3*XX + const mnt6_Fq3 Y1Z1 = (this->Y_) * (this->Z_); + const mnt6_Fq3 s = Y1Z1 + Y1Z1; // s = 2*Y1*Z1 + const mnt6_Fq3 ss = s.squared(); // ss = s^2 + const mnt6_Fq3 sss = s * ss; // sss = s*ss + const mnt6_Fq3 R = (this->Y_) * s; // R = Y1*s + const mnt6_Fq3 RR = R.squared(); // RR = R^2 + const mnt6_Fq3 B = ((this->X_)+R).squared()-XX-RR; // B = (X1+R)^2 - XX - RR + const mnt6_Fq3 h = w.squared() - (B+B); // h = w^2-2*B + const mnt6_Fq3 X3 = h * s; // X3 = h*s + const mnt6_Fq3 Y3 = w * (B-h)-(RR+RR); // Y3 = w*(B-h) - 2*RR + const mnt6_Fq3 Z3 = sss; // Z3 = sss + + return mnt6_G2(X3, Y3, Z3); + } +} + +mnt6_G2 mnt6_G2::mul_by_q() const +{ + return mnt6_G2(mnt6_twist_mul_by_q_X * (this->X_).Frobenius_map(1), + mnt6_twist_mul_by_q_Y * (this->Y_).Frobenius_map(1), + (this->Z_).Frobenius_map(1)); +} + +bool mnt6_G2::is_well_formed() const +{ + if (this->is_zero()) + { + return true; + } + else + { + + /* + y^2 = x^3 + ax + b + + We are using projective, so equation we need to check is actually + + (y/z)^2 = (x/z)^3 + a (x/z) + b + z y^2 = x^3 + a z^2 x + b z^3 + + z (y^2 - b z^2) = x ( x^2 + a z^2) + */ + const mnt6_Fq3 X2 = this->X_.squared(); + const mnt6_Fq3 Y2 = this->Y_.squared(); + const mnt6_Fq3 Z2 = this->Z_.squared(); + const mnt6_Fq3 aZ2 = mnt6_twist_coeff_a * Z2; + + return (this->Z_ * (Y2 - mnt6_twist_coeff_b * Z2) == this->X_ * (X2 + aZ2)); + } +} + +mnt6_G2 mnt6_G2::zero() +{ + return G2_zero; +} + +mnt6_G2 mnt6_G2::one() +{ + return G2_one; +} + +mnt6_G2 mnt6_G2::random_element() +{ + return (mnt6_Fr::random_element().as_bigint()) * G2_one; +} + +std::ostream& operator<<(std::ostream &out, const mnt6_G2 &g) +{ + mnt6_G2 copy(g); + copy.to_affine_coordinates(); + + out << (copy.is_zero() ? 1 : 0) << OUTPUT_SEPARATOR; +#ifdef NO_PT_COMPRESSION + out << copy.X_ << OUTPUT_SEPARATOR << copy.Y_; +#else + /* storing LSB of Y */ + out << copy.X_ << OUTPUT_SEPARATOR << (copy.Y_.c0.as_bigint().data[0] & 1); +#endif + + return out; +} + +std::istream& operator>>(std::istream &in, mnt6_G2 &g) +{ + char is_zero; + mnt6_Fq3 tX, tY; + +#ifdef NO_PT_COMPRESSION + in >> is_zero >> tX >> tY; + is_zero -= '0'; +#else + in.read((char*)&is_zero, 1); // this reads is_zero; + is_zero -= '0'; + consume_OUTPUT_SEPARATOR(in); + + unsigned char Y_lsb; + in >> tX; + consume_OUTPUT_SEPARATOR(in); + in.read((char*)&Y_lsb, 1); + Y_lsb -= '0'; + + // y = +/- sqrt(x^3 + a*x + b) + if (!is_zero) + { + const mnt6_Fq3 tX2 = tX.squared(); + const mnt6_Fq3 tY2 = (tX2 + mnt6_twist_coeff_a) * tX + mnt6_twist_coeff_b; + tY = tY2.sqrt(); + + if ((tY.c0.as_bigint().data[0] & 1) != Y_lsb) + { + tY = -tY; + } + } +#endif + // using projective coordinates + if (!is_zero) + { + g.X_ = tX; + g.Y_ = tY; + g.Z_ = mnt6_Fq3::one(); + } + else + { + g = mnt6_G2::zero(); + } + + return in; +} + +template<> +void batch_to_special_all_non_zeros(std::vector &vec) +{ + std::vector Z_vec; + Z_vec.reserve(vec.size()); + + for (auto &el: vec) + { + Z_vec.emplace_back(el.Z()); + } + batch_invert(Z_vec); + + const mnt6_Fq3 one = mnt6_Fq3::one(); + + for (size_t i = 0; i < vec.size(); ++i) + { + vec[i] = mnt6_G2(vec[i].X() * Z_vec[i], vec[i].Y() * Z_vec[i], one); + } +} + +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_g2.d b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_g2.d new file mode 100644 index 0000000..998212a --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_g2.d @@ -0,0 +1,19 @@ +src/algebra/curves/mnt/mnt6/mnt6_g2.o: \ + src/algebra/curves/mnt/mnt6/mnt6_g2.cpp \ + src/algebra/curves/mnt/mnt6/mnt6_g2.hpp \ + src/algebra/curves/curve_utils.hpp src/algebra/fields/bigint.hpp \ + src/common/serialization.hpp src/common/serialization.tcc \ + src/common/utils.hpp src/common/utils.tcc src/algebra/fields/bigint.tcc \ + src/algebra/curves/curve_utils.tcc \ + src/algebra/curves/mnt/mnt6/mnt6_init.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/mnt/mnt46_common.hpp src/algebra/fields/fp.hpp \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc src/algebra/fields/fp3.hpp \ + src/algebra/fields/fp3.tcc src/algebra/fields/fp6_2over3.hpp \ + src/algebra/fields/fp2.hpp src/algebra/fields/fp2.tcc \ + src/algebra/fields/fp6_2over3.tcc \ + src/algebra/scalar_multiplication/wnaf.hpp \ + src/algebra/scalar_multiplication/wnaf.tcc diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_g2.hpp b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_g2.hpp new file mode 100644 index 0000000..b14cadb --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_g2.hpp @@ -0,0 +1,111 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the MNT6 G2 group. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT6_G2_HPP_ +#define MNT6_G2_HPP_ + +#include + +#include "algebra/curves/curve_utils.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_init.hpp" + +namespace libsnark { + +class mnt6_G2; +std::ostream& operator<<(std::ostream &, const mnt6_G2&); +std::istream& operator>>(std::istream &, mnt6_G2&); + +class mnt6_G2 { +private: + mnt6_Fq3 X_, Y_, Z_; +public: +#ifdef PROFILE_OP_COUNTS + static long long add_cnt; + static long long dbl_cnt; +#endif + static std::vector wnaf_window_table; + static std::vector fixed_base_exp_window_table; + static mnt6_G2 G2_zero; + static mnt6_G2 G2_one; + static mnt6_Fq3 twist; + static mnt6_Fq3 coeff_a; + static mnt6_Fq3 coeff_b; + + typedef mnt6_Fq base_field; + typedef mnt6_Fq3 twist_field; + typedef mnt6_Fr scalar_field; + + // using projective coordinates + mnt6_G2(); + mnt6_G2(const mnt6_Fq3& X, const mnt6_Fq3& Y, const mnt6_Fq3& Z) : X_(X), Y_(Y), Z_(Z) {} + + mnt6_Fq3 X() const { return X_; } + mnt6_Fq3 Y() const { return Y_; } + mnt6_Fq3 Z() const { return Z_; } + + static mnt6_Fq3 mul_by_a(const mnt6_Fq3 &elt); + static mnt6_Fq3 mul_by_b(const mnt6_Fq3 &elt); + + void print() const; + void print_coordinates() const; + + void to_affine_coordinates(); + void to_special(); + bool is_special() const; + + bool is_zero() const; + + bool operator==(const mnt6_G2 &other) const; + bool operator!=(const mnt6_G2 &other) const; + + mnt6_G2 operator+(const mnt6_G2 &other) const; + mnt6_G2 operator-() const; + mnt6_G2 operator-(const mnt6_G2 &other) const; + + mnt6_G2 add(const mnt6_G2 &other) const; + mnt6_G2 mixed_add(const mnt6_G2 &other) const; + mnt6_G2 dbl() const; + mnt6_G2 mul_by_q() const; + + bool is_well_formed() const; + + static mnt6_G2 zero(); + static mnt6_G2 one(); + static mnt6_G2 random_element(); + + static size_t size_in_bits() { return twist_field::size_in_bits() + 1; } + static bigint base_field_char() { return base_field::field_char(); } + static bigint order() { return scalar_field::field_char(); } + + friend std::ostream& operator<<(std::ostream &out, const mnt6_G2 &g); + friend std::istream& operator>>(std::istream &in, mnt6_G2 &g); +}; + +template +mnt6_G2 operator*(const bigint &lhs, const mnt6_G2 &rhs) +{ + return scalar_mul(rhs, lhs); +} + +template& modulus_p> +mnt6_G2 operator*(const Fp_model &lhs, const mnt6_G2 &rhs) +{ + return scalar_mul(rhs, lhs.as_bigint()); +} + +template +void batch_to_special_all_non_zeros(std::vector &vec); +template<> +void batch_to_special_all_non_zeros(std::vector &vec); + +} // libsnark + +#endif // MNT6_G2_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_init.cpp b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_init.cpp new file mode 100644 index 0000000..715a6be --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_init.cpp @@ -0,0 +1,277 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for initializing MNT6. + + See mnt6_init.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/mnt/mnt6/mnt6_init.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_g1.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_g2.hpp" + +namespace libsnark { + +//bigint mnt6_modulus_r = mnt46_modulus_B; +//bigint mnt6_modulus_q = mnt46_modulus_A; + +mnt6_Fq3 mnt6_twist; +mnt6_Fq3 mnt6_twist_coeff_a; +mnt6_Fq3 mnt6_twist_coeff_b; +mnt6_Fq mnt6_twist_mul_by_a_c0; +mnt6_Fq mnt6_twist_mul_by_a_c1; +mnt6_Fq mnt6_twist_mul_by_a_c2; +mnt6_Fq mnt6_twist_mul_by_b_c0; +mnt6_Fq mnt6_twist_mul_by_b_c1; +mnt6_Fq mnt6_twist_mul_by_b_c2; +mnt6_Fq mnt6_twist_mul_by_q_X; +mnt6_Fq mnt6_twist_mul_by_q_Y; + +bigint mnt6_ate_loop_count; +bool mnt6_ate_is_loop_count_neg; +bigint<6*mnt6_q_limbs> mnt6_final_exponent; +bigint mnt6_final_exponent_last_chunk_abs_of_w0; +bool mnt6_final_exponent_last_chunk_is_w0_neg; +bigint mnt6_final_exponent_last_chunk_w1; + +void init_mnt6_params() +{ + typedef bigint bigint_r; + typedef bigint bigint_q; + + assert(sizeof(mp_limb_t) == 8 || sizeof(mp_limb_t) == 4); // Montgomery assumes this + + /* parameters for scalar field Fr */ + mnt6_modulus_r = bigint_r("475922286169261325753349249653048451545124879242694725395555128576210262817955800483758081"); + assert(mnt6_Fr::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + mnt6_Fr::Rsquared = bigint_r("273000478523237720910981655601160860640083126627235719712980612296263966512828033847775776"); + mnt6_Fr::Rcubed = bigint_r("427298980065529822574935274648041073124704261331681436071990730954930769758106792920349077"); + mnt6_Fr::inv = 0xb071a1b67165ffff; + } + if (sizeof(mp_limb_t) == 4) + { + mnt6_Fr::Rsquared = bigint_r("273000478523237720910981655601160860640083126627235719712980612296263966512828033847775776"); + mnt6_Fr::Rcubed = bigint_r("427298980065529822574935274648041073124704261331681436071990730954930769758106792920349077"); + mnt6_Fr::inv = 0x7165ffff; + } + mnt6_Fr::num_bits = 298; + mnt6_Fr::euler = bigint_r("237961143084630662876674624826524225772562439621347362697777564288105131408977900241879040"); + mnt6_Fr::s = 17; + mnt6_Fr::t = bigint_r("3630998887399759870554727551674258816109656366292531779446068791017229177993437198515"); + mnt6_Fr::t_minus_1_over_2 = bigint_r("1815499443699879935277363775837129408054828183146265889723034395508614588996718599257"); + mnt6_Fr::multiplicative_generator = mnt6_Fr("17"); + mnt6_Fr::root_of_unity = mnt6_Fr("264706250571800080758069302369654305530125675521263976034054878017580902343339784464690243"); + mnt6_Fr::nqr = mnt6_Fr("17"); + mnt6_Fr::nqr_to_t = mnt6_Fr("264706250571800080758069302369654305530125675521263976034054878017580902343339784464690243"); + + /* parameters for base field Fq */ + mnt6_modulus_q = bigint_q("475922286169261325753349249653048451545124878552823515553267735739164647307408490559963137"); + assert(mnt6_Fq::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + mnt6_Fq::Rsquared = bigint_q("163983144722506446826715124368972380525894397127205577781234305496325861831001705438796139"); + mnt6_Fq::Rcubed = bigint_q("207236281459091063710247635236340312578688659363066707916716212805695955118593239854980171"); + mnt6_Fq::inv = 0xbb4334a3ffffffff; + } + if (sizeof(mp_limb_t) == 4) + { + mnt6_Fq::Rsquared = bigint_q("163983144722506446826715124368972380525894397127205577781234305496325861831001705438796139"); + mnt6_Fq::Rcubed = bigint_q("207236281459091063710247635236340312578688659363066707916716212805695955118593239854980171"); + mnt6_Fq::inv = 0xffffffff; + } + mnt6_Fq::num_bits = 298; + mnt6_Fq::euler = bigint_q("237961143084630662876674624826524225772562439276411757776633867869582323653704245279981568"); + mnt6_Fq::s = 34; + mnt6_Fq::t = bigint_q("27702323054502562488973446286577291993024111641153199339359284829066871159442729"); + mnt6_Fq::t_minus_1_over_2 = bigint_q("13851161527251281244486723143288645996512055820576599669679642414533435579721364"); + mnt6_Fq::multiplicative_generator = mnt6_Fq("10"); + mnt6_Fq::root_of_unity = mnt6_Fq("120638817826913173458768829485690099845377008030891618010109772937363554409782252579816313"); + mnt6_Fq::nqr = mnt6_Fq("5"); + mnt6_Fq::nqr_to_t = mnt6_Fq("406220604243090401056429458730298145937262552508985450684842547562990900634752279902740880"); + + /* parameters for twist field Fq3 */ + mnt6_Fq3::euler = bigint<3*mnt6_q_limbs>("53898680178554951715397245154796036139463891589001478629193136369124915637741423690184935056189295242736833704290747216410090671804540908400210778934462129625646263095398323485795557551284190224166851571615834194321908328559167529729507439069424158411618728014749106176"); + mnt6_Fq3::s = 34; + mnt6_Fq3::t = bigint<3*mnt6_q_limbs>("6274632199033507112809136178669989590936327770934612330653836993631547740397674926811006741620285348354004521888069251599964996777072188956687550402067383940523288107407084140669968625447269322370045302856694231080113482726640944570478452261237446033817102203"); + mnt6_Fq3::t_minus_1_over_2 = bigint<3*mnt6_q_limbs>("3137316099516753556404568089334994795468163885467306165326918496815773870198837463405503370810142674177002260944034625799982498388536094478343775201033691970261644053703542070334984312723634661185022651428347115540056741363320472285239226130618723016908551101"); + mnt6_Fq3::non_residue = mnt6_Fq("5"); + mnt6_Fq3::nqr = mnt6_Fq3(mnt6_Fq("5"),mnt6_Fq("0"),mnt6_Fq("0")); + mnt6_Fq3::nqr_to_t = mnt6_Fq3(mnt6_Fq("154361449678783505076984156275977937654331103361174469632346230549735979552469642799720052"),mnt6_Fq("0"),mnt6_Fq("0")); + mnt6_Fq3::Frobenius_coeffs_c1[0] = mnt6_Fq("1"); + mnt6_Fq3::Frobenius_coeffs_c1[1] = mnt6_Fq("471738898967521029133040851318449165997304108729558973770077319830005517129946578866686956"); + mnt6_Fq3::Frobenius_coeffs_c1[2] = mnt6_Fq("4183387201740296620308398334599285547820769823264541783190415909159130177461911693276180"); + mnt6_Fq3::Frobenius_coeffs_c2[0] = mnt6_Fq("1"); + mnt6_Fq3::Frobenius_coeffs_c2[1] = mnt6_Fq("4183387201740296620308398334599285547820769823264541783190415909159130177461911693276180"); + mnt6_Fq3::Frobenius_coeffs_c2[2] = mnt6_Fq("471738898967521029133040851318449165997304108729558973770077319830005517129946578866686956"); + + /* parameters for Fq6 */ + mnt6_Fq6::non_residue = mnt6_Fq("5"); + mnt6_Fq6::Frobenius_coeffs_c1[0] = mnt6_Fq("1"); + mnt6_Fq6::Frobenius_coeffs_c1[1] = mnt6_Fq("471738898967521029133040851318449165997304108729558973770077319830005517129946578866686957"); + mnt6_Fq6::Frobenius_coeffs_c1[2] = mnt6_Fq("471738898967521029133040851318449165997304108729558973770077319830005517129946578866686956"); + mnt6_Fq6::Frobenius_coeffs_c1[3] = mnt6_Fq("475922286169261325753349249653048451545124878552823515553267735739164647307408490559963136"); + mnt6_Fq6::Frobenius_coeffs_c1[4] = mnt6_Fq("4183387201740296620308398334599285547820769823264541783190415909159130177461911693276180"); + mnt6_Fq6::Frobenius_coeffs_c1[5] = mnt6_Fq("4183387201740296620308398334599285547820769823264541783190415909159130177461911693276181"); + mnt6_Fq6::my_Fp2::non_residue = mnt6_Fq3::non_residue; + + /* choice of short Weierstrass curve and its twist */ + mnt6_G1::coeff_a = mnt6_Fq("11"); + mnt6_G1::coeff_b = mnt6_Fq("106700080510851735677967319632585352256454251201367587890185989362936000262606668469523074"); + mnt6_twist = mnt6_Fq3(mnt6_Fq::zero(), mnt6_Fq::one(), mnt6_Fq::zero()); + mnt6_twist_coeff_a = mnt6_Fq3(mnt6_Fq::zero(), mnt6_Fq::zero(), + mnt6_G1::coeff_a); + mnt6_twist_coeff_b = mnt6_Fq3(mnt6_G1::coeff_b * mnt6_Fq3::non_residue, + mnt6_Fq::zero(), mnt6_Fq::zero()); + mnt6_G2::twist = mnt6_twist; + mnt6_G2::coeff_a = mnt6_twist_coeff_a; + mnt6_G2::coeff_b = mnt6_twist_coeff_b; + mnt6_twist_mul_by_a_c0 = mnt6_G1::coeff_a * mnt6_Fq3::non_residue; + mnt6_twist_mul_by_a_c1 = mnt6_G1::coeff_a * mnt6_Fq3::non_residue; + mnt6_twist_mul_by_a_c2 = mnt6_G1::coeff_a; + mnt6_twist_mul_by_b_c0 = mnt6_G1::coeff_b * mnt6_Fq3::non_residue; + mnt6_twist_mul_by_b_c1 = mnt6_G1::coeff_b * mnt6_Fq3::non_residue; + mnt6_twist_mul_by_b_c2 = mnt6_G1::coeff_b * mnt6_Fq3::non_residue; + mnt6_twist_mul_by_q_X = mnt6_Fq("4183387201740296620308398334599285547820769823264541783190415909159130177461911693276180"); + mnt6_twist_mul_by_q_Y = mnt6_Fq("475922286169261325753349249653048451545124878552823515553267735739164647307408490559963136"); + + /* choice of group G1 */ + mnt6_G1::G1_zero = mnt6_G1(mnt6_Fq::zero(), + mnt6_Fq::one(), + mnt6_Fq::zero()); + mnt6_G1::G1_one = mnt6_G1(mnt6_Fq("336685752883082228109289846353937104185698209371404178342968838739115829740084426881123453"), + mnt6_Fq("402596290139780989709332707716568920777622032073762749862342374583908837063963736098549800"), + mnt6_Fq::one()); + + mnt6_G1::wnaf_window_table.resize(0); + mnt6_G1::wnaf_window_table.push_back(11); + mnt6_G1::wnaf_window_table.push_back(24); + mnt6_G1::wnaf_window_table.push_back(60); + mnt6_G1::wnaf_window_table.push_back(127); + + mnt6_G1::fixed_base_exp_window_table.resize(0); + // window 1 is unbeaten in [-inf, 3.96] + mnt6_G1::fixed_base_exp_window_table.push_back(1); + // window 2 is unbeaten in [3.96, 9.67] + mnt6_G1::fixed_base_exp_window_table.push_back(4); + // window 3 is unbeaten in [9.67, 25.13] + mnt6_G1::fixed_base_exp_window_table.push_back(10); + // window 4 is unbeaten in [25.13, 60.31] + mnt6_G1::fixed_base_exp_window_table.push_back(25); + // window 5 is unbeaten in [60.31, 146.07] + mnt6_G1::fixed_base_exp_window_table.push_back(60); + // window 6 is unbeaten in [146.07, 350.09] + mnt6_G1::fixed_base_exp_window_table.push_back(146); + // window 7 is unbeaten in [350.09, 844.54] + mnt6_G1::fixed_base_exp_window_table.push_back(350); + // window 8 is unbeaten in [844.54, 1839.64] + mnt6_G1::fixed_base_exp_window_table.push_back(845); + // window 9 is unbeaten in [1839.64, 3904.26] + mnt6_G1::fixed_base_exp_window_table.push_back(1840); + // window 10 is unbeaten in [3904.26, 11309.42] + mnt6_G1::fixed_base_exp_window_table.push_back(3904); + // window 11 is unbeaten in [11309.42, 24015.57] + mnt6_G1::fixed_base_exp_window_table.push_back(11309); + // window 12 is unbeaten in [24015.57, 72288.57] + mnt6_G1::fixed_base_exp_window_table.push_back(24016); + // window 13 is unbeaten in [72288.57, 138413.22] + mnt6_G1::fixed_base_exp_window_table.push_back(72289); + // window 14 is unbeaten in [138413.22, 156390.30] + mnt6_G1::fixed_base_exp_window_table.push_back(138413); + // window 15 is unbeaten in [156390.30, 562560.50] + mnt6_G1::fixed_base_exp_window_table.push_back(156390); + // window 16 is unbeaten in [562560.50, 1036742.02] + mnt6_G1::fixed_base_exp_window_table.push_back(562560); + // window 17 is unbeaten in [1036742.02, 2053818.86] + mnt6_G1::fixed_base_exp_window_table.push_back(1036742); + // window 18 is unbeaten in [2053818.86, 4370223.95] + mnt6_G1::fixed_base_exp_window_table.push_back(2053819); + // window 19 is unbeaten in [4370223.95, 8215703.81] + mnt6_G1::fixed_base_exp_window_table.push_back(4370224); + // window 20 is unbeaten in [8215703.81, 42682375.43] + mnt6_G1::fixed_base_exp_window_table.push_back(8215704); + // window 21 is never the best + mnt6_G1::fixed_base_exp_window_table.push_back(0); + // window 22 is unbeaten in [42682375.43, inf] + mnt6_G1::fixed_base_exp_window_table.push_back(42682375); + + /* choice of group G2 */ + mnt6_G2::G2_zero = mnt6_G2(mnt6_Fq3::zero(), + mnt6_Fq3::one(), + mnt6_Fq3::zero()); + mnt6_G2::G2_one = mnt6_G2(mnt6_Fq3(mnt6_Fq("421456435772811846256826561593908322288509115489119907560382401870203318738334702321297427"), + mnt6_Fq("103072927438548502463527009961344915021167584706439945404959058962657261178393635706405114"), + mnt6_Fq("143029172143731852627002926324735183809768363301149009204849580478324784395590388826052558")), + mnt6_Fq3(mnt6_Fq("464673596668689463130099227575639512541218133445388869383893594087634649237515554342751377"), + mnt6_Fq("100642907501977375184575075967118071807821117960152743335603284583254620685343989304941678"), + mnt6_Fq("123019855502969896026940545715841181300275180157288044663051565390506010149881373807142903")), + mnt6_Fq3::one()); + + mnt6_G2::wnaf_window_table.resize(0); + mnt6_G2::wnaf_window_table.push_back(5); + mnt6_G2::wnaf_window_table.push_back(15); + mnt6_G2::wnaf_window_table.push_back(39); + mnt6_G2::wnaf_window_table.push_back(109); + + mnt6_G2::fixed_base_exp_window_table.resize(0); + // window 1 is unbeaten in [-inf, 4.25] + mnt6_G2::fixed_base_exp_window_table.push_back(1); + // window 2 is unbeaten in [4.25, 10.22] + mnt6_G2::fixed_base_exp_window_table.push_back(4); + // window 3 is unbeaten in [10.22, 24.85] + mnt6_G2::fixed_base_exp_window_table.push_back(10); + // window 4 is unbeaten in [24.85, 60.06] + mnt6_G2::fixed_base_exp_window_table.push_back(25); + // window 5 is unbeaten in [60.06, 143.61] + mnt6_G2::fixed_base_exp_window_table.push_back(60); + // window 6 is unbeaten in [143.61, 345.66] + mnt6_G2::fixed_base_exp_window_table.push_back(144); + // window 7 is unbeaten in [345.66, 818.56] + mnt6_G2::fixed_base_exp_window_table.push_back(346); + // window 8 is unbeaten in [818.56, 1782.06] + mnt6_G2::fixed_base_exp_window_table.push_back(819); + // window 9 is unbeaten in [1782.06, 4002.45] + mnt6_G2::fixed_base_exp_window_table.push_back(1782); + // window 10 is unbeaten in [4002.45, 10870.18] + mnt6_G2::fixed_base_exp_window_table.push_back(4002); + // window 11 is unbeaten in [10870.18, 18022.51] + mnt6_G2::fixed_base_exp_window_table.push_back(10870); + // window 12 is unbeaten in [18022.51, 43160.74] + mnt6_G2::fixed_base_exp_window_table.push_back(18023); + // window 13 is unbeaten in [43160.74, 149743.32] + mnt6_G2::fixed_base_exp_window_table.push_back(43161); + // window 14 is never the best + mnt6_G2::fixed_base_exp_window_table.push_back(0); + // window 15 is unbeaten in [149743.32, 551844.13] + mnt6_G2::fixed_base_exp_window_table.push_back(149743); + // window 16 is unbeaten in [551844.13, 1041827.91] + mnt6_G2::fixed_base_exp_window_table.push_back(551844); + // window 17 is unbeaten in [1041827.91, 1977371.53] + mnt6_G2::fixed_base_exp_window_table.push_back(1041828); + // window 18 is unbeaten in [1977371.53, 3703619.51] + mnt6_G2::fixed_base_exp_window_table.push_back(1977372); + // window 19 is unbeaten in [3703619.51, 7057236.87] + mnt6_G2::fixed_base_exp_window_table.push_back(3703620); + // window 20 is unbeaten in [7057236.87, 38554491.67] + mnt6_G2::fixed_base_exp_window_table.push_back(7057237); + // window 21 is never the best + mnt6_G2::fixed_base_exp_window_table.push_back(0); + // window 22 is unbeaten in [38554491.67, inf] + mnt6_G2::fixed_base_exp_window_table.push_back(38554492); + + /* pairing parameters */ + mnt6_ate_loop_count = bigint_q("689871209842287392837045615510547309923794944"); + mnt6_ate_is_loop_count_neg = true; + mnt6_final_exponent = bigint<6*mnt6_q_limbs>("24416320138090509697890595414313438768353977489862543935904010715439066975957855922532159264213056712140358746422742237328406558352706591021642230618060502855451264045397444793186876199015256781648746888625527075466063075011307800862173764236311342105211681121426931616843635215852236649271569251468773714424208521977615548771268520882870120900360322044218806712027729351845307690474985502587527753847200130592058098363641559341826790559426614919168"); + mnt6_final_exponent_last_chunk_abs_of_w0 = bigint_q("689871209842287392837045615510547309923794944"); + mnt6_final_exponent_last_chunk_is_w0_neg = true; + mnt6_final_exponent_last_chunk_w1 = bigint_q("1"); +} + +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_init.d b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_init.d new file mode 100644 index 0000000..95c58cc --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_init.d @@ -0,0 +1,19 @@ +src/algebra/curves/mnt/mnt6/mnt6_init.o: \ + src/algebra/curves/mnt/mnt6/mnt6_init.cpp \ + src/algebra/curves/mnt/mnt6/mnt6_init.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/mnt/mnt46_common.hpp src/algebra/fields/bigint.hpp \ + src/common/serialization.hpp src/common/serialization.tcc \ + src/common/utils.hpp src/common/utils.tcc src/algebra/fields/bigint.tcc \ + src/algebra/fields/fp.hpp src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc src/algebra/fields/fp3.hpp \ + src/algebra/fields/fp3.tcc src/algebra/fields/fp6_2over3.hpp \ + src/algebra/fields/fp2.hpp src/algebra/fields/fp2.tcc \ + src/algebra/fields/fp6_2over3.tcc \ + src/algebra/scalar_multiplication/wnaf.hpp \ + src/algebra/scalar_multiplication/wnaf.tcc \ + src/algebra/curves/mnt/mnt6/mnt6_g1.hpp \ + src/algebra/curves/curve_utils.hpp src/algebra/curves/curve_utils.tcc \ + src/algebra/curves/mnt/mnt6/mnt6_g2.hpp diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_init.hpp b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_init.hpp new file mode 100644 index 0000000..10cd9da --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_init.hpp @@ -0,0 +1,69 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for initializing MNT6. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT6_INIT_HPP_ +#define MNT6_INIT_HPP_ + +#include "algebra/curves/public_params.hpp" +#include "algebra/curves/mnt/mnt46_common.hpp" +#include "algebra/fields/fp.hpp" +#include "algebra/fields/fp3.hpp" +#include "algebra/fields/fp6_2over3.hpp" + +namespace libsnark { + +#define mnt6_modulus_r mnt46_modulus_B +#define mnt6_modulus_q mnt46_modulus_A + +const mp_size_t mnt6_r_bitcount = mnt46_B_bitcount; +const mp_size_t mnt6_q_bitcount = mnt46_A_bitcount; + +const mp_size_t mnt6_r_limbs = mnt46_B_limbs; +const mp_size_t mnt6_q_limbs = mnt46_A_limbs; + +extern bigint mnt6_modulus_r; +extern bigint mnt6_modulus_q; + +typedef Fp_model mnt6_Fr; +typedef Fp_model mnt6_Fq; +typedef Fp3_model mnt6_Fq3; +typedef Fp6_2over3_model mnt6_Fq6; +typedef mnt6_Fq6 mnt6_GT; + +// parameters for twisted short Weierstrass curve E'/Fq3 : y^2 = x^3 + (a * twist^2) * x + (b * twist^3) +extern mnt6_Fq3 mnt6_twist; +extern mnt6_Fq3 mnt6_twist_coeff_a; +extern mnt6_Fq3 mnt6_twist_coeff_b; +extern mnt6_Fq mnt6_twist_mul_by_a_c0; +extern mnt6_Fq mnt6_twist_mul_by_a_c1; +extern mnt6_Fq mnt6_twist_mul_by_a_c2; +extern mnt6_Fq mnt6_twist_mul_by_b_c0; +extern mnt6_Fq mnt6_twist_mul_by_b_c1; +extern mnt6_Fq mnt6_twist_mul_by_b_c2; +extern mnt6_Fq mnt6_twist_mul_by_q_X; +extern mnt6_Fq mnt6_twist_mul_by_q_Y; + +// parameters for pairing +extern bigint mnt6_ate_loop_count; +extern bool mnt6_ate_is_loop_count_neg; +extern bigint<6*mnt6_q_limbs> mnt6_final_exponent; +extern bigint mnt6_final_exponent_last_chunk_abs_of_w0; +extern bool mnt6_final_exponent_last_chunk_is_w0_neg; +extern bigint mnt6_final_exponent_last_chunk_w1; + +void init_mnt6_params(); + +class mnt6_G1; +class mnt6_G2; + +} // libsnark + +#endif // MNT6_INIT_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_pairing.cpp b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_pairing.cpp new file mode 100644 index 0000000..41fc2f5 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_pairing.cpp @@ -0,0 +1,753 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for pairing operations on MNT6. + + See mnt6_pairing.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include + +#include "algebra/curves/mnt/mnt6/mnt6_pairing.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_init.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_g1.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_g2.hpp" +#include "algebra/scalar_multiplication/wnaf.hpp" +#include "common/profiling.hpp" + +namespace libsnark { + +bool mnt6_ate_G1_precomp::operator==(const mnt6_ate_G1_precomp &other) const +{ + return (this->PX == other.PX && + this->PY == other.PY && + this->PX_twist == other.PX_twist && + this->PY_twist == other.PY_twist); +} + +std::ostream& operator<<(std::ostream &out, const mnt6_ate_G1_precomp &prec_P) +{ + out << prec_P.PX << OUTPUT_SEPARATOR << prec_P.PY << OUTPUT_SEPARATOR << prec_P.PX_twist << OUTPUT_SEPARATOR << prec_P.PY_twist; + + return out; +} + +std::istream& operator>>(std::istream &in, mnt6_ate_G1_precomp &prec_P) +{ + in >> prec_P.PX; + consume_OUTPUT_SEPARATOR(in); + in >> prec_P.PY; + consume_OUTPUT_SEPARATOR(in); + in >> prec_P.PX_twist; + consume_OUTPUT_SEPARATOR(in); + in >> prec_P.PY_twist; + + return in; +} + +bool mnt6_ate_dbl_coeffs::operator==(const mnt6_ate_dbl_coeffs &other) const +{ + return (this->c_H == other.c_H && + this->c_4C == other.c_4C && + this->c_J == other.c_J && + this->c_L == other.c_L); +} + +std::ostream& operator<<(std::ostream &out, const mnt6_ate_dbl_coeffs &dc) +{ + out << dc.c_H << OUTPUT_SEPARATOR << dc.c_4C << OUTPUT_SEPARATOR << dc.c_J << OUTPUT_SEPARATOR << dc.c_L; + return out; +} + +std::istream& operator>>(std::istream &in, mnt6_ate_dbl_coeffs &dc) +{ + in >> dc.c_H; + consume_OUTPUT_SEPARATOR(in); + in >> dc.c_4C; + consume_OUTPUT_SEPARATOR(in); + in >> dc.c_J; + consume_OUTPUT_SEPARATOR(in); + in >> dc.c_L; + + return in; +} + +bool mnt6_ate_add_coeffs::operator==(const mnt6_ate_add_coeffs &other) const +{ + return (this->c_L1 == other.c_L1 && + this->c_RZ == other.c_RZ); +} + +std::ostream& operator<<(std::ostream &out, const mnt6_ate_add_coeffs &ac) +{ + out << ac.c_L1 << OUTPUT_SEPARATOR << ac.c_RZ; + return out; +} + +std::istream& operator>>(std::istream &in, mnt6_ate_add_coeffs &ac) +{ + in >> ac.c_L1; + consume_OUTPUT_SEPARATOR(in); + in >> ac.c_RZ; + + return in; +} + + +bool mnt6_ate_G2_precomp::operator==(const mnt6_ate_G2_precomp &other) const +{ + return (this->QX == other.QX && + this->QY == other.QY && + this->QY2 == other.QY2 && + this->QX_over_twist == other.QX_over_twist && + this->QY_over_twist == other.QY_over_twist && + this->dbl_coeffs == other.dbl_coeffs && + this->add_coeffs == other.add_coeffs); +} + +std::ostream& operator<<(std::ostream& out, const mnt6_ate_G2_precomp &prec_Q) +{ + out << prec_Q.QX << OUTPUT_SEPARATOR + << prec_Q.QY << OUTPUT_SEPARATOR + << prec_Q.QY2 << OUTPUT_SEPARATOR + << prec_Q.QX_over_twist << OUTPUT_SEPARATOR + << prec_Q.QY_over_twist << "\n"; + out << prec_Q.dbl_coeffs.size() << "\n"; + for (const mnt6_ate_dbl_coeffs &dc : prec_Q.dbl_coeffs) + { + out << dc << OUTPUT_NEWLINE; + } + out << prec_Q.add_coeffs.size() << "\n"; + for (const mnt6_ate_add_coeffs &ac : prec_Q.add_coeffs) + { + out << ac << OUTPUT_NEWLINE; + } + + return out; +} + +std::istream& operator>>(std::istream& in, mnt6_ate_G2_precomp &prec_Q) +{ + in >> prec_Q.QX; + consume_OUTPUT_SEPARATOR(in); + in >> prec_Q.QY; + consume_OUTPUT_SEPARATOR(in); + in >> prec_Q.QY2; + consume_OUTPUT_SEPARATOR(in); + in >> prec_Q.QX_over_twist; + consume_OUTPUT_SEPARATOR(in); + in >> prec_Q.QY_over_twist; + consume_newline(in); + + prec_Q.dbl_coeffs.clear(); + size_t dbl_s; + in >> dbl_s; + consume_newline(in); + + prec_Q.dbl_coeffs.reserve(dbl_s); + + for (size_t i = 0; i < dbl_s; ++i) + { + mnt6_ate_dbl_coeffs dc; + in >> dc; + consume_OUTPUT_NEWLINE(in); + prec_Q.dbl_coeffs.emplace_back(dc); + } + + prec_Q.add_coeffs.clear(); + size_t add_s; + in >> add_s; + consume_newline(in); + + prec_Q.add_coeffs.reserve(add_s); + + for (size_t i = 0; i < add_s; ++i) + { + mnt6_ate_add_coeffs ac; + in >> ac; + consume_OUTPUT_NEWLINE(in); + prec_Q.add_coeffs.emplace_back(ac); + } + + return in; +} + +/* final exponentiations */ + +mnt6_Fq6 mnt6_final_exponentiation_last_chunk(const mnt6_Fq6 &elt, const mnt6_Fq6 &elt_inv) +{ + enter_block("Call to mnt6_final_exponentiation_last_chunk"); + const mnt6_Fq6 elt_q = elt.Frobenius_map(1); + mnt6_Fq6 w1_part = elt_q.cyclotomic_exp(mnt6_final_exponent_last_chunk_w1); + mnt6_Fq6 w0_part; + if (mnt6_final_exponent_last_chunk_is_w0_neg) + { + w0_part = elt_inv.cyclotomic_exp(mnt6_final_exponent_last_chunk_abs_of_w0); + } else { + w0_part = elt.cyclotomic_exp(mnt6_final_exponent_last_chunk_abs_of_w0); + } + mnt6_Fq6 result = w1_part * w0_part; + leave_block("Call to mnt6_final_exponentiation_last_chunk"); + + return result; +} + +mnt6_Fq6 mnt6_final_exponentiation_first_chunk(const mnt6_Fq6 &elt, const mnt6_Fq6 &elt_inv) +{ + enter_block("Call to mnt6_final_exponentiation_first_chunk"); + + /* (q^3-1)*(q+1) */ + + /* elt_q3 = elt^(q^3) */ + const mnt6_Fq6 elt_q3 = elt.Frobenius_map(3); + /* elt_q3_over_elt = elt^(q^3-1) */ + const mnt6_Fq6 elt_q3_over_elt = elt_q3 * elt_inv; + /* alpha = elt^((q^3-1) * q) */ + const mnt6_Fq6 alpha = elt_q3_over_elt.Frobenius_map(1); + /* beta = elt^((q^3-1)*(q+1) */ + const mnt6_Fq6 beta = alpha * elt_q3_over_elt; + leave_block("Call to mnt6_final_exponentiation_first_chunk"); + return beta; +} + +mnt6_GT mnt6_final_exponentiation(const mnt6_Fq6 &elt) +{ + enter_block("Call to mnt6_final_exponentiation"); + const mnt6_Fq6 elt_inv = elt.inverse(); + const mnt6_Fq6 elt_to_first_chunk = mnt6_final_exponentiation_first_chunk(elt, elt_inv); + const mnt6_Fq6 elt_inv_to_first_chunk = mnt6_final_exponentiation_first_chunk(elt_inv, elt); + mnt6_GT result = mnt6_final_exponentiation_last_chunk(elt_to_first_chunk, elt_inv_to_first_chunk); + leave_block("Call to mnt6_final_exponentiation"); + + return result; +} + +/* affine ate miller loop */ + +mnt6_affine_ate_G1_precomputation mnt6_affine_ate_precompute_G1(const mnt6_G1& P) +{ + enter_block("Call to mnt6_affine_ate_precompute_G1"); + + mnt6_G1 Pcopy = P; + Pcopy.to_affine_coordinates(); + + mnt6_affine_ate_G1_precomputation result; + result.PX = Pcopy.X(); + result.PY = Pcopy.Y(); + result.PY_twist_squared = Pcopy.Y() * mnt6_twist.squared(); + + leave_block("Call to mnt6_affine_ate_precompute_G1"); + return result; +} + +mnt6_affine_ate_G2_precomputation mnt6_affine_ate_precompute_G2(const mnt6_G2& Q) +{ + enter_block("Call to mnt6_affine_ate_precompute_G2"); + + mnt6_G2 Qcopy(Q); + Qcopy.to_affine_coordinates(); + + mnt6_affine_ate_G2_precomputation result; + result.QX = Qcopy.X(); + result.QY = Qcopy.Y(); + + mnt6_Fq3 RX = Qcopy.X(); + mnt6_Fq3 RY = Qcopy.Y(); + + const bigint &loop_count = mnt6_ate_loop_count; + bool found_nonzero = false; + + std::vector NAF = find_wnaf(1, loop_count); + for (long i = NAF.size() - 1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + mnt6_affine_ate_coeffs c; + c.old_RX = RX; + c.old_RY = RY; + mnt6_Fq3 old_RX_2 = c.old_RX.squared(); + c.gamma = (old_RX_2 + old_RX_2 + old_RX_2 + mnt6_twist_coeff_a) * (c.old_RY + c.old_RY).inverse(); + c.gamma_twist = c.gamma * mnt6_twist; + c.gamma_X = c.gamma * c.old_RX; + result.coeffs.push_back(c); + + RX = c.gamma.squared() - (c.old_RX+c.old_RX); + RY = c.gamma * (c.old_RX - RX) - c.old_RY; + + if (NAF[i] != 0) + { + mnt6_affine_ate_coeffs c; + c.old_RX = RX; + c.old_RY = RY; + if (NAF[i] > 0) + { + c.gamma = (c.old_RY - result.QY) * (c.old_RX - result.QX).inverse(); + } + else + { + c.gamma = (c.old_RY + result.QY) * (c.old_RX - result.QX).inverse(); + } + c.gamma_twist = c.gamma * mnt6_twist; + c.gamma_X = c.gamma * result.QX; + result.coeffs.push_back(c); + + RX = c.gamma.squared() - (c.old_RX+result.QX); + RY = c.gamma * (c.old_RX - RX) - c.old_RY; + } + } + + /* TODO: maybe handle neg + if (mnt6_ate_is_loop_count_neg) + { + mnt6_ate_add_coeffs ac; + mnt6_affine_ate_dbl_coeffs c; + c.old_RX = RX; + c.old_RY = -RY; + old_RX_2 = c.old_RY.squared(); + c.gamma = (old_RX_2 + old_RX_2 + old_RX_2 + mnt6_coeff_a) * (c.old_RY + c.old_RY).inverse(); + c.gamma_twist = c.gamma * mnt6_twist; + c.gamma_X = c.gamma * c.old_RX; + result.coeffs.push_back(c); + } + */ + + leave_block("Call to mnt6_affine_ate_precompute_G2"); + return result; +} + +mnt6_Fq6 mnt6_affine_ate_miller_loop(const mnt6_affine_ate_G1_precomputation &prec_P, + const mnt6_affine_ate_G2_precomputation &prec_Q) +{ + enter_block("Call to mnt6_affine_ate_miller_loop"); + + mnt6_Fq6 f = mnt6_Fq6::one(); + + const bigint &loop_count = mnt6_ate_loop_count; + bool found_nonzero = false; + size_t idx = 0; + + std::vector NAF = find_wnaf(1, loop_count); + for (long i = NAF.size() - 1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + mnt6_param_p (skipping leading zeros) in MSB to LSB + order */ + mnt6_affine_ate_coeffs c = prec_Q.coeffs[idx++]; + + mnt6_Fq6 g_RR_at_P = mnt6_Fq6(prec_P.PY_twist_squared, + - prec_P.PX * c.gamma_twist + c.gamma_X - c.old_RY); + f = f.squared().mul_by_2345(g_RR_at_P); + + if (NAF[i] != 0) + { + mnt6_affine_ate_coeffs c = prec_Q.coeffs[idx++]; + mnt6_Fq6 g_RQ_at_P; + if (NAF[i] > 0) + { + g_RQ_at_P = mnt6_Fq6(prec_P.PY_twist_squared, + - prec_P.PX * c.gamma_twist + c.gamma_X - prec_Q.QY); + } + else + { + g_RQ_at_P = mnt6_Fq6(prec_P.PY_twist_squared, + - prec_P.PX * c.gamma_twist + c.gamma_X + prec_Q.QY); + } + f = f.mul_by_2345(g_RQ_at_P); + } + + } + + /* TODO: maybe handle neg + if (mnt6_ate_is_loop_count_neg) + { + // TODO: + mnt6_affine_ate_coeffs ac = prec_Q.coeffs[idx++]; + mnt6_Fq6 g_RnegR_at_P = mnt6_Fq6(prec_P.PY_twist_squared, + - prec_P.PX * c.gamma_twist + c.gamma_X - c.old_RY); + f = (f * g_RnegR_at_P).inverse(); + } + */ + + leave_block("Call to mnt6_affine_ate_miller_loop"); + + return f; +} + +/* ate pairing */ + +struct extended_mnt6_G2_projective { + mnt6_Fq3 X; + mnt6_Fq3 Y; + mnt6_Fq3 Z; + mnt6_Fq3 T; + + void print() const + { + printf("extended mnt6_G2 projective X/Y/Z/T:\n"); + X.print(); + Y.print(); + Z.print(); + T.print(); + } + + void test_invariant() const + { + assert(T == Z.squared()); + } +}; + +void doubling_step_for_flipped_miller_loop(extended_mnt6_G2_projective ¤t, + mnt6_ate_dbl_coeffs &dc) +{ + const mnt6_Fq3 X = current.X, Y = current.Y, Z = current.Z, T = current.T; + + const mnt6_Fq3 A = T.squared(); // A = T1^2 + const mnt6_Fq3 B = X.squared(); // B = X1^2 + const mnt6_Fq3 C = Y.squared(); // C = Y1^2 + const mnt6_Fq3 D = C.squared(); // D = C^2 + const mnt6_Fq3 E = (X+C).squared() - B - D; // E = (X1+C)^2-B-D + const mnt6_Fq3 F = (B+B+B) + mnt6_twist_coeff_a * A; // F = 3*B + a *A + const mnt6_Fq3 G = F.squared(); // G = F^2 + + current.X = -(E+E+E+E) + G; // X3 = -4*E+G + current.Y = -mnt6_Fq("8")*D + F*(E+E-current.X); // Y3 = -8*D+F*(2*E-X3) + current.Z = (Y+Z).squared() - C - Z.squared(); // Z3 = (Y1+Z1)^2-C-Z1^2 + current.T = current.Z.squared(); // T3 = Z3^2 + + dc.c_H = (current.Z + T).squared() - current.T - A; // H = (Z3+T1)^2-T3-A + dc.c_4C = C+C+C+C; // fourC = 4*C + dc.c_J = (F+T).squared() - G - A; // J = (F+T1)^2-G-A + dc.c_L = (F+X).squared() - G - B; // L = (F+X1)^2-G-B + +#ifdef DEBUG + current.test_invariant(); +#endif +} + +void mixed_addition_step_for_flipped_miller_loop(const mnt6_Fq3 base_X, const mnt6_Fq3 base_Y, const mnt6_Fq3 base_Y_squared, + extended_mnt6_G2_projective ¤t, + mnt6_ate_add_coeffs &ac) +{ + const mnt6_Fq3 X1 = current.X, Y1 = current.Y, Z1 = current.Z, T1 = current.T; + const mnt6_Fq3 &x2 = base_X, &y2 = base_Y, &y2_squared = base_Y_squared; + + const mnt6_Fq3 B = x2 * T1; // B = x2 * T1 + const mnt6_Fq3 D = ((y2 + Z1).squared() - y2_squared - T1) * T1; // D = ((y2 + Z1)^2 - y2squared - T1) * T1 + const mnt6_Fq3 H = B - X1; // H = B - X1 + const mnt6_Fq3 I = H.squared(); // I = H^2 + const mnt6_Fq3 E = I + I + I + I; // E = 4*I + const mnt6_Fq3 J = H * E; // J = H * E + const mnt6_Fq3 V = X1 * E; // V = X1 * E + const mnt6_Fq3 L1 = D - (Y1 + Y1); // L1 = D - 2 * Y1 + + current.X = L1.squared() - J - (V+V); // X3 = L1^2 - J - 2*V + current.Y = L1 * (V-current.X) - (Y1+Y1) * J; // Y3 = L1 * (V-X3) - 2*Y1 * J + current.Z = (Z1+H).squared() - T1 - I; // Z3 = (Z1 + H)^2 - T1 - I + current.T = current.Z.squared(); // T3 = Z3^2 + + ac.c_L1 = L1; + ac.c_RZ = current.Z; +#ifdef DEBUG + current.test_invariant(); +#endif +} + +mnt6_ate_G1_precomp mnt6_ate_precompute_G1(const mnt6_G1& P) +{ + enter_block("Call to mnt6_ate_precompute_G1"); + + mnt6_G1 Pcopy = P; + Pcopy.to_affine_coordinates(); + + mnt6_ate_G1_precomp result; + result.PX = Pcopy.X(); + result.PY = Pcopy.Y(); + result.PX_twist = Pcopy.X() * mnt6_twist; + result.PY_twist = Pcopy.Y() * mnt6_twist; + + leave_block("Call to mnt6_ate_precompute_G1"); + return result; +} + +mnt6_ate_G2_precomp mnt6_ate_precompute_G2(const mnt6_G2& Q) +{ + enter_block("Call to mnt6_ate_precompute_G2"); + + mnt6_G2 Qcopy(Q); + Qcopy.to_affine_coordinates(); + + mnt6_Fq3 mnt6_twist_inv = mnt6_twist.inverse(); // could add to global params if needed + + mnt6_ate_G2_precomp result; + result.QX = Qcopy.X(); + result.QY = Qcopy.Y(); + result.QY2 = Qcopy.Y().squared(); + result.QX_over_twist = Qcopy.X() * mnt6_twist_inv; + result.QY_over_twist = Qcopy.Y() * mnt6_twist_inv; + + extended_mnt6_G2_projective R; + R.X = Qcopy.X(); + R.Y = Qcopy.Y(); + R.Z = mnt6_Fq3::one(); + R.T = mnt6_Fq3::one(); + + const bigint &loop_count = mnt6_ate_loop_count; + bool found_one = false; + for (long i = loop_count.max_bits() - 1; i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + mnt6_ate_dbl_coeffs dc; + doubling_step_for_flipped_miller_loop(R, dc); + result.dbl_coeffs.push_back(dc); + + if (bit) + { + mnt6_ate_add_coeffs ac; + mixed_addition_step_for_flipped_miller_loop(result.QX, result.QY, result.QY2, R, ac); + result.add_coeffs.push_back(ac); + } + } + + if (mnt6_ate_is_loop_count_neg) + { + mnt6_Fq3 RZ_inv = R.Z.inverse(); + mnt6_Fq3 RZ2_inv = RZ_inv.squared(); + mnt6_Fq3 RZ3_inv = RZ2_inv * RZ_inv; + mnt6_Fq3 minus_R_affine_X = R.X * RZ2_inv; + mnt6_Fq3 minus_R_affine_Y = - R.Y * RZ3_inv; + mnt6_Fq3 minus_R_affine_Y2 = minus_R_affine_Y.squared(); + mnt6_ate_add_coeffs ac; + mixed_addition_step_for_flipped_miller_loop(minus_R_affine_X, minus_R_affine_Y, minus_R_affine_Y2, R, ac); + result.add_coeffs.push_back(ac); + } + + leave_block("Call to mnt6_ate_precompute_G2"); + return result; +} + +mnt6_Fq6 mnt6_ate_miller_loop(const mnt6_ate_G1_precomp &prec_P, + const mnt6_ate_G2_precomp &prec_Q) +{ + enter_block("Call to mnt6_ate_miller_loop"); + + mnt6_Fq3 L1_coeff = mnt6_Fq3(prec_P.PX, mnt6_Fq::zero(), mnt6_Fq::zero()) - prec_Q.QX_over_twist; + + mnt6_Fq6 f = mnt6_Fq6::one(); + + bool found_one = false; + size_t dbl_idx = 0; + size_t add_idx = 0; + + const bigint &loop_count = mnt6_ate_loop_count; + + for (long i = loop_count.max_bits() - 1; i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + mnt6_param_p (skipping leading zeros) in MSB to LSB + order */ + mnt6_ate_dbl_coeffs dc = prec_Q.dbl_coeffs[dbl_idx++]; + + mnt6_Fq6 g_RR_at_P = mnt6_Fq6(- dc.c_4C - dc.c_J * prec_P.PX_twist + dc.c_L, + dc.c_H * prec_P.PY_twist); + f = f.squared() * g_RR_at_P; + + if (bit) + { + mnt6_ate_add_coeffs ac = prec_Q.add_coeffs[add_idx++]; + mnt6_Fq6 g_RQ_at_P = mnt6_Fq6(ac.c_RZ * prec_P.PY_twist, + -(prec_Q.QY_over_twist * ac.c_RZ + L1_coeff * ac.c_L1)); + f = f * g_RQ_at_P; + } + + } + + if (mnt6_ate_is_loop_count_neg) + { + mnt6_ate_add_coeffs ac = prec_Q.add_coeffs[add_idx++]; + mnt6_Fq6 g_RnegR_at_P = mnt6_Fq6(ac.c_RZ * prec_P.PY_twist, + -(prec_Q.QY_over_twist * ac.c_RZ + L1_coeff * ac.c_L1)); + f = (f * g_RnegR_at_P).inverse(); + } + + leave_block("Call to mnt6_ate_miller_loop"); + + return f; +} + +mnt6_Fq6 mnt6_ate_double_miller_loop(const mnt6_ate_G1_precomp &prec_P1, + const mnt6_ate_G2_precomp &prec_Q1, + const mnt6_ate_G1_precomp &prec_P2, + const mnt6_ate_G2_precomp &prec_Q2) +{ + enter_block("Call to mnt6_ate_double_miller_loop"); + + mnt6_Fq3 L1_coeff1 = mnt6_Fq3(prec_P1.PX, mnt6_Fq::zero(), mnt6_Fq::zero()) - prec_Q1.QX_over_twist; + mnt6_Fq3 L1_coeff2 = mnt6_Fq3(prec_P2.PX, mnt6_Fq::zero(), mnt6_Fq::zero()) - prec_Q2.QX_over_twist; + + mnt6_Fq6 f = mnt6_Fq6::one(); + + bool found_one = false; + size_t dbl_idx = 0; + size_t add_idx = 0; + + const bigint &loop_count = mnt6_ate_loop_count; + + for (long i = loop_count.max_bits() - 1; i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + mnt6_param_p (skipping leading zeros) in MSB to LSB + order */ + mnt6_ate_dbl_coeffs dc1 = prec_Q1.dbl_coeffs[dbl_idx]; + mnt6_ate_dbl_coeffs dc2 = prec_Q2.dbl_coeffs[dbl_idx]; + ++dbl_idx; + + mnt6_Fq6 g_RR_at_P1 = mnt6_Fq6(- dc1.c_4C - dc1.c_J * prec_P1.PX_twist + dc1.c_L, + dc1.c_H * prec_P1.PY_twist); + + mnt6_Fq6 g_RR_at_P2 = mnt6_Fq6(- dc2.c_4C - dc2.c_J * prec_P2.PX_twist + dc2.c_L, + dc2.c_H * prec_P2.PY_twist); + + f = f.squared() * g_RR_at_P1 * g_RR_at_P2; + + if (bit) + { + mnt6_ate_add_coeffs ac1 = prec_Q1.add_coeffs[add_idx]; + mnt6_ate_add_coeffs ac2 = prec_Q2.add_coeffs[add_idx]; + ++add_idx; + + mnt6_Fq6 g_RQ_at_P1 = mnt6_Fq6(ac1.c_RZ * prec_P1.PY_twist, + -(prec_Q1.QY_over_twist * ac1.c_RZ + L1_coeff1 * ac1.c_L1)); + mnt6_Fq6 g_RQ_at_P2 = mnt6_Fq6(ac2.c_RZ * prec_P2.PY_twist, + -(prec_Q2.QY_over_twist * ac2.c_RZ + L1_coeff2 * ac2.c_L1)); + + f = f * g_RQ_at_P1 * g_RQ_at_P2; + } + } + + if (mnt6_ate_is_loop_count_neg) + { + mnt6_ate_add_coeffs ac1 = prec_Q1.add_coeffs[add_idx]; + mnt6_ate_add_coeffs ac2 = prec_Q2.add_coeffs[add_idx]; + ++add_idx; + mnt6_Fq6 g_RnegR_at_P1 = mnt6_Fq6(ac1.c_RZ * prec_P1.PY_twist, + -(prec_Q1.QY_over_twist * ac1.c_RZ + L1_coeff1 * ac1.c_L1)); + mnt6_Fq6 g_RnegR_at_P2 = mnt6_Fq6(ac2.c_RZ * prec_P2.PY_twist, + -(prec_Q2.QY_over_twist * ac2.c_RZ + L1_coeff2 * ac2.c_L1)); + + f = (f * g_RnegR_at_P1 * g_RnegR_at_P2).inverse(); + } + + leave_block("Call to mnt6_ate_double_miller_loop"); + + return f; +} + +mnt6_Fq6 mnt6_ate_pairing(const mnt6_G1& P, const mnt6_G2 &Q) +{ + enter_block("Call to mnt6_ate_pairing"); + mnt6_ate_G1_precomp prec_P = mnt6_ate_precompute_G1(P); + mnt6_ate_G2_precomp prec_Q = mnt6_ate_precompute_G2(Q); + mnt6_Fq6 result = mnt6_ate_miller_loop(prec_P, prec_Q); + leave_block("Call to mnt6_ate_pairing"); + return result; +} + +mnt6_GT mnt6_ate_reduced_pairing(const mnt6_G1 &P, const mnt6_G2 &Q) +{ + enter_block("Call to mnt6_ate_reduced_pairing"); + const mnt6_Fq6 f = mnt6_ate_pairing(P, Q); + const mnt6_GT result = mnt6_final_exponentiation(f); + leave_block("Call to mnt6_ate_reduced_pairing"); + return result; +} + +mnt6_G1_precomp mnt6_precompute_G1(const mnt6_G1& P) +{ + return mnt6_ate_precompute_G1(P); +} + +mnt6_G2_precomp mnt6_precompute_G2(const mnt6_G2& Q) +{ + return mnt6_ate_precompute_G2(Q); +} + +mnt6_Fq6 mnt6_miller_loop(const mnt6_G1_precomp &prec_P, + const mnt6_G2_precomp &prec_Q) +{ + return mnt6_ate_miller_loop(prec_P, prec_Q); +} + +mnt6_Fq6 mnt6_double_miller_loop(const mnt6_G1_precomp &prec_P1, + const mnt6_G2_precomp &prec_Q1, + const mnt6_G1_precomp &prec_P2, + const mnt6_G2_precomp &prec_Q2) +{ + return mnt6_ate_double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); +} + +mnt6_Fq6 mnt6_pairing(const mnt6_G1& P, + const mnt6_G2 &Q) +{ + return mnt6_ate_pairing(P, Q); +} + +mnt6_GT mnt6_reduced_pairing(const mnt6_G1 &P, + const mnt6_G2 &Q) +{ + return mnt6_ate_reduced_pairing(P, Q); +} + +mnt6_GT mnt6_affine_reduced_pairing(const mnt6_G1 &P, + const mnt6_G2 &Q) +{ + const mnt6_affine_ate_G1_precomputation prec_P = mnt6_affine_ate_precompute_G1(P); + const mnt6_affine_ate_G2_precomputation prec_Q = mnt6_affine_ate_precompute_G2(Q); + const mnt6_Fq6 f = mnt6_affine_ate_miller_loop(prec_P, prec_Q); + const mnt6_GT result = mnt6_final_exponentiation(f); + return result; +} + +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_pairing.d b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_pairing.d new file mode 100644 index 0000000..8b10f80 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_pairing.d @@ -0,0 +1,20 @@ +src/algebra/curves/mnt/mnt6/mnt6_pairing.o: \ + src/algebra/curves/mnt/mnt6/mnt6_pairing.cpp \ + src/algebra/curves/mnt/mnt6/mnt6_pairing.hpp \ + src/algebra/curves/mnt/mnt6/mnt6_init.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/mnt/mnt46_common.hpp src/algebra/fields/bigint.hpp \ + src/common/serialization.hpp src/common/serialization.tcc \ + src/common/utils.hpp src/common/utils.tcc src/algebra/fields/bigint.tcc \ + src/algebra/fields/fp.hpp src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc src/algebra/fields/fp3.hpp \ + src/algebra/fields/fp3.tcc src/algebra/fields/fp6_2over3.hpp \ + src/algebra/fields/fp2.hpp src/algebra/fields/fp2.tcc \ + src/algebra/fields/fp6_2over3.tcc \ + src/algebra/scalar_multiplication/wnaf.hpp \ + src/algebra/scalar_multiplication/wnaf.tcc \ + src/algebra/curves/mnt/mnt6/mnt6_g1.hpp \ + src/algebra/curves/curve_utils.hpp src/algebra/curves/curve_utils.tcc \ + src/algebra/curves/mnt/mnt6/mnt6_g2.hpp src/common/profiling.hpp diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_pairing.hpp b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_pairing.hpp new file mode 100644 index 0000000..f5c2117 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_pairing.hpp @@ -0,0 +1,148 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for pairing operations on MNT6. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT6_PAIRING_HPP_ +#define MNT6_PAIRING_HPP_ + +#include + +#include "algebra/curves/mnt/mnt6/mnt6_init.hpp" + +namespace libsnark { + +/* final exponentiation */ + +mnt6_Fq6 mnt6_final_exponentiation_last_chunk(const mnt6_Fq6 &elt, + const mnt6_Fq6 &elt_inv); +mnt6_Fq6 mnt6_final_exponentiation_first_chunk(const mnt6_Fq6 &elt, + const mnt6_Fq6 &elt_inv); +mnt6_GT mnt6_final_exponentiation(const mnt6_Fq6 &elt); + +/* affine ate miller loop */ + +struct mnt6_affine_ate_G1_precomputation { + mnt6_Fq PX; + mnt6_Fq PY; + mnt6_Fq3 PY_twist_squared; +}; + +struct mnt6_affine_ate_coeffs { + // TODO: trim (not all of them are needed) + mnt6_Fq3 old_RX; + mnt6_Fq3 old_RY; + mnt6_Fq3 gamma; + mnt6_Fq3 gamma_twist; + mnt6_Fq3 gamma_X; +}; + +struct mnt6_affine_ate_G2_precomputation { + mnt6_Fq3 QX; + mnt6_Fq3 QY; + std::vector coeffs; +}; + +mnt6_affine_ate_G1_precomputation mnt6_affine_ate_precompute_G1(const mnt6_G1& P); +mnt6_affine_ate_G2_precomputation mnt6_affine_ate_precompute_G2(const mnt6_G2& Q); + +mnt6_Fq6 mnt6_affine_ate_miller_loop(const mnt6_affine_ate_G1_precomputation &prec_P, + const mnt6_affine_ate_G2_precomputation &prec_Q); + +/* ate pairing */ + +struct mnt6_ate_G1_precomp { + mnt6_Fq PX; + mnt6_Fq PY; + mnt6_Fq3 PX_twist; + mnt6_Fq3 PY_twist; + + bool operator==(const mnt6_ate_G1_precomp &other) const; + friend std::ostream& operator<<(std::ostream &out, const mnt6_ate_G1_precomp &prec_P); + friend std::istream& operator>>(std::istream &in, mnt6_ate_G1_precomp &prec_P); +}; + +struct mnt6_ate_dbl_coeffs { + mnt6_Fq3 c_H; + mnt6_Fq3 c_4C; + mnt6_Fq3 c_J; + mnt6_Fq3 c_L; + + bool operator==(const mnt6_ate_dbl_coeffs &other) const; + friend std::ostream& operator<<(std::ostream &out, const mnt6_ate_dbl_coeffs &dc); + friend std::istream& operator>>(std::istream &in, mnt6_ate_dbl_coeffs &dc); +}; + +struct mnt6_ate_add_coeffs { + mnt6_Fq3 c_L1; + mnt6_Fq3 c_RZ; + + bool operator==(const mnt6_ate_add_coeffs &other) const; + friend std::ostream& operator<<(std::ostream &out, const mnt6_ate_add_coeffs &dc); + friend std::istream& operator>>(std::istream &in, mnt6_ate_add_coeffs &dc); +}; + +struct mnt6_ate_G2_precomp { + mnt6_Fq3 QX; + mnt6_Fq3 QY; + mnt6_Fq3 QY2; + mnt6_Fq3 QX_over_twist; + mnt6_Fq3 QY_over_twist; + std::vector dbl_coeffs; + std::vector add_coeffs; + + bool operator==(const mnt6_ate_G2_precomp &other) const; + friend std::ostream& operator<<(std::ostream &out, const mnt6_ate_G2_precomp &prec_Q); + friend std::istream& operator>>(std::istream &in, mnt6_ate_G2_precomp &prec_Q); +}; + +mnt6_ate_G1_precomp mnt6_ate_precompute_G1(const mnt6_G1& P); +mnt6_ate_G2_precomp mnt6_ate_precompute_G2(const mnt6_G2& Q); + +mnt6_Fq6 mnt6_ate_miller_loop(const mnt6_ate_G1_precomp &prec_P, + const mnt6_ate_G2_precomp &prec_Q); +mnt6_Fq6 mnt6_ate_double_miller_loop(const mnt6_ate_G1_precomp &prec_P1, + const mnt6_ate_G2_precomp &prec_Q1, + const mnt6_ate_G1_precomp &prec_P2, + const mnt6_ate_G2_precomp &prec_Q2); + +mnt6_Fq6 mnt6_ate_pairing(const mnt6_G1& P, + const mnt6_G2 &Q); +mnt6_GT mnt6_ate_reduced_pairing(const mnt6_G1 &P, + const mnt6_G2 &Q); + +/* choice of pairing */ + +typedef mnt6_ate_G1_precomp mnt6_G1_precomp; +typedef mnt6_ate_G2_precomp mnt6_G2_precomp; + +mnt6_G1_precomp mnt6_precompute_G1(const mnt6_G1& P); + +mnt6_G2_precomp mnt6_precompute_G2(const mnt6_G2& Q); + +mnt6_Fq6 mnt6_miller_loop(const mnt6_G1_precomp &prec_P, + const mnt6_G2_precomp &prec_Q); + +mnt6_Fq6 mnt6_double_miller_loop(const mnt6_G1_precomp &prec_P1, + const mnt6_G2_precomp &prec_Q1, + const mnt6_G1_precomp &prec_P2, + const mnt6_G2_precomp &prec_Q2); + +mnt6_Fq6 mnt6_pairing(const mnt6_G1& P, + const mnt6_G2 &Q); + +mnt6_GT mnt6_reduced_pairing(const mnt6_G1 &P, + const mnt6_G2 &Q); + +mnt6_GT mnt6_affine_reduced_pairing(const mnt6_G1 &P, + const mnt6_G2 &Q); + +} // libsnark + +#endif // MNT6_PAIRING_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_pp.cpp b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_pp.cpp new file mode 100644 index 0000000..9983d50 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_pp.cpp @@ -0,0 +1,106 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for public parameters of MNT6. + + See mnt6_pp.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" + +namespace libsnark { + +void mnt6_pp::init_public_params() +{ + init_mnt6_params(); +} + +mnt6_GT mnt6_pp::final_exponentiation(const mnt6_Fq6 &elt) +{ + return mnt6_final_exponentiation(elt); +} + +mnt6_G1_precomp mnt6_pp::precompute_G1(const mnt6_G1 &P) +{ + return mnt6_precompute_G1(P); +} + +mnt6_G2_precomp mnt6_pp::precompute_G2(const mnt6_G2 &Q) +{ + return mnt6_precompute_G2(Q); +} + + +mnt6_Fq6 mnt6_pp::miller_loop(const mnt6_G1_precomp &prec_P, + const mnt6_G2_precomp &prec_Q) +{ + return mnt6_miller_loop(prec_P, prec_Q); +} + +mnt6_affine_ate_G1_precomputation mnt6_pp::affine_ate_precompute_G1(const mnt6_G1 &P) +{ + return mnt6_affine_ate_precompute_G1(P); +} + +mnt6_affine_ate_G2_precomputation mnt6_pp::affine_ate_precompute_G2(const mnt6_G2 &Q) +{ + return mnt6_affine_ate_precompute_G2(Q); +} + +mnt6_Fq6 mnt6_pp::affine_ate_miller_loop(const mnt6_affine_ate_G1_precomputation &prec_P, + const mnt6_affine_ate_G2_precomputation &prec_Q) +{ + return mnt6_affine_ate_miller_loop(prec_P, prec_Q); +} + +mnt6_Fq6 mnt6_pp::double_miller_loop(const mnt6_G1_precomp &prec_P1, + const mnt6_G2_precomp &prec_Q1, + const mnt6_G1_precomp &prec_P2, + const mnt6_G2_precomp &prec_Q2) +{ + return mnt6_double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); +} + +mnt6_Fq6 mnt6_pp::affine_ate_e_over_e_miller_loop(const mnt6_affine_ate_G1_precomputation &prec_P1, + const mnt6_affine_ate_G2_precomputation &prec_Q1, + const mnt6_affine_ate_G1_precomputation &prec_P2, + const mnt6_affine_ate_G2_precomputation &prec_Q2) +{ + return mnt6_affine_ate_miller_loop(prec_P1, prec_Q1) * mnt6_affine_ate_miller_loop(prec_P2, prec_Q2).unitary_inverse(); +} + +mnt6_Fq6 mnt6_pp::affine_ate_e_times_e_over_e_miller_loop(const mnt6_affine_ate_G1_precomputation &prec_P1, + const mnt6_affine_ate_G2_precomputation &prec_Q1, + const mnt6_affine_ate_G1_precomputation &prec_P2, + const mnt6_affine_ate_G2_precomputation &prec_Q2, + const mnt6_affine_ate_G1_precomputation &prec_P3, + const mnt6_affine_ate_G2_precomputation &prec_Q3) +{ + return ((mnt6_affine_ate_miller_loop(prec_P1, prec_Q1) * mnt6_affine_ate_miller_loop(prec_P2, prec_Q2)) * + mnt6_affine_ate_miller_loop(prec_P3, prec_Q3).unitary_inverse()); +} + +mnt6_Fq6 mnt6_pp::pairing(const mnt6_G1 &P, + const mnt6_G2 &Q) +{ + return mnt6_pairing(P, Q); +} + +mnt6_Fq6 mnt6_pp::reduced_pairing(const mnt6_G1 &P, + const mnt6_G2 &Q) +{ + return mnt6_reduced_pairing(P, Q); +} + +mnt6_Fq6 mnt6_pp::affine_reduced_pairing(const mnt6_G1 &P, + const mnt6_G2 &Q) +{ + return mnt6_affine_reduced_pairing(P, Q); +} + +} // libsnark diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_pp.d b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_pp.d new file mode 100644 index 0000000..ae424a5 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_pp.d @@ -0,0 +1,21 @@ +src/algebra/curves/mnt/mnt6/mnt6_pp.o: \ + src/algebra/curves/mnt/mnt6/mnt6_pp.cpp \ + src/algebra/curves/mnt/mnt6/mnt6_pp.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/mnt/mnt6/mnt6_init.hpp \ + src/algebra/curves/mnt/mnt46_common.hpp src/algebra/fields/bigint.hpp \ + src/common/serialization.hpp src/common/serialization.tcc \ + src/common/utils.hpp src/common/utils.tcc src/algebra/fields/bigint.tcc \ + src/algebra/fields/fp.hpp src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc src/algebra/fields/fp3.hpp \ + src/algebra/fields/fp3.tcc src/algebra/fields/fp6_2over3.hpp \ + src/algebra/fields/fp2.hpp src/algebra/fields/fp2.tcc \ + src/algebra/fields/fp6_2over3.tcc \ + src/algebra/scalar_multiplication/wnaf.hpp \ + src/algebra/scalar_multiplication/wnaf.tcc \ + src/algebra/curves/mnt/mnt6/mnt6_g1.hpp \ + src/algebra/curves/curve_utils.hpp src/algebra/curves/curve_utils.tcc \ + src/algebra/curves/mnt/mnt6/mnt6_g2.hpp \ + src/algebra/curves/mnt/mnt6/mnt6_pairing.hpp diff --git a/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_pp.hpp b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_pp.hpp new file mode 100644 index 0000000..bbe05a4 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/mnt/mnt6/mnt6_pp.hpp @@ -0,0 +1,75 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for public parameters of MNT6. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT6_PP_HPP_ +#define MNT6_PP_HPP_ + +#include "algebra/curves/public_params.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_init.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_g1.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_g2.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_pairing.hpp" + +namespace libsnark { + +class mnt6_pp { +public: + typedef mnt6_Fr Fp_type; + typedef mnt6_G1 G1_type; + typedef mnt6_G2 G2_type; + typedef mnt6_affine_ate_G1_precomputation affine_ate_G1_precomp_type; + typedef mnt6_affine_ate_G2_precomputation affine_ate_G2_precomp_type; + typedef mnt6_G1_precomp G1_precomp_type; + typedef mnt6_G2_precomp G2_precomp_type; + typedef mnt6_Fq Fq_type; + typedef mnt6_Fq3 Fqe_type; + typedef mnt6_Fq6 Fqk_type; + typedef mnt6_GT GT_type; + + static const bool has_affine_pairing = true; + + static void init_public_params(); + static mnt6_GT final_exponentiation(const mnt6_Fq6 &elt); + static mnt6_G1_precomp precompute_G1(const mnt6_G1 &P); + static mnt6_G2_precomp precompute_G2(const mnt6_G2 &Q); + static mnt6_Fq6 miller_loop(const mnt6_G1_precomp &prec_P, + const mnt6_G2_precomp &prec_Q); + static mnt6_affine_ate_G1_precomputation affine_ate_precompute_G1(const mnt6_G1 &P); + static mnt6_affine_ate_G2_precomputation affine_ate_precompute_G2(const mnt6_G2 &Q); + static mnt6_Fq6 affine_ate_miller_loop(const mnt6_affine_ate_G1_precomputation &prec_P, + const mnt6_affine_ate_G2_precomputation &prec_Q); + static mnt6_Fq6 affine_ate_e_over_e_miller_loop(const mnt6_affine_ate_G1_precomputation &prec_P1, + const mnt6_affine_ate_G2_precomputation &prec_Q1, + const mnt6_affine_ate_G1_precomputation &prec_P2, + const mnt6_affine_ate_G2_precomputation &prec_Q2); + static mnt6_Fq6 affine_ate_e_times_e_over_e_miller_loop(const mnt6_affine_ate_G1_precomputation &prec_P1, + const mnt6_affine_ate_G2_precomputation &prec_Q1, + const mnt6_affine_ate_G1_precomputation &prec_P2, + const mnt6_affine_ate_G2_precomputation &prec_Q2, + const mnt6_affine_ate_G1_precomputation &prec_P3, + const mnt6_affine_ate_G2_precomputation &prec_Q3); + static mnt6_Fq6 double_miller_loop(const mnt6_G1_precomp &prec_P1, + const mnt6_G2_precomp &prec_Q1, + const mnt6_G1_precomp &prec_P2, + const mnt6_G2_precomp &prec_Q2); + + /* the following are used in test files */ + static mnt6_Fq6 pairing(const mnt6_G1 &P, + const mnt6_G2 &Q); + static mnt6_Fq6 reduced_pairing(const mnt6_G1 &P, + const mnt6_G2 &Q); + static mnt6_Fq6 affine_reduced_pairing(const mnt6_G1 &P, + const mnt6_G2 &Q); +}; + +} // libsnark + +#endif // MNT6_PP_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/public_params.hpp b/privacy/zsl/zsl/algebra/curves/public_params.hpp new file mode 100644 index 0000000..07e0475 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/public_params.hpp @@ -0,0 +1,103 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PUBLIC_PARAMS_HPP_ +#define PUBLIC_PARAMS_HPP_ +#include + +namespace libsnark { + +/* + for every curve the user should define corresponding + public_params with the following typedefs: + + Fp_type + G1_type + G2_type + G1_precomp_type + G2_precomp_type + affine_ate_G1_precomp_type + affine_ate_G2_precomp_type + Fq_type + Fqe_type + Fqk_type + GT_type + + one should also define the following static methods: + + void init_public_params(); + + GT final_exponentiation(const Fqk &elt); + + G1_precomp precompute_G1(const G1 &P); + G2_precomp precompute_G2(const G2 &Q); + + Fqk miller_loop(const G1_precomp &prec_P, + const G2_precomp &prec_Q); + + affine_ate_G1_precomp affine_ate_precompute_G1(const G1 &P); + affine_ate_G2_precomp affine_ate_precompute_G2(const G2 &Q); + + + Fqk affine_ate_miller_loop(const affine_ate_G1_precomp &prec_P, + const affine_ate_G2_precomp &prec_Q); + Fqk affine_ate_e_over_e_miller_loop(const affine_ate_G1_precomp &prec_P1, + const affine_ate_G2_precomp &prec_Q1, + const affine_ate_G1_precomp &prec_P2, + const affine_ate_G2_precomp &prec_Q2); + Fqk affine_ate_e_times_e_over_e_miller_loop(const affine_ate_G1_precomp &prec_P1, + const affine_ate_G2_precomp &prec_Q1, + const affine_ate_G1_precomp &prec_P2, + const affine_ate_G2_precomp &prec_Q2, + const affine_ate_G1_precomp &prec_P3, + const affine_ate_G2_precomp &prec_Q3); + Fqk double_miller_loop(const G1_precomp &prec_P1, + const G2_precomp &prec_Q1, + const G1_precomp &prec_P2, + const G2_precomp &prec_Q2); + + Fqk pairing(const G1 &P, + const G2 &Q); + GT reduced_pairing(const G1 &P, + const G2 &Q); + GT affine_reduced_pairing(const G1 &P, + const G2 &Q); +*/ + +template +using Fr = typename EC_ppT::Fp_type; +template +using G1 = typename EC_ppT::G1_type; +template +using G2 = typename EC_ppT::G2_type; +template +using G1_precomp = typename EC_ppT::G1_precomp_type; +template +using G2_precomp = typename EC_ppT::G2_precomp_type; +template +using affine_ate_G1_precomp = typename EC_ppT::affine_ate_G1_precomp_type; +template +using affine_ate_G2_precomp = typename EC_ppT::affine_ate_G2_precomp_type; +template +using Fq = typename EC_ppT::Fq_type; +template +using Fqe = typename EC_ppT::Fqe_type; +template +using Fqk = typename EC_ppT::Fqk_type; +template +using GT = typename EC_ppT::GT_type; + +template +using Fr_vector = std::vector >; +template +using G1_vector = std::vector >; +template +using G2_vector = std::vector >; + +} // libsnark + +#endif // PUBLIC_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/algebra/curves/tests/test_bilinearity.cpp b/privacy/zsl/zsl/algebra/curves/tests/test_bilinearity.cpp new file mode 100644 index 0000000..2957452 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/tests/test_bilinearity.cpp @@ -0,0 +1,136 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include "common/profiling.hpp" +#include "algebra/curves/edwards/edwards_pp.hpp" +#ifdef CURVE_BN128 +#include "algebra/curves/bn128/bn128_pp.hpp" +#endif +#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" + +using namespace libsnark; + +template +void pairing_test() +{ + GT GT_one = GT::one(); + + printf("Running bilinearity tests:\n"); + G1 P = (Fr::random_element()) * G1::one(); + //G1 P = Fr("2") * G1::one(); + G2 Q = (Fr::random_element()) * G2::one(); + //G2 Q = Fr("3") * G2::one(); + + printf("P:\n"); + P.print(); + P.print_coordinates(); + printf("Q:\n"); + Q.print(); + Q.print_coordinates(); + printf("\n\n"); + + Fr s = Fr::random_element(); + //Fr s = Fr("2"); + G1 sP = s * P; + G2 sQ = s * Q; + + printf("Pairing bilinearity tests (three must match):\n"); + GT ans1 = ppT::reduced_pairing(sP, Q); + GT ans2 = ppT::reduced_pairing(P, sQ); + GT ans3 = ppT::reduced_pairing(P, Q)^s; + ans1.print(); + ans2.print(); + ans3.print(); + assert(ans1 == ans2); + assert(ans2 == ans3); + + assert(ans1 != GT_one); + assert((ans1^Fr::field_char()) == GT_one); + printf("\n\n"); +} + +template +void double_miller_loop_test() +{ + const G1 P1 = (Fr::random_element()) * G1::one(); + const G1 P2 = (Fr::random_element()) * G1::one(); + const G2 Q1 = (Fr::random_element()) * G2::one(); + const G2 Q2 = (Fr::random_element()) * G2::one(); + + const G1_precomp prec_P1 = ppT::precompute_G1(P1); + const G1_precomp prec_P2 = ppT::precompute_G1(P2); + const G2_precomp prec_Q1 = ppT::precompute_G2(Q1); + const G2_precomp prec_Q2 = ppT::precompute_G2(Q2); + + const Fqk ans_1 = ppT::miller_loop(prec_P1, prec_Q1); + const Fqk ans_2 = ppT::miller_loop(prec_P2, prec_Q2); + const Fqk ans_12 = ppT::double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); + assert(ans_1 * ans_2 == ans_12); +} + +template +void affine_pairing_test() +{ + GT GT_one = GT::one(); + + printf("Running bilinearity tests:\n"); + G1 P = (Fr::random_element()) * G1::one(); + G2 Q = (Fr::random_element()) * G2::one(); + + printf("P:\n"); + P.print(); + printf("Q:\n"); + Q.print(); + printf("\n\n"); + + Fr s = Fr::random_element(); + G1 sP = s * P; + G2 sQ = s * Q; + + printf("Pairing bilinearity tests (three must match):\n"); + GT ans1 = ppT::affine_reduced_pairing(sP, Q); + GT ans2 = ppT::affine_reduced_pairing(P, sQ); + GT ans3 = ppT::affine_reduced_pairing(P, Q)^s; + ans1.print(); + ans2.print(); + ans3.print(); + assert(ans1 == ans2); + assert(ans2 == ans3); + + assert(ans1 != GT_one); + assert((ans1^Fr::field_char()) == GT_one); + printf("\n\n"); +} + +int main(void) +{ + start_profiling(); + edwards_pp::init_public_params(); + pairing_test(); + double_miller_loop_test(); + + mnt6_pp::init_public_params(); + pairing_test(); + double_miller_loop_test(); + affine_pairing_test(); + + mnt4_pp::init_public_params(); + pairing_test(); + double_miller_loop_test(); + affine_pairing_test(); + + alt_bn128_pp::init_public_params(); + pairing_test(); + double_miller_loop_test(); + +#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled + bn128_pp::init_public_params(); + pairing_test(); + double_miller_loop_test(); +#endif +} diff --git a/privacy/zsl/zsl/algebra/curves/tests/test_groups.cpp b/privacy/zsl/zsl/algebra/curves/tests/test_groups.cpp new file mode 100644 index 0000000..725e490 --- /dev/null +++ b/privacy/zsl/zsl/algebra/curves/tests/test_groups.cpp @@ -0,0 +1,175 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include "common/profiling.hpp" +#include "algebra/curves/edwards/edwards_pp.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +#ifdef CURVE_BN128 +#include "algebra/curves/bn128/bn128_pp.hpp" +#endif +#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" +#include + +using namespace libsnark; + +template +void test_mixed_add() +{ + GroupT base, el, result; + + base = GroupT::zero(); + el = GroupT::zero(); + el.to_special(); + result = base.mixed_add(el); + assert(result == base + el); + + base = GroupT::zero(); + el = GroupT::random_element(); + el.to_special(); + result = base.mixed_add(el); + assert(result == base + el); + + base = GroupT::random_element(); + el = GroupT::zero(); + el.to_special(); + result = base.mixed_add(el); + assert(result == base + el); + + base = GroupT::random_element(); + el = GroupT::random_element(); + el.to_special(); + result = base.mixed_add(el); + assert(result == base + el); + + base = GroupT::random_element(); + el = base; + el.to_special(); + result = base.mixed_add(el); + assert(result == base.dbl()); +} + +template +void test_group() +{ + bigint<1> rand1 = bigint<1>("76749407"); + bigint<1> rand2 = bigint<1>("44410867"); + bigint<1> randsum = bigint<1>("121160274"); + + GroupT zero = GroupT::zero(); + assert(zero == zero); + GroupT one = GroupT::one(); + assert(one == one); + GroupT two = bigint<1>(2l) * GroupT::one(); + assert(two == two); + GroupT five = bigint<1>(5l) * GroupT::one(); + + GroupT three = bigint<1>(3l) * GroupT::one(); + GroupT four = bigint<1>(4l) * GroupT::one(); + + assert(two+five == three+four); + + GroupT a = GroupT::random_element(); + GroupT b = GroupT::random_element(); + + assert(one != zero); + assert(a != zero); + assert(a != one); + + assert(b != zero); + assert(b != one); + + assert(a.dbl() == a + a); + assert(b.dbl() == b + b); + assert(one.add(two) == three); + assert(two.add(one) == three); + assert(a + b == b + a); + assert(a - a == zero); + assert(a - b == a + (-b)); + assert(a - b == (-b) + a); + + // handle special cases + assert(zero + (-a) == -a); + assert(zero - a == -a); + assert(a - zero == a); + assert(a + zero == a); + assert(zero + a == a); + + assert((a + b).dbl() == (a + b) + (b + a)); + assert(bigint<1>("2") * (a + b) == (a + b) + (b + a)); + + assert((rand1 * a) + (rand2 * a) == (randsum * a)); + + assert(GroupT::order() * a == zero); + assert(GroupT::order() * one == zero); + assert((GroupT::order() * a) - a != zero); + assert((GroupT::order() * one) - one != zero); + + test_mixed_add(); +} + +template +void test_mul_by_q() +{ + GroupT a = GroupT::random_element(); + assert((GroupT::base_field_char()*a) == a.mul_by_q()); +} + +template +void test_output() +{ + GroupT g = GroupT::zero(); + + for (size_t i = 0; i < 1000; ++i) + { + std::stringstream ss; + ss << g; + GroupT gg; + ss >> gg; + assert(g == gg); + /* use a random point in next iteration */ + g = GroupT::random_element(); + } +} + +int main(void) +{ + edwards_pp::init_public_params(); + test_group >(); + test_output >(); + test_group >(); + test_output >(); + test_mul_by_q >(); + + mnt4_pp::init_public_params(); + test_group >(); + test_output >(); + test_group >(); + test_output >(); + test_mul_by_q >(); + + mnt6_pp::init_public_params(); + test_group >(); + test_output >(); + test_group >(); + test_output >(); + test_mul_by_q >(); + + alt_bn128_pp::init_public_params(); + test_group >(); + test_output >(); + test_group >(); + test_output >(); + test_mul_by_q >(); + +#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled + bn128_pp::init_public_params(); + test_group >(); + test_output >(); + test_group >(); + test_output >(); +#endif +} diff --git a/privacy/zsl/zsl/algebra/evaluation_domain/domains/basic_radix2_domain.hpp b/privacy/zsl/zsl/algebra/evaluation_domain/domains/basic_radix2_domain.hpp new file mode 100644 index 0000000..3e127a0 --- /dev/null +++ b/privacy/zsl/zsl/algebra/evaluation_domain/domains/basic_radix2_domain.hpp @@ -0,0 +1,45 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the "basic radix-2" evaluation domain. + + Roughly, the domain has size m = 2^k and consists of the m-th roots of unity. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BASIC_RADIX2_DOMAIN_HPP_ +#define BASIC_RADIX2_DOMAIN_HPP_ + +#include "algebra/evaluation_domain/evaluation_domain.hpp" + +namespace libsnark { + +template +class basic_radix2_domain : public evaluation_domain { +public: + + FieldT omega; + + basic_radix2_domain(const size_t m); + + void FFT(std::vector &a); + void iFFT(std::vector &a); + void cosetFFT(std::vector &a, const FieldT &g); + void icosetFFT(std::vector &a, const FieldT &g); + std::vector lagrange_coeffs(const FieldT &t); + FieldT get_element(const size_t idx); + FieldT compute_Z(const FieldT &t); + void add_poly_Z(const FieldT &coeff, std::vector &H); + void divide_by_Z_on_coset(std::vector &P); + +}; + +} // libsnark + +#include "algebra/evaluation_domain/domains/basic_radix2_domain.tcc" + +#endif // BASIC_RADIX2_DOMAIN_HPP_ diff --git a/privacy/zsl/zsl/algebra/evaluation_domain/domains/basic_radix2_domain.tcc b/privacy/zsl/zsl/algebra/evaluation_domain/domains/basic_radix2_domain.tcc new file mode 100644 index 0000000..d315e83 --- /dev/null +++ b/privacy/zsl/zsl/algebra/evaluation_domain/domains/basic_radix2_domain.tcc @@ -0,0 +1,112 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the "basic radix-2" evaluation domain. + + See basic_radix2_domain.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BASIC_RADIX2_DOMAIN_TCC_ +#define BASIC_RADIX2_DOMAIN_TCC_ + +#include "algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp" + +namespace libsnark { + +template +basic_radix2_domain::basic_radix2_domain(const size_t m) : evaluation_domain(m) +{ + assert(m > 1); + const size_t logm = log2(m); + assert(logm <= (FieldT::s)); + + omega = get_root_of_unity(m); +} + +template +void basic_radix2_domain::FFT(std::vector &a) +{ + enter_block("Execute FFT"); + assert(a.size() == this->m); + _basic_radix2_FFT(a, omega); + leave_block("Execute FFT"); +} + +template +void basic_radix2_domain::iFFT(std::vector &a) +{ + enter_block("Execute inverse FFT"); + assert(a.size() == this->m); + _basic_radix2_FFT(a, omega.inverse()); + + const FieldT sconst = FieldT(a.size()).inverse(); + for (size_t i = 0; i < a.size(); ++i) + { + a[i] *= sconst; + } + leave_block("Execute inverse FFT"); +} + +template +void basic_radix2_domain::cosetFFT(std::vector &a, const FieldT &g) +{ + enter_block("Execute coset FFT"); + _multiply_by_coset(a, g); + FFT(a); + leave_block("Execute coset FFT"); +} + +template +void basic_radix2_domain::icosetFFT(std::vector &a, const FieldT &g) +{ + enter_block("Execute inverse coset IFFT"); + iFFT(a); + _multiply_by_coset(a, g.inverse()); + leave_block("Execute inverse coset IFFT"); +} + +template +std::vector basic_radix2_domain::lagrange_coeffs(const FieldT &t) +{ + return _basic_radix2_lagrange_coeffs(this->m, t); +} + +template +FieldT basic_radix2_domain::get_element(const size_t idx) +{ + return omega^idx; +} + +template +FieldT basic_radix2_domain::compute_Z(const FieldT &t) +{ + return (t^this->m) - FieldT::one(); +} + +template +void basic_radix2_domain::add_poly_Z(const FieldT &coeff, std::vector &H) +{ + assert(H.size() == this->m+1); + H[this->m] += coeff; + H[0] -= coeff; +} + +template +void basic_radix2_domain::divide_by_Z_on_coset(std::vector &P) +{ + const FieldT coset = FieldT::multiplicative_generator; + const FieldT Z_inverse_at_coset = this->compute_Z(coset).inverse(); + for (size_t i = 0; i < this->m; ++i) + { + P[i] *= Z_inverse_at_coset; + } +} + +} // libsnark + +#endif // BASIC_RADIX2_DOMAIN_TCC_ diff --git a/privacy/zsl/zsl/algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp b/privacy/zsl/zsl/algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp new file mode 100644 index 0000000..c42ab2f --- /dev/null +++ b/privacy/zsl/zsl/algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp @@ -0,0 +1,48 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for auxiliary functions for the "basic radix-2" evaluation domain. + + These functions compute the radix-2 FFT (in single- or multi-thread mode) and, + also compute Lagrange coefficients. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BASIC_RADIX2_DOMAIN_AUX_HPP_ +#define BASIC_RADIX2_DOMAIN_AUX_HPP_ + +namespace libsnark { + +/** + * Compute the radix-2 FFT of the vector a over the set S={omega^{0},...,omega^{m-1}}. + */ +template +void _basic_radix2_FFT(std::vector &a, const FieldT &omega); + +/** + * A multi-thread version of _basic_radix2_FFT. + */ +template +void _parallel_basic_radix2_FFT(std::vector &a, const FieldT &omega); + +/** + * Translate the vector a to a coset defined by g. + */ +template +void _multiply_by_coset(std::vector &a, const FieldT &g); + +/** + * Compute the m Lagrange coefficients, relative to the set S={omega^{0},...,omega^{m-1}}, at the field element t. + */ +template +std::vector _basic_radix2_lagrange_coeffs(const size_t m, const FieldT &t); + +} // libsnark + +#include "algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc" + +#endif // BASIC_RADIX2_DOMAIN_AUX_HPP_ diff --git a/privacy/zsl/zsl/algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc b/privacy/zsl/zsl/algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc new file mode 100644 index 0000000..138b82d --- /dev/null +++ b/privacy/zsl/zsl/algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc @@ -0,0 +1,242 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for auxiliary functions for the "basic radix-2" evaluation domain. + + See basic_radix2_domain_aux.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BASIC_RADIX2_DOMAIN_AUX_TCC_ +#define BASIC_RADIX2_DOMAIN_AUX_TCC_ + +#include +#ifdef MULTICORE +#include +#endif +#include "algebra/fields/field_utils.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" + +namespace libsnark { + +#ifdef MULTICORE +#define _basic_radix2_FFT _basic_parallel_radix2_FFT +#else +#define _basic_radix2_FFT _basic_serial_radix2_FFT +#endif + +/* + Below we make use of pseudocode from [CLRS 2n Ed, pp. 864]. + Also, note that it's the caller's responsibility to multiply by 1/N. + */ +template +void _basic_serial_radix2_FFT(std::vector &a, const FieldT &omega) +{ + const size_t n = a.size(), logn = log2(n); + assert(n == (1u << logn)); + + /* swapping in place (from Storer's book) */ + for (size_t k = 0; k < n; ++k) + { + const size_t rk = bitreverse(k, logn); + if (k < rk) + std::swap(a[k], a[rk]); + } + + size_t m = 1; // invariant: m = 2^{s-1} + for (size_t s = 1; s <= logn; ++s) + { + // w_m is 2^s-th root of unity now + const FieldT w_m = omega^(n/(2*m)); + + asm volatile ("/* pre-inner */"); + for (size_t k = 0; k < n; k += 2*m) + { + FieldT w = FieldT::one(); + for (size_t j = 0; j < m; ++j) + { + const FieldT t = w * a[k+j+m]; + a[k+j+m] = a[k+j] - t; + a[k+j] += t; + w *= w_m; + } + } + asm volatile ("/* post-inner */"); + m *= 2; + } +} + +template +void _basic_parallel_radix2_FFT_inner(std::vector &a, const FieldT &omega, const size_t log_cpus) +{ + const size_t num_cpus = 1ul< > tmp(num_cpus); + for (size_t j = 0; j < num_cpus; ++j) + { + tmp[j].resize(1ul<<(log_m-log_cpus), FieldT::zero()); + } + +#ifdef MULTICORE + #pragma omp parallel for +#endif + for (size_t j = 0; j < num_cpus; ++j) + { + const FieldT omega_j = omega^j; + const FieldT omega_step = omega^(j<<(log_m - log_cpus)); + + FieldT elt = FieldT::one(); + for (size_t i = 0; i < 1ul<<(log_m - log_cpus); ++i) + { + for (size_t s = 0; s < num_cpus; ++s) + { + // invariant: elt is omega^(j*idx) + const size_t idx = (i + (s<<(log_m - log_cpus))) % (1u << log_m); + tmp[j][i] += a[idx] * elt; + elt *= omega_step; + } + elt *= omega_j; + } + } + leave_block("Shuffle inputs"); + + enter_block("Execute sub-FFTs"); + const FieldT omega_num_cpus = omega^num_cpus; + +#ifdef MULTICORE + #pragma omp parallel for +#endif + for (size_t j = 0; j < num_cpus; ++j) + { + _basic_serial_radix2_FFT(tmp[j], omega_num_cpus); + } + leave_block("Execute sub-FFTs"); + + enter_block("Re-shuffle outputs"); + +#ifdef MULTICORE + #pragma omp parallel for +#endif + for (size_t i = 0; i < num_cpus; ++i) + { + for (size_t j = 0; j < 1ul<<(log_m - log_cpus); ++j) + { + // now: i = idx >> (log_m - log_cpus) and j = idx % (1u << (log_m - log_cpus)), for idx = ((i<<(log_m-log_cpus))+j) % (1u << log_m) + a[(j< +void _basic_parallel_radix2_FFT(std::vector &a, const FieldT &omega) +{ +#ifdef MULTICORE + const size_t num_cpus = omp_get_max_threads(); +#else + const size_t num_cpus = 1; +#endif + const size_t log_cpus = ((num_cpus & (num_cpus - 1)) == 0 ? log2(num_cpus) : log2(num_cpus) - 1); + +#ifdef DEBUG + print_indent(); printf("* Invoking parallel FFT on 2^%zu CPUs (omp_get_max_threads = %zu)\n", log_cpus, num_cpus); +#endif + + if (log_cpus == 0) + { + _basic_serial_radix2_FFT(a, omega); + } + else + { + _basic_parallel_radix2_FFT_inner(a, omega, log_cpus); + } +} + +template +void _multiply_by_coset(std::vector &a, const FieldT &g) +{ + //enter_block("Multiply by coset"); + FieldT u = g; + for (size_t i = 1; i < a.size(); ++i) + { + a[i] *= u; + u *= g; + } + //leave_block("Multiply by coset"); +} + +template +std::vector _basic_radix2_lagrange_coeffs(const size_t m, const FieldT &t) +{ + if (m == 1) + { + return std::vector(1, FieldT::one()); + } + + assert(m == (1u << log2(m))); + + const FieldT omega = get_root_of_unity(m); + + std::vector u(m, FieldT::zero()); + + /* + If t equals one of the roots of unity in S={omega^{0},...,omega^{m-1}} + then output 1 at the right place, and 0 elsewhere + */ + + if ((t^m) == (FieldT::one())) + { + FieldT omega_i = FieldT::one(); + for (size_t i = 0; i < m; ++i) + { + if (omega_i == t) // i.e., t equals omega^i + { + u[i] = FieldT::one(); + return u; + } + + omega_i *= omega; + } + } + + /* + Otherwise, if t does not equal any of the roots of unity in S, + then compute each L_{i,S}(t) as Z_{S}(t) * v_i / (t-\omega^i) + where: + - Z_{S}(t) = \prod_{j} (t-\omega^j) = (t^m-1), and + - v_{i} = 1 / \prod_{j \neq i} (\omega^i-\omega^j). + Below we use the fact that v_{0} = 1/m and v_{i+1} = \omega * v_{i}. + */ + + const FieldT Z = (t^m)-FieldT::one(); + FieldT l = Z * FieldT(m).inverse(); + FieldT r = FieldT::one(); + for (size_t i = 0; i < m; ++i) + { + u[i] = l * (t - r).inverse(); + l *= omega; + r *= omega; + } + + return u; +} + +} // libsnark + +#endif // BASIC_RADIX2_DOMAIN_AUX_TCC_ diff --git a/privacy/zsl/zsl/algebra/evaluation_domain/domains/extended_radix2_domain.hpp b/privacy/zsl/zsl/algebra/evaluation_domain/domains/extended_radix2_domain.hpp new file mode 100644 index 0000000..59cf898 --- /dev/null +++ b/privacy/zsl/zsl/algebra/evaluation_domain/domains/extended_radix2_domain.hpp @@ -0,0 +1,48 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the "extended radix-2" evaluation domain. + + Roughly, the domain has size m = 2^{k+1} and consists of + "the m-th roots of unity" union "a coset of these roots". + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EXTENDED_RADIX2_DOMAIN_HPP_ +#define EXTENDED_RADIX2_DOMAIN_HPP_ + +#include "algebra/evaluation_domain/evaluation_domain.hpp" + +namespace libsnark { + +template +class extended_radix2_domain : public evaluation_domain { +public: + + size_t small_m; + FieldT omega; + FieldT shift; + + extended_radix2_domain(const size_t m); + + void FFT(std::vector &a); + void iFFT(std::vector &a); + void cosetFFT(std::vector &a, const FieldT &g); + void icosetFFT(std::vector &a, const FieldT &g); + std::vector lagrange_coeffs(const FieldT &t); + FieldT get_element(const size_t idx); + FieldT compute_Z(const FieldT &t); + void add_poly_Z(const FieldT &coeff, std::vector &H); + void divide_by_Z_on_coset(std::vector &P); + +}; + +} // libsnark + +#include "algebra/evaluation_domain/domains/extended_radix2_domain.tcc" + +#endif // EXTENDED_RADIX2_DOMAIN_HPP_ diff --git a/privacy/zsl/zsl/algebra/evaluation_domain/domains/extended_radix2_domain.tcc b/privacy/zsl/zsl/algebra/evaluation_domain/domains/extended_radix2_domain.tcc new file mode 100644 index 0000000..bd5c700 --- /dev/null +++ b/privacy/zsl/zsl/algebra/evaluation_domain/domains/extended_radix2_domain.tcc @@ -0,0 +1,180 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the "extended radix-2" evaluation domain. + + See extended_radix2_domain.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EXTENDED_RADIX2_DOMAIN_TCC_ + +#include "algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp" + +namespace libsnark { + +template +extended_radix2_domain::extended_radix2_domain(const size_t m) : evaluation_domain(m) +{ + assert(m > 1); + + const size_t logm = log2(m); + + assert(logm == FieldT::s + 1); + + small_m = m/2; + omega = get_root_of_unity(small_m); + shift = coset_shift(); +} + +template +void extended_radix2_domain::FFT(std::vector &a) +{ + assert(a.size() == this->m); + + std::vector a0(small_m, FieldT::zero()); + std::vector a1(small_m, FieldT::zero()); + + const FieldT shift_to_small_m = shift^bigint<1>(small_m); + + FieldT shift_i = FieldT::one(); + for (size_t i = 0; i < small_m; ++i) + { + a0[i] = a[i] + a[small_m + i]; + a1[i] = shift_i * (a[i] + shift_to_small_m * a[small_m + i]); + + shift_i *= shift; + } + + _basic_radix2_FFT(a0, omega); + _basic_radix2_FFT(a1, omega); + + for (size_t i = 0; i < small_m; ++i) + { + a[i] = a0[i]; + a[i+small_m] = a1[i]; + } +} + +template +void extended_radix2_domain::iFFT(std::vector &a) +{ + assert(a.size() == this->m); + + // note: this is not in-place + std::vector a0(a.begin(), a.begin() + small_m); + std::vector a1(a.begin() + small_m, a.end()); + + const FieldT omega_inverse = omega.inverse(); + _basic_radix2_FFT(a0, omega_inverse); + _basic_radix2_FFT(a1, omega_inverse); + + const FieldT shift_to_small_m = shift^bigint<1>(small_m); + const FieldT sconst = (FieldT(small_m) * (FieldT::one()-shift_to_small_m)).inverse(); + + const FieldT shift_inverse = shift.inverse(); + FieldT shift_inverse_i = FieldT::one(); + + for (size_t i = 0; i < small_m; ++i) + { + a[i] = sconst * (-shift_to_small_m * a0[i] + shift_inverse_i * a1[i]); + a[i+small_m] = sconst * (a0[i] - shift_inverse_i * a1[i]); + + shift_inverse_i *= shift_inverse; + } +} + +template +void extended_radix2_domain::cosetFFT(std::vector &a, const FieldT &g) +{ + _multiply_by_coset(a, g); + FFT(a); +} + +template +void extended_radix2_domain::icosetFFT(std::vector &a, const FieldT &g) +{ + iFFT(a); + _multiply_by_coset(a, g.inverse()); +} + +template +std::vector extended_radix2_domain::lagrange_coeffs(const FieldT &t) +{ + const std::vector T0 = _basic_radix2_lagrange_coeffs(small_m, t); + const std::vector T1 = _basic_radix2_lagrange_coeffs(small_m, t * shift.inverse()); + + std::vector result(this->m, FieldT::zero()); + + const FieldT t_to_small_m = t ^ bigint<1>(small_m); + const FieldT shift_to_small_m = shift ^ bigint<1>(small_m); + const FieldT one_over_denom = (shift_to_small_m - FieldT::one()).inverse(); + const FieldT T0_coeff = (t_to_small_m - shift_to_small_m) * (-one_over_denom); + const FieldT T1_coeff = (t_to_small_m - FieldT::one()) * one_over_denom; + for (size_t i = 0; i < small_m; ++i) + { + result[i] = T0[i] * T0_coeff; + result[i+small_m] = T1[i] * T1_coeff; + } + + return result; +} + +template +FieldT extended_radix2_domain::get_element(const size_t idx) +{ + if (idx < small_m) + { + return omega^idx; + } + else + { + return shift*(omega^(idx-small_m)); + } +} + +template +FieldT extended_radix2_domain::compute_Z(const FieldT &t) +{ + return ((t^small_m) - FieldT::one()) * ((t^small_m) - (shift^small_m)); +} + +template +void extended_radix2_domain::add_poly_Z(const FieldT &coeff, std::vector &H) +{ + assert(H.size() == this->m+1); + const FieldT shift_to_small_m = shift^small_m; + + H[this->m] += coeff; + H[small_m] -= coeff * (shift_to_small_m + FieldT::one()); + H[0] += coeff * shift_to_small_m; +} + +template +void extended_radix2_domain::divide_by_Z_on_coset(std::vector &P) +{ + const FieldT coset = FieldT::multiplicative_generator; + + const FieldT coset_to_small_m = coset^small_m; + const FieldT shift_to_small_m = shift^small_m; + + const FieldT Z0 = (coset_to_small_m - FieldT::one()) * (coset_to_small_m - shift_to_small_m); + const FieldT Z1 = (coset_to_small_m*shift_to_small_m - FieldT::one()) * (coset_to_small_m * shift_to_small_m - shift_to_small_m); + + const FieldT Z0_inverse = Z0.inverse(); + const FieldT Z1_inverse = Z1.inverse(); + + for (size_t i = 0; i < small_m; ++i) + { + P[i] *= Z0_inverse; + P[i+small_m] *= Z1_inverse; + } +} + +} // libsnark + +#endif // EXTENDED_RADIX2_DOMAIN_TCC_ diff --git a/privacy/zsl/zsl/algebra/evaluation_domain/domains/step_radix2_domain.hpp b/privacy/zsl/zsl/algebra/evaluation_domain/domains/step_radix2_domain.hpp new file mode 100644 index 0000000..ae9818a --- /dev/null +++ b/privacy/zsl/zsl/algebra/evaluation_domain/domains/step_radix2_domain.hpp @@ -0,0 +1,50 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the "step radix-2" evaluation domain. + + Roughly, the domain has size m = 2^k + 2^r and consists of + "the 2^k-th roots of unity" union "a coset of 2^r-th roots of unity". + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef STEP_RADIX2_DOMAIN_HPP_ +#define STEP_RADIX2_DOMAIN_HPP_ + +#include "algebra/evaluation_domain/evaluation_domain.hpp" + +namespace libsnark { + +template +class step_radix2_domain : public evaluation_domain { +public: + + size_t big_m; + size_t small_m; + FieldT omega; + FieldT big_omega; + FieldT small_omega; + + step_radix2_domain(const size_t m); + + void FFT(std::vector &a); + void iFFT(std::vector &a); + void cosetFFT(std::vector &a, const FieldT &g); + void icosetFFT(std::vector &a, const FieldT &g); + std::vector lagrange_coeffs(const FieldT &t); + FieldT get_element(const size_t idx); + FieldT compute_Z(const FieldT &t); + void add_poly_Z(const FieldT &coeff, std::vector &H); + void divide_by_Z_on_coset(std::vector &P); + +}; + +} // libsnark + +#include "algebra/evaluation_domain/domains/step_radix2_domain.tcc" + +#endif // STEP_RADIX2_DOMAIN_HPP_ diff --git a/privacy/zsl/zsl/algebra/evaluation_domain/domains/step_radix2_domain.tcc b/privacy/zsl/zsl/algebra/evaluation_domain/domains/step_radix2_domain.tcc new file mode 100644 index 0000000..af9fa29 --- /dev/null +++ b/privacy/zsl/zsl/algebra/evaluation_domain/domains/step_radix2_domain.tcc @@ -0,0 +1,247 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the "step radix-2" evaluation domain. + + See step_radix2_domain.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef STEP_RADIX2_DOMAIN_TCC_ + +#include "algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp" + +namespace libsnark { + +template +step_radix2_domain::step_radix2_domain(const size_t m) : evaluation_domain(m) +{ + assert(m > 1); + + big_m = 1ul<<(log2(m)-1); + small_m = m - big_m; + + assert(small_m == 1ul<(1ul<(small_m); +} + +template +void step_radix2_domain::FFT(std::vector &a) +{ + assert(a.size() == this->m); + std::vector c(big_m, FieldT::zero()); + std::vector d(big_m, FieldT::zero()); + + FieldT omega_i = FieldT::one(); + for (size_t i = 0; i < big_m; ++i) + { + c[i] = (i < small_m ? a[i] + a[i+big_m] : a[i]); + d[i] = omega_i * (i < small_m ? a[i] - a[i+big_m] : a[i]); + omega_i *= omega; + } + + std::vector e(small_m, FieldT::zero()); + const size_t compr = 1ul<<(log2(big_m) - log2(small_m)); + for (size_t i = 0; i < small_m; ++i) + { + for (size_t j = 0; j < compr; ++j) + { + e[i] += d[i + j * small_m]; + } + } + + _basic_radix2_FFT(c, omega.squared()); + _basic_radix2_FFT(e, get_root_of_unity(small_m)); + + for (size_t i = 0; i < big_m; ++i) + { + a[i] = c[i]; + } + + for (size_t i = 0; i < small_m; ++i) + { + a[i+big_m] = e[i]; + } +} + +template +void step_radix2_domain::iFFT(std::vector &a) +{ + assert(a.size() == this->m); + + std::vector U0(a.begin(), a.begin() + big_m); + std::vector U1(a.begin() + big_m, a.end()); + + _basic_radix2_FFT(U0, omega.squared().inverse()); + _basic_radix2_FFT(U1, get_root_of_unity(small_m).inverse()); + + const FieldT U0_size_inv = FieldT(big_m).inverse(); + for (size_t i = 0; i < big_m; ++i) + { + U0[i] *= U0_size_inv; + } + + const FieldT U1_size_inv = FieldT(small_m).inverse(); + for (size_t i = 0; i < small_m; ++i) + { + U1[i] *= U1_size_inv; + } + + std::vector tmp = U0; + FieldT omega_i = FieldT::one(); + for (size_t i = 0; i < big_m; ++i) + { + tmp[i] *= omega_i; + omega_i *= omega; + } + + // save A_suffix + for (size_t i = small_m; i < big_m; ++i) + { + a[i] = U0[i]; + } + + const size_t compr = 1ul<<(log2(big_m) - log2(small_m)); + for (size_t i = 0; i < small_m; ++i) + { + for (size_t j = 1; j < compr; ++j) + { + U1[i] -= tmp[i + j * small_m]; + } + } + + const FieldT omega_inv = omega.inverse(); + FieldT omega_inv_i = FieldT::one(); + for (size_t i = 0; i < small_m; ++i) + { + U1[i] *= omega_inv_i; + omega_inv_i *= omega_inv; + } + + // compute A_prefix + const FieldT over_two = FieldT(2).inverse(); + for (size_t i = 0; i < small_m; ++i) + { + a[i] = (U0[i]+U1[i]) * over_two; + } + + // compute B2 + for (size_t i = 0; i < small_m; ++i) + { + a[big_m + i] = (U0[i]-U1[i]) * over_two; + } +} + +template +void step_radix2_domain::cosetFFT(std::vector &a, const FieldT &g) +{ + _multiply_by_coset(a, g); + FFT(a); +} + +template +void step_radix2_domain::icosetFFT(std::vector &a, const FieldT &g) +{ + iFFT(a); + _multiply_by_coset(a, g.inverse()); +} + +template +std::vector step_radix2_domain::lagrange_coeffs(const FieldT &t) +{ + std::vector inner_big = _basic_radix2_lagrange_coeffs(big_m, t); + std::vector inner_small = _basic_radix2_lagrange_coeffs(small_m, t * omega.inverse()); + + std::vector result(this->m, FieldT::zero()); + + const FieldT L0 = (t^small_m)-(omega^small_m); + const FieldT omega_to_small_m = omega^small_m; + const FieldT big_omega_to_small_m = big_omega ^ small_m; + FieldT elt = FieldT::one(); + for (size_t i = 0; i < big_m; ++i) + { + result[i] = inner_big[i] * L0 * (elt - omega_to_small_m).inverse(); + elt *= big_omega_to_small_m; + } + + const FieldT L1 = ((t^big_m)-FieldT::one()) * ((omega^big_m) - FieldT::one()).inverse(); + + for (size_t i = 0; i < small_m; ++i) + { + result[big_m + i] = L1 * inner_small[i]; + } + + return result; +} + +template +FieldT step_radix2_domain::get_element(const size_t idx) +{ + if (idx < big_m) + { + return big_omega^idx; + } + else + { + return omega * (small_omega^(idx-big_m)); + } +} + +template +FieldT step_radix2_domain::compute_Z(const FieldT &t) +{ + return ((t^big_m) - FieldT::one()) * ((t^small_m) - (omega^small_m)); +} + +template +void step_radix2_domain::add_poly_Z(const FieldT &coeff, std::vector &H) +{ + assert(H.size() == this->m+1); + const FieldT omega_to_small_m = omega^small_m; + + H[this->m] += coeff; + H[big_m] -= coeff * omega_to_small_m; + H[small_m] -= coeff; + H[0] += coeff * omega_to_small_m; +} + +template +void step_radix2_domain::divide_by_Z_on_coset(std::vector &P) +{ + // (c^{2^k}-1) * (c^{2^r} * w^{2^{r+1}*i) - w^{2^r}) + const FieldT coset = FieldT::multiplicative_generator; + + const FieldT Z0 = (coset^big_m) - FieldT::one(); + const FieldT coset_to_small_m_times_Z0 = (coset^small_m) * Z0; + const FieldT omega_to_small_m_times_Z0 = (omega^small_m) * Z0; + const FieldT omega_to_2small_m = omega^(2*small_m); + FieldT elt = FieldT::one(); + + for (size_t i = 0; i < big_m; ++i) + { + P[i] *= (coset_to_small_m_times_Z0 * elt - omega_to_small_m_times_Z0).inverse(); + elt *= omega_to_2small_m; + } + + // (c^{2^k}*w^{2^k}-1) * (c^{2^k} * w^{2^r} - w^{2^r}) + + const FieldT Z1 = ((((coset*omega)^big_m) - FieldT::one()) * (((coset * omega)^small_m) - (omega^small_m))); + const FieldT Z1_inverse = Z1.inverse(); + + for (size_t i = 0; i < small_m; ++i) + { + P[big_m + i] *= Z1_inverse; + } + +} + +} // libsnark + +#endif // STEP_RADIX2_DOMAIN_TCC_ diff --git a/privacy/zsl/zsl/algebra/evaluation_domain/evaluation_domain.hpp b/privacy/zsl/zsl/algebra/evaluation_domain/evaluation_domain.hpp new file mode 100644 index 0000000..358db97 --- /dev/null +++ b/privacy/zsl/zsl/algebra/evaluation_domain/evaluation_domain.hpp @@ -0,0 +1,125 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for evaluation domains. + + Roughly, given a desired size m for the domain, the constructor selects + a choice of domain S with size ~m that has been selected so to optimize + - computations of Lagrange polynomials, and + - FFT/iFFT computations. + An evaluation domain also provides other other functions, e.g., accessing + individual elements in S or evaluating its vanishing polynomial. + + The descriptions below make use of the definition of a *Lagrange polynomial*, + which we recall. Given a field F, a subset S=(a_i)_i of F, and an index idx + in {0,...,|S-1|}, the idx-th Lagrange polynomial (wrt to subset S) is defined to be + \f[ L_{idx,S}(z) := prod_{k \neq idx} (z - a_k) / prod_{k \neq idx} (a_{idx} - a_k) \f] + Note that, by construction: + \f[ \forall j \neq idx: L_{idx,S}(a_{idx}) = 1 \text{ and } L_{idx,S}(a_j) = 0 \f] + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EVALUATION_DOMAIN_HPP_ +#define EVALUATION_DOMAIN_HPP_ + +#include + +namespace libsnark { + +/** + * An evaluation domain. + */ +template +class evaluation_domain { +public: + + const size_t m; + + /** + * Construct an evaluation domain S of size m, if possible. + * + * (See the function get_evaluation_domain below.) + */ + evaluation_domain(const size_t m) : m(m) {}; + + /** + * Get the idx-th element in S. + */ + virtual FieldT get_element(const size_t idx) = 0; + + /** + * Compute the FFT, over the domain S, of the vector a. + */ + virtual void FFT(std::vector &a) = 0; + + /** + * Compute the inverse FFT, over the domain S, of the vector a. + */ + virtual void iFFT(std::vector &a) = 0; + + /** + * Compute the FFT, over the domain g*S, of the vector a. + */ + virtual void cosetFFT(std::vector &a, const FieldT &g) = 0; + + /** + * Compute the inverse FFT, over the domain g*S, of the vector a. + */ + virtual void icosetFFT(std::vector &a, const FieldT &g) = 0; + + /** + * Evaluate all Lagrange polynomials. + * + * The inputs are: + * - an integer m + * - an element t + * The output is a vector (b_{0},...,b_{m-1}) + * where b_{i} is the evaluation of L_{i,S}(z) at z = t. + */ + virtual std::vector lagrange_coeffs(const FieldT &t) = 0; + + /** + * Evaluate the vanishing polynomial of S at the field element t. + */ + virtual FieldT compute_Z(const FieldT &t) = 0; + + /** + * Add the coefficients of the vanishing polynomial of S to the coefficients of the polynomial H. + */ + virtual void add_poly_Z(const FieldT &coeff, std::vector &H) = 0; + + /** + * Multiply by the evaluation, on a coset of S, of the inverse of the vanishing polynomial of S. + */ + virtual void divide_by_Z_on_coset(std::vector &P) = 0; +}; + +/** + * Return an evaluation domain object in which the domain S has size |S| >= min_size. + * The function chooses from different supported domains, depending on min_size. + */ +template +std::shared_ptr > get_evaluation_domain(const size_t min_size); + +/** + * Naive evaluation of a *single* Lagrange polynomial, used for testing purposes. + * + * The inputs are: + * - an integer m + * - a domain S = (a_{0},...,a_{m-1}) of size m + * - a field element element t + * - an index idx in {0,...,m-1} + * The output is the polynomial L_{idx,S}(z) evaluated at z = t. + */ +template +FieldT lagrange_eval(const size_t m, const std::vector &domain, const FieldT &t, const size_t idx); + +} // libsnark + +#include "algebra/evaluation_domain/evaluation_domain.tcc" + +#endif // EVALUATION_DOMAIN_HPP_ diff --git a/privacy/zsl/zsl/algebra/evaluation_domain/evaluation_domain.tcc b/privacy/zsl/zsl/algebra/evaluation_domain/evaluation_domain.tcc new file mode 100644 index 0000000..47d0495 --- /dev/null +++ b/privacy/zsl/zsl/algebra/evaluation_domain/evaluation_domain.tcc @@ -0,0 +1,119 @@ +/** @file + ***************************************************************************** + + Imeplementation of interfaces for evaluation domains. + + See evaluation_domain.hpp . + + We currently implement, and select among, three types of domains: + - "basic radix-2": the domain has size m = 2^k and consists of the m-th roots of unity + - "extended radix-2": the domain has size m = 2^{k+1} and consists of "the m-th roots of unity" union "a coset" + - "step radix-2": the domain has size m = 2^k + 2^r and consists of "the 2^k-th roots of unity" union "a coset of 2^r-th roots of unity" + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EVALUATION_DOMAIN_TCC_ +#define EVALUATION_DOMAIN_TCC_ + +#include +#include "algebra/fields/field_utils.hpp" +#include "algebra/evaluation_domain/domains/basic_radix2_domain.hpp" +#include "algebra/evaluation_domain/domains/extended_radix2_domain.hpp" +#include "algebra/evaluation_domain/domains/step_radix2_domain.hpp" + +namespace libsnark { + +template +std::shared_ptr > get_evaluation_domain(const size_t min_size) +{ + assert(min_size > 1); + const size_t log_min_size = log2(min_size); + assert(log_min_size <= (FieldT::s+1)); + + std::shared_ptr > result; + if (min_size == (1u << log_min_size)) + { + if (log_min_size == FieldT::s+1) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("* Selected domain: extended_radix2\n"); + } + result.reset(new extended_radix2_domain(min_size)); + } + else + { + if (!inhibit_profiling_info) + { + print_indent(); printf("* Selected domain: basic_radix2\n"); + } + result.reset(new basic_radix2_domain(min_size)); + } + } + else + { + const size_t big = 1ul<<(log2(min_size)-1); + const size_t small = min_size - big; + const size_t rounded_small = (1ul<(big + rounded_small)); + } + else + { + if (!inhibit_profiling_info) + { + print_indent(); printf("* Selected domain: extended_radix2\n"); + } + result.reset(new extended_radix2_domain(big + rounded_small)); + } + } + else + { + if (!inhibit_profiling_info) + { + print_indent(); printf("* Selected domain: step_radix2\n"); + } + result.reset(new step_radix2_domain(big + rounded_small)); + } + } + + return result; +} + +template +FieldT lagrange_eval(const size_t m, const std::vector &domain, const FieldT &t, const size_t idx) +{ + assert(m == domain.size()); + assert(idx < m); + + FieldT num = FieldT::one(); + FieldT denom = FieldT::one(); + + for (size_t k = 0; k < m; ++k) + { + if (k == idx) + { + continue; + } + + num *= t - domain[k]; + denom *= domain[idx] - domain[k]; + } + + return num * denom.inverse(); +} + +} // libsnark + +#endif // EVALUATION_DOMAIN_TCC_ diff --git a/privacy/zsl/zsl/algebra/exponentiation/exponentiation.hpp b/privacy/zsl/zsl/algebra/exponentiation/exponentiation.hpp new file mode 100644 index 0000000..a8a2c92 --- /dev/null +++ b/privacy/zsl/zsl/algebra/exponentiation/exponentiation.hpp @@ -0,0 +1,31 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for (square-and-multiply) exponentiation. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EXPONENTIATION_HPP_ +#define EXPONENTIATION_HPP_ + +#include + +#include "algebra/fields/bigint.hpp" + +namespace libsnark { + +template +FieldT power(const FieldT &base, const bigint &exponent); + +template +FieldT power(const FieldT &base, const unsigned long exponent); + +} // libsnark + +#include "algebra/exponentiation/exponentiation.tcc" + +#endif // EXPONENTIATION_HPP_ diff --git a/privacy/zsl/zsl/algebra/exponentiation/exponentiation.tcc b/privacy/zsl/zsl/algebra/exponentiation/exponentiation.tcc new file mode 100644 index 0000000..dd557eb --- /dev/null +++ b/privacy/zsl/zsl/algebra/exponentiation/exponentiation.tcc @@ -0,0 +1,53 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for (square-and-multiply) exponentiation. + + See exponentiation.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EXPONENTIATION_TCC_ +#define EXPONENTIATION_TCC_ + +#include "common/utils.hpp" + +namespace libsnark { + +template +FieldT power(const FieldT &base, const bigint &exponent) +{ + FieldT result = FieldT::one(); + + bool found_one = false; + + for (long i = exponent.max_bits() - 1; i >= 0; --i) + { + if (found_one) + { + result = result * result; + } + + if (exponent.test_bit(i)) + { + found_one = true; + result = result * base; + } + } + + return result; +} + +template +FieldT power(const FieldT &base, const unsigned long exponent) +{ + return power(base, bigint<1>(exponent)); +} + +} // libsnark + +#endif // EXPONENTIATION_TCC_ diff --git a/privacy/zsl/zsl/algebra/fields/bigint.hpp b/privacy/zsl/zsl/algebra/fields/bigint.hpp new file mode 100644 index 0000000..7331e9d --- /dev/null +++ b/privacy/zsl/zsl/algebra/fields/bigint.hpp @@ -0,0 +1,61 @@ +/** @file + ***************************************************************************** + Declaration of bigint wrapper class around GMP's MPZ long integers. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BIGINT_HPP_ +#define BIGINT_HPP_ +#include +#include +#include +#include "common/serialization.hpp" + +namespace libsnark { + +template class bigint; +template std::ostream& operator<<(std::ostream &, const bigint&); +template std::istream& operator>>(std::istream &, bigint&); + +/** + * Wrapper class around GMP's MPZ long integers. It supports arithmetic operations, + * serialization and randomization. Serialization is fragile, see common/serialization.hpp. + */ + +template +class bigint { +public: + static const mp_size_t N = n; + + mp_limb_t data[n] = {0}; + + bigint() = default; + bigint(const unsigned long x); /// Initalize from a small integer + bigint(const char* s); /// Initialize from a string containing an integer in decimal notation + bigint(const mpz_t r); /// Initialize from MPZ element + + void print() const; + void print_hex() const; + bool operator==(const bigint& other) const; + bool operator!=(const bigint& other) const; + void clear(); + bool is_zero() const; + size_t max_bits() const { return n * GMP_NUMB_BITS; } /// Returns the number of bits representable by this bigint type + size_t num_bits() const; /// Returns the number of bits in this specific bigint value, i.e., position of the most-significant 1 in binary + + unsigned long as_ulong() const; /// Return the last limb of the integer + void to_mpz(mpz_t r) const; + bool test_bit(const std::size_t bitno) const; + + bigint& randomize(); + + friend std::ostream& operator<< (std::ostream &out, const bigint &b); + friend std::istream& operator>> (std::istream &in, bigint &b); +}; + +} // libsnark +#include "algebra/fields/bigint.tcc" +#endif diff --git a/privacy/zsl/zsl/algebra/fields/bigint.tcc b/privacy/zsl/zsl/algebra/fields/bigint.tcc new file mode 100644 index 0000000..9db5d32 --- /dev/null +++ b/privacy/zsl/zsl/algebra/fields/bigint.tcc @@ -0,0 +1,222 @@ +/** @file + ***************************************************************************** + Implementation of bigint wrapper class around GMP's MPZ long integers. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BIGINT_TCC_ +#define BIGINT_TCC_ +#include +#include + +namespace libsnark { + +template +bigint::bigint(const unsigned long x) /// Initalize from a small integer +{ + assert(8*sizeof(x) <= GMP_NUMB_BITS); + this->data[0] = x; +} + +template +bigint::bigint(const char* s) /// Initialize from a string containing an integer in decimal notation +{ + size_t l = strlen(s); + unsigned char* s_copy = new unsigned char[l]; + + for (size_t i = 0; i < l; ++i) + { + assert(s[i] >= '0' && s[i] <= '9'); + s_copy[i] = s[i] - '0'; + } + + mp_size_t limbs_written = mpn_set_str(this->data, s_copy, l, 10); + assert(limbs_written <= n); + + delete[] s_copy; +} + +template +bigint::bigint(const mpz_t r) /// Initialize from MPZ element +{ + mpz_t k; + mpz_init_set(k, r); + + for (size_t i = 0; i < n; ++i) + { + data[i] = mpz_get_ui(k); + mpz_fdiv_q_2exp(k, k, GMP_NUMB_BITS); + } + + assert(mpz_sgn(k) == 0); + mpz_clear(k); +} + +template +void bigint::print() const +{ + gmp_printf("%Nd\n", this->data, n); +} + +template +void bigint::print_hex() const +{ + gmp_printf("%Nx\n", this->data, n); +} + +template +bool bigint::operator==(const bigint& other) const +{ + return (mpn_cmp(this->data, other.data, n) == 0); +} + +template +bool bigint::operator!=(const bigint& other) const +{ + return !(operator==(other)); +} + +template +void bigint::clear() +{ + mpn_zero(this->data, n); +} + +template +bool bigint::is_zero() const +{ + for (size_t i = 0; i < n; ++i) + { + if (this->data[i]) + { + return false; + } + } + + return true; +} + +template +size_t bigint::num_bits() const +{ +/* + for (long i = max_bits(); i >= 0; --i) + { + if (this->test_bit(i)) + { + return i+1; + } + } + + return 0; +*/ + for (long i = n-1; i >= 0; --i) + { + mp_limb_t x = this->data[i]; + if (x == 0) + { + continue; + } + else + { + return ((i+1) * GMP_NUMB_BITS) - __builtin_clzl(x); + } + } + return 0; +} + +template +unsigned long bigint::as_ulong() const +{ + return this->data[0]; +} + +template +void bigint::to_mpz(mpz_t r) const +{ + mpz_set_ui(r, 0); + + for (int i = n-1; i >= 0; --i) + { + mpz_mul_2exp(r, r, GMP_NUMB_BITS); + mpz_add_ui(r, r, this->data[i]); + } +} + +template +bool bigint::test_bit(const std::size_t bitno) const +{ + if (bitno >= n * GMP_NUMB_BITS) + { + return false; + } + else + { + const std::size_t part = bitno/GMP_NUMB_BITS; + const std::size_t bit = bitno - (GMP_NUMB_BITS*part); + const mp_limb_t one = 1; + return (this->data[part] & (one< +bigint& bigint::randomize() +{ + assert(GMP_NUMB_BITS == sizeof(mp_limb_t) * 8); + FILE *fp = fopen("/dev/urandom", "r"); //TODO Remove hard-coded use of /dev/urandom. + size_t bytes_read = fread(this->data, 1, sizeof(mp_limb_t) * n, fp); + assert(bytes_read == sizeof(mp_limb_t) * n); + fclose(fp); + + return (*this); +} + + +template +std::ostream& operator<<(std::ostream &out, const bigint &b) +{ +#ifdef BINARY_OUTPUT + out.write((char*)b.data, sizeof(b.data[0]) * n); +#else + mpz_t t; + mpz_init(t); + b.to_mpz(t); + + out << t; + + mpz_clear(t); +#endif + return out; +} + +template +std::istream& operator>>(std::istream &in, bigint &b) +{ +#ifdef BINARY_OUTPUT + in.read((char*)b.data, sizeof(b.data[0]) * n); +#else + std::string s; + in >> s; + + size_t l = s.size(); + unsigned char* s_copy = new unsigned char[l]; + + for (size_t i = 0; i < l; ++i) + { + assert(s[i] >= '0' && s[i] <= '9'); + s_copy[i] = s[i] - '0'; + } + + mp_size_t limbs_written = mpn_set_str(b.data, s_copy, l, 10); + assert(limbs_written <= n); + + delete[] s_copy; +#endif + return in; +} + +} // libsnark +#endif // BIGINT_TCC_ diff --git a/privacy/zsl/zsl/algebra/fields/field_utils.hpp b/privacy/zsl/zsl/algebra/fields/field_utils.hpp new file mode 100644 index 0000000..a07ecfe --- /dev/null +++ b/privacy/zsl/zsl/algebra/fields/field_utils.hpp @@ -0,0 +1,51 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FIELD_UTILS_HPP_ +#define FIELD_UTILS_HPP_ +#include + +#include "common/utils.hpp" +#include "algebra/fields/bigint.hpp" + +namespace libsnark { + +// returns root of unity of order n (for n a power of 2), if one exists +template +FieldT get_root_of_unity(const size_t n); + +template +std::vector pack_int_vector_into_field_element_vector(const std::vector &v, const size_t w); + +template +std::vector pack_bit_vector_into_field_element_vector(const bit_vector &v, const size_t chunk_bits); + +template +std::vector pack_bit_vector_into_field_element_vector(const bit_vector &v); + +template +std::vector convert_bit_vector_to_field_element_vector(const bit_vector &v); + +template +bit_vector convert_field_element_vector_to_bit_vector(const std::vector &v); + +template +bit_vector convert_field_element_to_bit_vector(const FieldT &el); + +template +bit_vector convert_field_element_to_bit_vector(const FieldT &el, const size_t bitcount); + +template +FieldT convert_bit_vector_to_field_element(const bit_vector &v); + +template +void batch_invert(std::vector &vec); + +} // libsnark +#include "algebra/fields/field_utils.tcc" + +#endif // FIELD_UTILS_HPP_ diff --git a/privacy/zsl/zsl/algebra/fields/field_utils.tcc b/privacy/zsl/zsl/algebra/fields/field_utils.tcc new file mode 100644 index 0000000..13197b2 --- /dev/null +++ b/privacy/zsl/zsl/algebra/fields/field_utils.tcc @@ -0,0 +1,183 @@ +/** @file + ***************************************************************************** + Implementation of misc. math and serialization utility functions + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FIELD_UTILS_TCC_ +#define FIELD_UTILS_TCC_ + +#include "common/utils.hpp" + +namespace libsnark { + +template +FieldT coset_shift() +{ + return FieldT::multiplicative_generator.squared(); +} + +template +FieldT get_root_of_unity(const size_t n) +{ + const size_t logn = log2(n); + assert(n == (1u << logn)); + assert(logn <= FieldT::s); + + FieldT omega = FieldT::root_of_unity; + for (size_t i = FieldT::s; i > logn; --i) + { + omega *= omega; + } + + return omega; +} + +template +std::vector pack_int_vector_into_field_element_vector(const std::vector &v, const size_t w) +{ + const size_t chunk_bits = FieldT::capacity(); + const size_t repacked_size = div_ceil(v.size() * w, chunk_bits); + std::vector result(repacked_size); + + for (size_t i = 0; i < repacked_size; ++i) + { + bigint b; + for (size_t j = 0; j < chunk_bits; ++j) + { + const size_t word_index = (i * chunk_bits + j) / w; + const size_t pos_in_word = (i * chunk_bits + j) % w; + const size_t word_or_0 = (word_index < v.size() ? v[word_index] : 0); + const size_t bit = (word_or_0 >> pos_in_word) & 1; + + b.data[j / GMP_NUMB_BITS] |= bit << (j % GMP_NUMB_BITS); + } + result[i] = FieldT(b); + } + + return result; +} + +template +std::vector pack_bit_vector_into_field_element_vector(const bit_vector &v, const size_t chunk_bits) +{ + assert(chunk_bits <= FieldT::capacity()); + + const size_t repacked_size = div_ceil(v.size(), chunk_bits); + std::vector result(repacked_size); + + for (size_t i = 0; i < repacked_size; ++i) + { + bigint b; + for (size_t j = 0; j < chunk_bits; ++j) + { + b.data[j / GMP_NUMB_BITS] |= ((i * chunk_bits + j) < v.size() && v[i * chunk_bits + j] ? 1ll : 0ll) << (j % GMP_NUMB_BITS); + } + result[i] = FieldT(b); + } + + return result; +} + +template +std::vector pack_bit_vector_into_field_element_vector(const bit_vector &v) +{ + return pack_bit_vector_into_field_element_vector(v, FieldT::capacity()); +} + +template +std::vector convert_bit_vector_to_field_element_vector(const bit_vector &v) +{ + std::vector result; + result.reserve(v.size()); + + for (const bool b : v) + { + result.emplace_back(b ? FieldT::one() : FieldT::zero()); + } + + return result; +} + +template +bit_vector convert_field_element_vector_to_bit_vector(const std::vector &v) +{ + bit_vector result; + + for (const FieldT &el : v) + { + const bit_vector el_bits = convert_field_element_to_bit_vector(el); + result.insert(result.end(), el_bits.begin(), el_bits.end()); + } + + return result; +} + +template +bit_vector convert_field_element_to_bit_vector(const FieldT &el) +{ + bit_vector result; + + bigint b = el.as_bigint(); + for (size_t i = 0; i < FieldT::size_in_bits(); ++i) + { + result.push_back(b.test_bit(i)); + } + + return result; +} + +template +bit_vector convert_field_element_to_bit_vector(const FieldT &el, const size_t bitcount) +{ + bit_vector result = convert_field_element_to_bit_vector(el); + result.resize(bitcount); + + return result; +} + +template +FieldT convert_bit_vector_to_field_element(const bit_vector &v) +{ + assert(v.size() <= FieldT::size_in_bits()); + + FieldT res = FieldT::zero(); + FieldT c = FieldT::one(); + for (bool b : v) + { + res += b ? c : FieldT::zero(); + c += c; + } + return res; +} + +template +void batch_invert(std::vector &vec) +{ + std::vector prod; + prod.reserve(vec.size()); + + FieldT acc = FieldT::one(); + + for (auto el : vec) + { + assert(!el.is_zero()); + prod.emplace_back(acc); + acc = acc * el; + } + + FieldT acc_inverse = acc.inverse(); + + for (long i = vec.size()-1; i >= 0; --i) + { + const FieldT old_el = vec[i]; + vec[i] = acc_inverse * prod[i]; + acc_inverse = acc_inverse * old_el; + } +} + +} // libsnark +#endif // FIELD_UTILS_TCC_ diff --git a/privacy/zsl/zsl/algebra/fields/fp.hpp b/privacy/zsl/zsl/algebra/fields/fp.hpp new file mode 100644 index 0000000..a498683 --- /dev/null +++ b/privacy/zsl/zsl/algebra/fields/fp.hpp @@ -0,0 +1,182 @@ +/** @file + ***************************************************************************** + Declaration of arithmetic in the finite field F[p], for prime p of fixed length. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP_HPP_ +#define FP_HPP_ + +#include "algebra/fields/bigint.hpp" +#include "algebra/exponentiation/exponentiation.hpp" + +namespace libsnark { + +template& modulus> +class Fp_model; + +template& modulus> +std::ostream& operator<<(std::ostream &, const Fp_model&); + +template& modulus> +std::istream& operator>>(std::istream &, Fp_model &); + +/** + * Arithmetic in the finite field F[p], for prime p of fixed length. + * + * This class implements Fp-arithmetic, for a large prime p, using a fixed number + * of words. It is optimized for tight memory consumption, so the modulus p is + * passed as a template parameter, to avoid per-element overheads. + * + * The implementation is mostly a wrapper around GMP's MPN (constant-size integers). + * But for the integer sizes of interest for libsnark (3 to 5 limbs of 64 bits each), + * we implement performance-critical routines, like addition and multiplication, + * using hand-optimzied assembly code. +*/ +template& modulus> +class Fp_model { +public: + bigint mont_repr; +public: + static const mp_size_t num_limbs = n; + static const constexpr bigint& mod = modulus; +#ifdef PROFILE_OP_COUNTS + static long long add_cnt; + static long long sub_cnt; + static long long mul_cnt; + static long long sqr_cnt; + static long long inv_cnt; +#endif + static size_t num_bits; + static bigint euler; // (modulus-1)/2 + static size_t s; // modulus = 2^s * t + 1 + static bigint t; // with t odd + static bigint t_minus_1_over_2; // (t-1)/2 + static Fp_model nqr; // a quadratic nonresidue + static Fp_model nqr_to_t; // nqr^t + static Fp_model multiplicative_generator; // generator of Fp^* + static Fp_model root_of_unity; // generator^((modulus-1)/2^s) + static mp_limb_t inv; // modulus^(-1) mod W, where W = 2^(word size) + static bigint Rsquared; // R^2, where R = W^k, where k = ?? + static bigint Rcubed; // R^3 + + static bool modulus_is_valid() { return modulus.data[n-1] != 0; } // mpn inverse assumes that highest limb is non-zero + + Fp_model() {}; + Fp_model(const bigint &b); + Fp_model(const long x, const bool is_unsigned=false); + + void set_ulong(const unsigned long x); + + void mul_reduce(const bigint &other); + + void clear(); + + /* Return the standard (not Montgomery) representation of the + Field element's requivalence class. I.e. Fp(2).as_bigint() + would return bigint(2) */ + bigint as_bigint() const; + /* Return the last limb of the standard representation of the + field element. E.g. on 64-bit architectures Fp(123).as_ulong() + and Fp(2^64+123).as_ulong() would both return 123. */ + unsigned long as_ulong() const; + + bool operator==(const Fp_model& other) const; + bool operator!=(const Fp_model& other) const; + bool is_zero() const; + + void print() const; + + Fp_model& operator+=(const Fp_model& other); + Fp_model& operator-=(const Fp_model& other); + Fp_model& operator*=(const Fp_model& other); + Fp_model& operator^=(const unsigned long pow); + + template + Fp_model& operator^=(const bigint &pow); + + Fp_model operator+(const Fp_model& other) const; + Fp_model operator-(const Fp_model& other) const; + Fp_model operator*(const Fp_model& other) const; + Fp_model operator-() const; + Fp_model squared() const; + Fp_model& invert(); + Fp_model inverse() const; + Fp_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate) + + Fp_model operator^(const unsigned long pow) const; + template + Fp_model operator^(const bigint &pow) const; + + static size_t size_in_bits() { return num_bits; } + static size_t capacity() { return num_bits - 1; } + static bigint field_char() { return modulus; } + + static Fp_model zero(); + static Fp_model one(); + static Fp_model random_element(); + + friend std::ostream& operator<< (std::ostream &out, const Fp_model &p); + friend std::istream& operator>> (std::istream &in, Fp_model &p); +}; + +#ifdef PROFILE_OP_COUNTS +template& modulus> +long long Fp_model::add_cnt = 0; + +template& modulus> +long long Fp_model::sub_cnt = 0; + +template& modulus> +long long Fp_model::mul_cnt = 0; + +template& modulus> +long long Fp_model::sqr_cnt = 0; + +template& modulus> +long long Fp_model::inv_cnt = 0; +#endif + +template& modulus> +size_t Fp_model::num_bits; + +template& modulus> +bigint Fp_model::euler; + +template& modulus> +size_t Fp_model::s; + +template& modulus> +bigint Fp_model::t; + +template& modulus> +bigint Fp_model::t_minus_1_over_2; + +template& modulus> +Fp_model Fp_model::nqr; + +template& modulus> +Fp_model Fp_model::nqr_to_t; + +template& modulus> +Fp_model Fp_model::multiplicative_generator; + +template& modulus> +Fp_model Fp_model::root_of_unity; + +template& modulus> +mp_limb_t Fp_model::inv; + +template& modulus> +bigint Fp_model::Rsquared; + +template& modulus> +bigint Fp_model::Rcubed; + +} // libsnark +#include "algebra/fields/fp.tcc" + +#endif // FP_HPP_ diff --git a/privacy/zsl/zsl/algebra/fields/fp.tcc b/privacy/zsl/zsl/algebra/fields/fp.tcc new file mode 100644 index 0000000..35fd3ac --- /dev/null +++ b/privacy/zsl/zsl/algebra/fields/fp.tcc @@ -0,0 +1,785 @@ +/** @file + ***************************************************************************** + Implementation of arithmetic in the finite field F[p], for prime p of fixed length. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP_TCC_ +#define FP_TCC_ +#include +#include +#include + +#include "algebra/fields/fp_aux.tcc" +#include "algebra/fields/field_utils.hpp" + +namespace libsnark { + +template& modulus> +void Fp_model::mul_reduce(const bigint &other) +{ + /* stupid pre-processor tricks; beware */ +#if defined(__x86_64__) && defined(USE_ASM) + if (n == 3) + { // Use asm-optimized Comba multiplication and reduction + mp_limb_t res[2*n]; + mp_limb_t c0, c1, c2; + COMBA_3_BY_3_MUL(c0, c1, c2, res, this->mont_repr.data, other.data); + + mp_limb_t k; + mp_limb_t tmp1, tmp2, tmp3; + REDUCE_6_LIMB_PRODUCT(k, tmp1, tmp2, tmp3, inv, res, modulus.data); + + /* subtract t > mod */ + __asm__ + ("/* check for overflow */ \n\t" + MONT_CMP(16) + MONT_CMP(8) + MONT_CMP(0) + + "/* subtract mod if overflow */ \n\t" + "subtract%=: \n\t" + MONT_FIRSTSUB + MONT_NEXTSUB(8) + MONT_NEXTSUB(16) + "done%=: \n\t" + : + : [tmp] "r" (res+n), [M] "r" (modulus.data) + : "cc", "memory", "%rax"); + mpn_copyi(this->mont_repr.data, res+n, n); + } + else if (n == 4) + { // use asm-optimized "CIOS method" + + mp_limb_t tmp[n+1]; + mp_limb_t T0=0, T1=1, cy=2, u=3; // TODO: fix this + + __asm__ (MONT_PRECOMPUTE + MONT_FIRSTITER(1) + MONT_FIRSTITER(2) + MONT_FIRSTITER(3) + MONT_FINALIZE(3) + MONT_ITERFIRST(1) + MONT_ITERITER(1, 1) + MONT_ITERITER(1, 2) + MONT_ITERITER(1, 3) + MONT_FINALIZE(3) + MONT_ITERFIRST(2) + MONT_ITERITER(2, 1) + MONT_ITERITER(2, 2) + MONT_ITERITER(2, 3) + MONT_FINALIZE(3) + MONT_ITERFIRST(3) + MONT_ITERITER(3, 1) + MONT_ITERITER(3, 2) + MONT_ITERITER(3, 3) + MONT_FINALIZE(3) + "/* check for overflow */ \n\t" + MONT_CMP(24) + MONT_CMP(16) + MONT_CMP(8) + MONT_CMP(0) + + "/* subtract mod if overflow */ \n\t" + "subtract%=: \n\t" + MONT_FIRSTSUB + MONT_NEXTSUB(8) + MONT_NEXTSUB(16) + MONT_NEXTSUB(24) + "done%=: \n\t" + : + : [tmp] "r" (tmp), [A] "r" (this->mont_repr.data), [B] "r" (other.data), [inv] "r" (inv), [M] "r" (modulus.data), + [T0] "r" (T0), [T1] "r" (T1), [cy] "r" (cy), [u] "r" (u) + : "cc", "memory", "%rax", "%rdx" + ); + mpn_copyi(this->mont_repr.data, tmp, n); + } + else if (n == 5) + { // use asm-optimized "CIOS method" + + mp_limb_t tmp[n+1]; + mp_limb_t T0=0, T1=1, cy=2, u=3; // TODO: fix this + + __asm__ (MONT_PRECOMPUTE + MONT_FIRSTITER(1) + MONT_FIRSTITER(2) + MONT_FIRSTITER(3) + MONT_FIRSTITER(4) + MONT_FINALIZE(4) + MONT_ITERFIRST(1) + MONT_ITERITER(1, 1) + MONT_ITERITER(1, 2) + MONT_ITERITER(1, 3) + MONT_ITERITER(1, 4) + MONT_FINALIZE(4) + MONT_ITERFIRST(2) + MONT_ITERITER(2, 1) + MONT_ITERITER(2, 2) + MONT_ITERITER(2, 3) + MONT_ITERITER(2, 4) + MONT_FINALIZE(4) + MONT_ITERFIRST(3) + MONT_ITERITER(3, 1) + MONT_ITERITER(3, 2) + MONT_ITERITER(3, 3) + MONT_ITERITER(3, 4) + MONT_FINALIZE(4) + MONT_ITERFIRST(4) + MONT_ITERITER(4, 1) + MONT_ITERITER(4, 2) + MONT_ITERITER(4, 3) + MONT_ITERITER(4, 4) + MONT_FINALIZE(4) + "/* check for overflow */ \n\t" + MONT_CMP(32) + MONT_CMP(24) + MONT_CMP(16) + MONT_CMP(8) + MONT_CMP(0) + + "/* subtract mod if overflow */ \n\t" + "subtract%=: \n\t" + MONT_FIRSTSUB + MONT_NEXTSUB(8) + MONT_NEXTSUB(16) + MONT_NEXTSUB(24) + MONT_NEXTSUB(32) + "done%=: \n\t" + : + : [tmp] "r" (tmp), [A] "r" (this->mont_repr.data), [B] "r" (other.data), [inv] "r" (inv), [M] "r" (modulus.data), + [T0] "r" (T0), [T1] "r" (T1), [cy] "r" (cy), [u] "r" (u) + : "cc", "memory", "%rax", "%rdx" + ); + mpn_copyi(this->mont_repr.data, tmp, n); + } + else +#endif + { + mp_limb_t res[2*n]; + mpn_mul_n(res, this->mont_repr.data, other.data, n); + + /* + The Montgomery reduction here is based on Algorithm 14.32 in + Handbook of Applied Cryptography + . + */ + for (size_t i = 0; i < n; ++i) + { + mp_limb_t k = inv * res[i]; + /* calculate res = res + k * mod * b^i */ + mp_limb_t carryout = mpn_addmul_1(res+i, modulus.data, n, k); + carryout = mpn_add_1(res+n+i, res+n+i, n-i, carryout); + assert(carryout == 0); + } + + if (mpn_cmp(res+n, modulus.data, n) >= 0) + { + const mp_limb_t borrow = mpn_sub(res+n, res+n, n, modulus.data, n); + assert(borrow == 0); + } + + mpn_copyi(this->mont_repr.data, res+n, n); + } +} + +template& modulus> +Fp_model::Fp_model(const bigint &b) +{ + mpn_copyi(this->mont_repr.data, Rsquared.data, n); + mul_reduce(b); +} + +template& modulus> +Fp_model::Fp_model(const long x, const bool is_unsigned) +{ + if (is_unsigned || x >= 0) + { + this->mont_repr.data[0] = (mp_limb_t)x; + } + else + { + const mp_limb_t borrow = mpn_sub_1(this->mont_repr.data, modulus.data, n, (mp_limb_t)-x); + assert(borrow == 0); + } + + mul_reduce(Rsquared); +} + +template& modulus> +void Fp_model::set_ulong(const unsigned long x) +{ + this->mont_repr.clear(); + this->mont_repr.data[0] = x; + mul_reduce(Rsquared); +} + +template& modulus> +void Fp_model::clear() +{ + this->mont_repr.clear(); +} + +template& modulus> +bigint Fp_model::as_bigint() const +{ + bigint one; + one.clear(); + one.data[0] = 1; + + Fp_model res(*this); + res.mul_reduce(one); + + return (res.mont_repr); +} + +template& modulus> +unsigned long Fp_model::as_ulong() const +{ + return this->as_bigint().as_ulong(); +} + +template& modulus> +bool Fp_model::operator==(const Fp_model& other) const +{ + return (this->mont_repr == other.mont_repr); +} + +template& modulus> +bool Fp_model::operator!=(const Fp_model& other) const +{ + return (this->mont_repr != other.mont_repr); +} + +template& modulus> +bool Fp_model::is_zero() const +{ + return (this->mont_repr.is_zero()); // zero maps to zero +} + +template& modulus> +void Fp_model::print() const +{ + Fp_model tmp; + tmp.mont_repr.data[0] = 1; + tmp.mul_reduce(this->mont_repr); + + tmp.mont_repr.print(); +} + +template& modulus> +Fp_model Fp_model::zero() +{ + Fp_model res; + res.mont_repr.clear(); + return res; +} + +template& modulus> +Fp_model Fp_model::one() +{ + Fp_model res; + res.mont_repr.data[0] = 1; + res.mul_reduce(Rsquared); + return res; +} + +template& modulus> +Fp_model& Fp_model::operator+=(const Fp_model& other) +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif +#if defined(__x86_64__) && defined(USE_ASM) + if (n == 3) + { + __asm__ + ("/* perform bignum addition */ \n\t" + ADD_FIRSTADD + ADD_NEXTADD(8) + ADD_NEXTADD(16) + "/* if overflow: subtract */ \n\t" + "/* (tricky point: if A and B are in the range we do not need to do anything special for the possible carry flag) */ \n\t" + "jc subtract%= \n\t" + + "/* check for overflow */ \n\t" + ADD_CMP(16) + ADD_CMP(8) + ADD_CMP(0) + + "/* subtract mod if overflow */ \n\t" + "subtract%=: \n\t" + ADD_FIRSTSUB + ADD_NEXTSUB(8) + ADD_NEXTSUB(16) + "done%=: \n\t" + : + : [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data) + : "cc", "memory", "%rax"); + } + else if (n == 4) + { + __asm__ + ("/* perform bignum addition */ \n\t" + ADD_FIRSTADD + ADD_NEXTADD(8) + ADD_NEXTADD(16) + ADD_NEXTADD(24) + "/* if overflow: subtract */ \n\t" + "/* (tricky point: if A and B are in the range we do not need to do anything special for the possible carry flag) */ \n\t" + "jc subtract%= \n\t" + + "/* check for overflow */ \n\t" + ADD_CMP(24) + ADD_CMP(16) + ADD_CMP(8) + ADD_CMP(0) + + "/* subtract mod if overflow */ \n\t" + "subtract%=: \n\t" + ADD_FIRSTSUB + ADD_NEXTSUB(8) + ADD_NEXTSUB(16) + ADD_NEXTSUB(24) + "done%=: \n\t" + : + : [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data) + : "cc", "memory", "%rax"); + } + else if (n == 5) + { + __asm__ + ("/* perform bignum addition */ \n\t" + ADD_FIRSTADD + ADD_NEXTADD(8) + ADD_NEXTADD(16) + ADD_NEXTADD(24) + ADD_NEXTADD(32) + "/* if overflow: subtract */ \n\t" + "/* (tricky point: if A and B are in the range we do not need to do anything special for the possible carry flag) */ \n\t" + "jc subtract%= \n\t" + + "/* check for overflow */ \n\t" + ADD_CMP(32) + ADD_CMP(24) + ADD_CMP(16) + ADD_CMP(8) + ADD_CMP(0) + + "/* subtract mod if overflow */ \n\t" + "subtract%=: \n\t" + ADD_FIRSTSUB + ADD_NEXTSUB(8) + ADD_NEXTSUB(16) + ADD_NEXTSUB(24) + ADD_NEXTSUB(32) + "done%=: \n\t" + : + : [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data) + : "cc", "memory", "%rax"); + } + else +#endif + { + mp_limb_t scratch[n+1]; + const mp_limb_t carry = mpn_add_n(scratch, this->mont_repr.data, other.mont_repr.data, n); + scratch[n] = carry; + + if (carry || mpn_cmp(scratch, modulus.data, n) >= 0) + { + const mp_limb_t borrow = mpn_sub(scratch, scratch, n+1, modulus.data, n); + assert(borrow == 0); + } + + mpn_copyi(this->mont_repr.data, scratch, n); + } + + return *this; +} + +template& modulus> +Fp_model& Fp_model::operator-=(const Fp_model& other) +{ +#ifdef PROFILE_OP_COUNTS + this->sub_cnt++; +#endif +#if defined(__x86_64__) && defined(USE_ASM) + if (n == 3) + { + __asm__ + (SUB_FIRSTSUB + SUB_NEXTSUB(8) + SUB_NEXTSUB(16) + + "jnc done%=\n\t" + + SUB_FIRSTADD + SUB_NEXTADD(8) + SUB_NEXTADD(16) + + "done%=:\n\t" + : + : [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data) + : "cc", "memory", "%rax"); + } + else if (n == 4) + { + __asm__ + (SUB_FIRSTSUB + SUB_NEXTSUB(8) + SUB_NEXTSUB(16) + SUB_NEXTSUB(24) + + "jnc done%=\n\t" + + SUB_FIRSTADD + SUB_NEXTADD(8) + SUB_NEXTADD(16) + SUB_NEXTADD(24) + + "done%=:\n\t" + : + : [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data) + : "cc", "memory", "%rax"); + } + else if (n == 5) + { + __asm__ + (SUB_FIRSTSUB + SUB_NEXTSUB(8) + SUB_NEXTSUB(16) + SUB_NEXTSUB(24) + SUB_NEXTSUB(32) + + "jnc done%=\n\t" + + SUB_FIRSTADD + SUB_NEXTADD(8) + SUB_NEXTADD(16) + SUB_NEXTADD(24) + SUB_NEXTADD(32) + + "done%=:\n\t" + : + : [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data) + : "cc", "memory", "%rax"); + } + else +#endif + { + mp_limb_t scratch[n+1]; + if (mpn_cmp(this->mont_repr.data, other.mont_repr.data, n) < 0) + { + const mp_limb_t carry = mpn_add_n(scratch, this->mont_repr.data, modulus.data, n); + scratch[n] = carry; + } + else + { + mpn_copyi(scratch, this->mont_repr.data, n); + scratch[n] = 0; + } + + const mp_limb_t borrow = mpn_sub(scratch, scratch, n+1, other.mont_repr.data, n); + assert(borrow == 0); + + mpn_copyi(this->mont_repr.data, scratch, n); + } + return *this; +} + +template& modulus> +Fp_model& Fp_model::operator*=(const Fp_model& other) +{ +#ifdef PROFILE_OP_COUNTS + this->mul_cnt++; +#endif + + mul_reduce(other.mont_repr); + return *this; +} + +template& modulus> +Fp_model& Fp_model::operator^=(const unsigned long pow) +{ + (*this) = power >(*this, pow); + return (*this); +} + +template& modulus> +template +Fp_model& Fp_model::operator^=(const bigint &pow) +{ + (*this) = power, m>(*this, pow); + return (*this); +} + +template& modulus> +Fp_model Fp_model::operator+(const Fp_model& other) const +{ + Fp_model r(*this); + return (r += other); +} + +template& modulus> +Fp_model Fp_model::operator-(const Fp_model& other) const +{ + Fp_model r(*this); + return (r -= other); +} + +template& modulus> +Fp_model Fp_model::operator*(const Fp_model& other) const +{ + Fp_model r(*this); + return (r *= other); +} + +template& modulus> +Fp_model Fp_model::operator^(const unsigned long pow) const +{ + Fp_model r(*this); + return (r ^= pow); +} + +template& modulus> +template +Fp_model Fp_model::operator^(const bigint &pow) const +{ + Fp_model r(*this); + return (r ^= pow); +} + +template& modulus> +Fp_model Fp_model::operator-() const +{ +#ifdef PROFILE_OP_COUNTS + this->sub_cnt++; +#endif + + if (this->is_zero()) + { + return (*this); + } + else + { + Fp_model r; + mpn_sub_n(r.mont_repr.data, modulus.data, this->mont_repr.data, n); + return r; + } +} + +template& modulus> +Fp_model Fp_model::squared() const +{ +#ifdef PROFILE_OP_COUNTS + this->sqr_cnt++; + this->mul_cnt--; // zero out the upcoming mul +#endif + /* stupid pre-processor tricks; beware */ +#if defined(__x86_64__) && defined(USE_ASM) + if (n == 3) + { // use asm-optimized Comba squaring + mp_limb_t res[2*n]; + mp_limb_t c0, c1, c2; + COMBA_3_BY_3_SQR(c0, c1, c2, res, this->mont_repr.data); + + mp_limb_t k; + mp_limb_t tmp1, tmp2, tmp3; + REDUCE_6_LIMB_PRODUCT(k, tmp1, tmp2, tmp3, inv, res, modulus.data); + + /* subtract t > mod */ + __asm__ volatile + ("/* check for overflow */ \n\t" + MONT_CMP(16) + MONT_CMP(8) + MONT_CMP(0) + + "/* subtract mod if overflow */ \n\t" + "subtract%=: \n\t" + MONT_FIRSTSUB + MONT_NEXTSUB(8) + MONT_NEXTSUB(16) + "done%=: \n\t" + : + : [tmp] "r" (res+n), [M] "r" (modulus.data) + : "cc", "memory", "%rax"); + + Fp_model r; + mpn_copyi(r.mont_repr.data, res+n, n); + return r; + } + else +#endif + { + Fp_model r(*this); + return (r *= r); + } +} + +template& modulus> +Fp_model& Fp_model::invert() +{ +#ifdef PROFILE_OP_COUNTS + this->inv_cnt++; +#endif + + assert(!this->is_zero()); + + bigint g; /* gp should have room for vn = n limbs */ + + mp_limb_t s[n+1]; /* sp should have room for vn+1 limbs */ + mp_size_t sn; + + bigint v = modulus; // both source operands are destroyed by mpn_gcdext + + /* computes gcd(u, v) = g = u*s + v*t, so s*u will be 1 (mod v) */ + const mp_size_t gn = mpn_gcdext(g.data, s, &sn, this->mont_repr.data, n, v.data, n); + assert(gn == 1 && g.data[0] == 1); /* inverse exists */ + + mp_limb_t q; /* division result fits into q, as sn <= n+1 */ + /* sn < 0 indicates negative sn; will fix up later */ + + if (std::abs(sn) >= n) + { + /* if sn could require modulus reduction, do it here */ + mpn_tdiv_qr(&q, this->mont_repr.data, 0, s, std::abs(sn), modulus.data, n); + } + else + { + /* otherwise just copy it over */ + mpn_zero(this->mont_repr.data, n); + mpn_copyi(this->mont_repr.data, s, std::abs(sn)); + } + + /* fix up the negative sn */ + if (sn < 0) + { + const mp_limb_t borrow = mpn_sub_n(this->mont_repr.data, modulus.data, this->mont_repr.data, n); + assert(borrow == 0); + } + + mul_reduce(Rcubed); + return *this; +} + +template& modulus> +Fp_model Fp_model::inverse() const +{ + Fp_model r(*this); + return (r.invert()); +} + +template& modulus> +Fp_model Fp_model::random_element() /// returns random element of Fp_model +{ + /* note that as Montgomery representation is a bijection then + selecting a random element of {xR} is the same as selecting a + random element of {x} */ + Fp_model r; + do + { + r.mont_repr.randomize(); + + /* clear all bits higher than MSB of modulus */ + size_t bitno = GMP_NUMB_BITS * n - 1; + while (modulus.test_bit(bitno) == false) + { + const std::size_t part = bitno/GMP_NUMB_BITS; + const std::size_t bit = bitno - (GMP_NUMB_BITS*part); + + r.mont_repr.data[part] &= ~(1ul<= modulus -- repeat (rejection sampling) */ + while (mpn_cmp(r.mont_repr.data, modulus.data, n) >= 0); + + return r; +} + +template& modulus> +Fp_model Fp_model::sqrt() const +{ + Fp_model one = Fp_model::one(); + + size_t v = Fp_model::s; + Fp_model z = Fp_model::nqr_to_t; + Fp_model w = (*this)^Fp_model::t_minus_1_over_2; + Fp_model x = (*this) * w; + Fp_model b = x * w; // b = (*this)^t + +#if DEBUG + // check if square with euler's criterion + Fp_model check = b; + for (size_t i = 0; i < v-1; ++i) + { + check = check.squared(); + } + if (check != one) + { + assert(0); + } +#endif + + // compute square root with Tonelli--Shanks + // (does not terminate if not a square!) + + while (b != one) + { + size_t m = 0; + Fp_model b2m = b; + while (b2m != one) + { + /* invariant: b2m = b^(2^m) after entering this loop */ + b2m = b2m.squared(); + m += 1; + } + + int j = v-m-1; + w = z; + while (j > 0) + { + w = w.squared(); + --j; + } // w = z^2^(v-m-1) + + z = w.squared(); + b = b * z; + x = x * w; + v = m; + } + + return x; +} + +template& modulus> +std::ostream& operator<<(std::ostream &out, const Fp_model &p) +{ +#ifndef MONTGOMERY_OUTPUT + Fp_model tmp; + tmp.mont_repr.data[0] = 1; + tmp.mul_reduce(p.mont_repr); + out << tmp.mont_repr; +#else + out << p.mont_repr; +#endif + return out; +} + +template& modulus> +std::istream& operator>>(std::istream &in, Fp_model &p) +{ +#ifndef MONTGOMERY_OUTPUT + in >> p.mont_repr; + p.mul_reduce(Fp_model::Rsquared); +#else + in >> p.mont_repr; +#endif + return in; +} + +} // libsnark +#endif // FP_TCC_ diff --git a/privacy/zsl/zsl/algebra/fields/fp12_2over3over2.hpp b/privacy/zsl/zsl/algebra/fields/fp12_2over3over2.hpp new file mode 100644 index 0000000..1de9d88 --- /dev/null +++ b/privacy/zsl/zsl/algebra/fields/fp12_2over3over2.hpp @@ -0,0 +1,116 @@ +/** @file + ***************************************************************************** + Declaration of arithmetic in the finite field F[((p^2)^3)^2]. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP12_2OVER3OVER2_HPP_ +#define FP12_2OVER3OVER2_HPP_ +#include "algebra/fields/fp.hpp" +#include "algebra/fields/fp2.hpp" +#include "algebra/fields/fp6_3over2.hpp" +#include + +namespace libsnark { + +template& modulus> +class Fp12_2over3over2_model; + +template& modulus> +std::ostream& operator<<(std::ostream &, const Fp12_2over3over2_model &); + +template& modulus> +std::istream& operator>>(std::istream &, Fp12_2over3over2_model &); + +/** + * Arithmetic in the finite field F[((p^2)^3)^2]. + * + * Let p := modulus. This interface provides arithmetic for the extension field + * Fp12 = Fp6[W]/(W^2-V) where Fp6 = Fp2[V]/(V^3-non_residue) and non_residue is in Fp2 + * + * ASSUMPTION: p = 1 (mod 6) + */ +template& modulus> +class Fp12_2over3over2_model { +public: + typedef Fp_model my_Fp; + typedef Fp2_model my_Fp2; + typedef Fp6_3over2_model my_Fp6; + + static Fp2_model non_residue; + static Fp2_model Frobenius_coeffs_c1[12]; // non_residue^((modulus^i-1)/6) for i=0,...,11 + + my_Fp6 c0, c1; + Fp12_2over3over2_model() {}; + Fp12_2over3over2_model(const my_Fp6& c0, const my_Fp6& c1) : c0(c0), c1(c1) {}; + + void clear() { c0.clear(); c1.clear(); } + void print() const { printf("c0/c1:\n"); c0.print(); c1.print(); } + + static Fp12_2over3over2_model zero(); + static Fp12_2over3over2_model one(); + static Fp12_2over3over2_model random_element(); + + bool is_zero() const { return c0.is_zero() && c1.is_zero(); } + bool operator==(const Fp12_2over3over2_model &other) const; + bool operator!=(const Fp12_2over3over2_model &other) const; + + Fp12_2over3over2_model operator+(const Fp12_2over3over2_model &other) const; + Fp12_2over3over2_model operator-(const Fp12_2over3over2_model &other) const; + Fp12_2over3over2_model operator*(const Fp12_2over3over2_model &other) const; + Fp12_2over3over2_model operator-() const; + Fp12_2over3over2_model squared() const; // default is squared_complex + Fp12_2over3over2_model squared_karatsuba() const; + Fp12_2over3over2_model squared_complex() const; + Fp12_2over3over2_model inverse() const; + Fp12_2over3over2_model Frobenius_map(unsigned long power) const; + Fp12_2over3over2_model unitary_inverse() const; + Fp12_2over3over2_model cyclotomic_squared() const; + + Fp12_2over3over2_model mul_by_024(const my_Fp2 &ell_0, const my_Fp2 &ell_VW, const my_Fp2 &ell_VV) const; + + static my_Fp6 mul_by_non_residue(const my_Fp6 &elt); + + template + Fp12_2over3over2_model cyclotomic_exp(const bigint &exponent) const; + + static bigint base_field_char() { return modulus; } + static size_t extension_degree() { return 12; } + + friend std::ostream& operator<< (std::ostream &out, const Fp12_2over3over2_model &el); + friend std::istream& operator>> (std::istream &in, Fp12_2over3over2_model &el); +}; + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v); + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v); + +template& modulus> +Fp12_2over3over2_model operator*(const Fp_model &lhs, const Fp12_2over3over2_model &rhs); + +template& modulus> +Fp12_2over3over2_model operator*(const Fp2_model &lhs, const Fp12_2over3over2_model &rhs); + +template& modulus> +Fp12_2over3over2_model operator*(const Fp6_3over2_model &lhs, const Fp12_2over3over2_model &rhs); + +template& modulus, mp_size_t m> +Fp12_2over3over2_model operator^(const Fp12_2over3over2_model &self, const bigint &exponent); + +template& modulus, mp_size_t m, const bigint& exp_modulus> +Fp12_2over3over2_model operator^(const Fp12_2over3over2_model &self, const Fp_model &exponent); + +template& modulus> +Fp2_model Fp12_2over3over2_model::non_residue; + +template& modulus> +Fp2_model Fp12_2over3over2_model::Frobenius_coeffs_c1[12]; + +} // libsnark +#include "algebra/fields/fp12_2over3over2.tcc" +#endif // FP12_2OVER3OVER2_HPP_ diff --git a/privacy/zsl/zsl/algebra/fields/fp12_2over3over2.tcc b/privacy/zsl/zsl/algebra/fields/fp12_2over3over2.tcc new file mode 100644 index 0000000..2fbc0b6 --- /dev/null +++ b/privacy/zsl/zsl/algebra/fields/fp12_2over3over2.tcc @@ -0,0 +1,412 @@ +/** @file + ***************************************************************************** + Implementation of arithmetic in the finite field F[((p^2)^3)^2]. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP12_2OVER3OVER2_TCC_ +#define FP12_2OVER3OVER2_TCC_ + +namespace libsnark { + +template& modulus> +Fp6_3over2_model Fp12_2over3over2_model::mul_by_non_residue(const Fp6_3over2_model &elt) +{ + return Fp6_3over2_model(non_residue * elt.c2, elt.c0, elt.c1); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::zero() +{ + return Fp12_2over3over2_model(my_Fp6::zero(), my_Fp6::zero()); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::one() +{ + return Fp12_2over3over2_model(my_Fp6::one(), my_Fp6::zero()); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::random_element() +{ + Fp12_2over3over2_model r; + r.c0 = my_Fp6::random_element(); + r.c1 = my_Fp6::random_element(); + + return r; +} + +template& modulus> +bool Fp12_2over3over2_model::operator==(const Fp12_2over3over2_model &other) const +{ + return (this->c0 == other.c0 && this->c1 == other.c1); +} + +template& modulus> +bool Fp12_2over3over2_model::operator!=(const Fp12_2over3over2_model &other) const +{ + return !(operator==(other)); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::operator+(const Fp12_2over3over2_model &other) const +{ + return Fp12_2over3over2_model(this->c0 + other.c0, + this->c1 + other.c1); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::operator-(const Fp12_2over3over2_model &other) const +{ + return Fp12_2over3over2_model(this->c0 - other.c0, + this->c1 - other.c1); +} + +template& modulus> +Fp12_2over3over2_model operator*(const Fp_model &lhs, const Fp12_2over3over2_model &rhs) +{ + return Fp12_2over3over2_model(lhs*rhs.c0, + lhs*rhs.c1); +} + +template& modulus> +Fp12_2over3over2_model operator*(const Fp2_model &lhs, const Fp12_2over3over2_model &rhs) +{ + return Fp12_2over3over2_model(lhs*rhs.c0, + lhs*rhs.c1); +} + +template& modulus> +Fp12_2over3over2_model operator*(const Fp6_3over2_model &lhs, const Fp12_2over3over2_model &rhs) +{ + return Fp12_2over3over2_model(lhs*rhs.c0, + lhs*rhs.c1); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::operator*(const Fp12_2over3over2_model &other) const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba) */ + + const my_Fp6 &A = other.c0, &B = other.c1, + &a = this->c0, &b = this->c1; + const my_Fp6 aA = a * A; + const my_Fp6 bB = b * B; + + return Fp12_2over3over2_model(aA + Fp12_2over3over2_model::mul_by_non_residue(bB), + (a + b)*(A+B) - aA - bB); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::operator-() const +{ + return Fp12_2over3over2_model(-this->c0, + -this->c1); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::squared() const +{ + return squared_complex(); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::squared_karatsuba() const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba squaring) */ + + const my_Fp6 &a = this->c0, &b = this->c1; + const my_Fp6 asq = a.squared(); + const my_Fp6 bsq = b.squared(); + + return Fp12_2over3over2_model(asq + Fp12_2over3over2_model::mul_by_non_residue(bsq), + (a + b).squared() - asq - bsq); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::squared_complex() const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Complex squaring) */ + + const my_Fp6 &a = this->c0, &b = this->c1; + const my_Fp6 ab = a * b; + + return Fp12_2over3over2_model((a + b) * (a + Fp12_2over3over2_model::mul_by_non_residue(b)) - ab - Fp12_2over3over2_model::mul_by_non_residue(ab), + ab + ab); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::inverse() const +{ + /* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 8 */ + + const my_Fp6 &a = this->c0, &b = this->c1; + const my_Fp6 t0 = a.squared(); + const my_Fp6 t1 = b.squared(); + const my_Fp6 t2 = t0 - Fp12_2over3over2_model::mul_by_non_residue(t1); + const my_Fp6 t3 = t2.inverse(); + const my_Fp6 c0 = a * t3; + const my_Fp6 c1 = - (b * t3); + + return Fp12_2over3over2_model(c0, c1); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::Frobenius_map(unsigned long power) const +{ + return Fp12_2over3over2_model(c0.Frobenius_map(power), + Frobenius_coeffs_c1[power % 12] * c1.Frobenius_map(power)); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::unitary_inverse() const +{ + return Fp12_2over3over2_model(this->c0, + -this->c1); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::cyclotomic_squared() const +{ + /* OLD: naive implementation + return (*this).squared(); + */ + my_Fp2 z0 = this->c0.c0; + my_Fp2 z4 = this->c0.c1; + my_Fp2 z3 = this->c0.c2; + my_Fp2 z2 = this->c1.c0; + my_Fp2 z1 = this->c1.c1; + my_Fp2 z5 = this->c1.c2; + + my_Fp2 t0, t1, t2, t3, t4, t5, tmp; + + // t0 + t1*y = (z0 + z1*y)^2 = a^2 + tmp = z0 * z1; + t0 = (z0 + z1) * (z0 + my_Fp6::non_residue * z1) - tmp - my_Fp6::non_residue * tmp; + t1 = tmp + tmp; + // t2 + t3*y = (z2 + z3*y)^2 = b^2 + tmp = z2 * z3; + t2 = (z2 + z3) * (z2 + my_Fp6::non_residue * z3) - tmp - my_Fp6::non_residue * tmp; + t3 = tmp + tmp; + // t4 + t5*y = (z4 + z5*y)^2 = c^2 + tmp = z4 * z5; + t4 = (z4 + z5) * (z4 + my_Fp6::non_residue * z5) - tmp - my_Fp6::non_residue * tmp; + t5 = tmp + tmp; + + // for A + + // z0 = 3 * t0 - 2 * z0 + z0 = t0 - z0; + z0 = z0 + z0; + z0 = z0 + t0; + // z1 = 3 * t1 + 2 * z1 + z1 = t1 + z1; + z1 = z1 + z1; + z1 = z1 + t1; + + // for B + + // z2 = 3 * (xi * t5) + 2 * z2 + tmp = my_Fp6::non_residue * t5; + z2 = tmp + z2; + z2 = z2 + z2; + z2 = z2 + tmp; + + // z3 = 3 * t4 - 2 * z3 + z3 = t4 - z3; + z3 = z3 + z3; + z3 = z3 + t4; + + // for C + + // z4 = 3 * t2 - 2 * z4 + z4 = t2 - z4; + z4 = z4 + z4; + z4 = z4 + t2; + + // z5 = 3 * t3 + 2 * z5 + z5 = t3 + z5; + z5 = z5 + z5; + z5 = z5 + t3; + + return Fp12_2over3over2_model(my_Fp6(z0,z4,z3),my_Fp6(z2,z1,z5)); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::mul_by_024(const Fp2_model &ell_0, + const Fp2_model &ell_VW, + const Fp2_model &ell_VV) const +{ + /* OLD: naive implementation + Fp12_2over3over2_model a(my_Fp6(ell_0, my_Fp2::zero(), ell_VV), + my_Fp6(my_Fp2::zero(), ell_VW, my_Fp2::zero())); + + return (*this) * a; + */ + my_Fp2 z0 = this->c0.c0; + my_Fp2 z1 = this->c0.c1; + my_Fp2 z2 = this->c0.c2; + my_Fp2 z3 = this->c1.c0; + my_Fp2 z4 = this->c1.c1; + my_Fp2 z5 = this->c1.c2; + + my_Fp2 x0 = ell_0; + my_Fp2 x2 = ell_VV; + my_Fp2 x4 = ell_VW; + + my_Fp2 t0, t1, t2, s0, T3, T4, D0, D2, D4, S1; + + D0 = z0 * x0; + D2 = z2 * x2; + D4 = z4 * x4; + t2 = z0 + z4; + t1 = z0 + z2; + s0 = z1 + z3 + z5; + + // For z.a_.a_ = z0. + S1 = z1 * x2; + T3 = S1 + D4; + T4 = my_Fp6::non_residue * T3 + D0; + z0 = T4; + + // For z.a_.b_ = z1 + T3 = z5 * x4; + S1 = S1 + T3; + T3 = T3 + D2; + T4 = my_Fp6::non_residue * T3; + T3 = z1 * x0; + S1 = S1 + T3; + T4 = T4 + T3; + z1 = T4; + + // For z.a_.c_ = z2 + t0 = x0 + x2; + T3 = t1 * t0 - D0 - D2; + T4 = z3 * x4; + S1 = S1 + T4; + T3 = T3 + T4; + + // For z.b_.a_ = z3 (z3 needs z2) + t0 = z2 + z4; + z2 = T3; + t1 = x2 + x4; + T3 = t0 * t1 - D2 - D4; + T4 = my_Fp6::non_residue * T3; + T3 = z3 * x0; + S1 = S1 + T3; + T4 = T4 + T3; + z3 = T4; + + // For z.b_.b_ = z4 + T3 = z5 * x2; + S1 = S1 + T3; + T4 = my_Fp6::non_residue * T3; + t0 = x0 + x4; + T3 = t2 * t0 - D0 - D4; + T4 = T4 + T3; + z4 = T4; + + // For z.b_.c_ = z5. + t0 = x0 + x2 + x4; + T3 = s0 * t0 - S1; + z5 = T3; + + return Fp12_2over3over2_model(my_Fp6(z0,z1,z2),my_Fp6(z3,z4,z5)); + +} + +template& modulus, mp_size_t m> +Fp12_2over3over2_model operator^(const Fp12_2over3over2_model &self, const bigint &exponent) +{ + return power >(self, exponent); +} + +template& modulus, mp_size_t m, const bigint& exp_modulus> +Fp12_2over3over2_model operator^(const Fp12_2over3over2_model &self, const Fp_model &exponent) +{ + return self^(exponent.as_bigint()); +} + + +template& modulus> +template +Fp12_2over3over2_model Fp12_2over3over2_model::cyclotomic_exp(const bigint &exponent) const +{ + Fp12_2over3over2_model res = Fp12_2over3over2_model::one(); + + bool found_one = false; + for (long i = m-1; i >= 0; --i) + { + for (long j = GMP_NUMB_BITS - 1; j >= 0; --j) + { + if (found_one) + { + res = res.cyclotomic_squared(); + } + + if (exponent.data[i] & (1ul<& modulus> +std::ostream& operator<<(std::ostream &out, const Fp12_2over3over2_model &el) +{ + out << el.c0 << OUTPUT_SEPARATOR << el.c1; + return out; +} + +template& modulus> +std::istream& operator>>(std::istream &in, Fp12_2over3over2_model &el) +{ + in >> el.c0 >> el.c1; + return in; +} + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v) +{ + out << v.size() << "\n"; + for (const Fp12_2over3over2_model& t : v) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v) +{ + v.clear(); + + size_t s; + in >> s; + + char b; + in.read(&b, 1); + + v.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + Fp12_2over3over2_model el; + in >> el; + v.emplace_back(el); + } + + return in; +} + +} // libsnark +#endif // FP12_2OVER3OVER2_TCC_ diff --git a/privacy/zsl/zsl/algebra/fields/fp2.hpp b/privacy/zsl/zsl/algebra/fields/fp2.hpp new file mode 100644 index 0000000..7624779 --- /dev/null +++ b/privacy/zsl/zsl/algebra/fields/fp2.hpp @@ -0,0 +1,120 @@ +/** @file + ***************************************************************************** + Implementation of arithmetic in the finite field F[p^2]. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP2_HPP_ +#define FP2_HPP_ +#include "algebra/fields/fp.hpp" +#include + +namespace libsnark { + +template& modulus> +class Fp2_model; + +template& modulus> +std::ostream& operator<<(std::ostream &, const Fp2_model &); + +template& modulus> +std::istream& operator>>(std::istream &, Fp2_model &); + +/** + * Arithmetic in the field F[p^2]. + * + * Let p := modulus. This interface provides arithmetic for the extension field + * Fp2 = Fp[U]/(U^2-non_residue), where non_residue is in Fp. + * + * ASSUMPTION: p = 1 (mod 6) + */ +template& modulus> +class Fp2_model { +public: + typedef Fp_model my_Fp; + + static bigint<2*n> euler; // (modulus^2-1)/2 + static size_t s; // modulus^2 = 2^s * t + 1 + static bigint<2*n> t; // with t odd + static bigint<2*n> t_minus_1_over_2; // (t-1)/2 + static my_Fp non_residue; // X^4-non_residue irreducible over Fp; used for constructing Fp2 = Fp[X] / (X^2 - non_residue) + static Fp2_model nqr; // a quadratic nonresidue in Fp2 + static Fp2_model nqr_to_t; // nqr^t + static my_Fp Frobenius_coeffs_c1[2]; // non_residue^((modulus^i-1)/2) for i=0,1 + + my_Fp c0, c1; + Fp2_model() {}; + Fp2_model(const my_Fp& c0, const my_Fp& c1) : c0(c0), c1(c1) {}; + + void clear() { c0.clear(); c1.clear(); } + void print() const { printf("c0/c1:\n"); c0.print(); c1.print(); } + + static Fp2_model zero(); + static Fp2_model one(); + static Fp2_model random_element(); + + bool is_zero() const { return c0.is_zero() && c1.is_zero(); } + bool operator==(const Fp2_model &other) const; + bool operator!=(const Fp2_model &other) const; + + Fp2_model operator+(const Fp2_model &other) const; + Fp2_model operator-(const Fp2_model &other) const; + Fp2_model operator*(const Fp2_model &other) const; + Fp2_model operator-() const; + Fp2_model squared() const; // default is squared_complex + Fp2_model inverse() const; + Fp2_model Frobenius_map(unsigned long power) const; + Fp2_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate) + Fp2_model squared_karatsuba() const; + Fp2_model squared_complex() const; + + template + Fp2_model operator^(const bigint &other) const; + + static size_t size_in_bits() { return 2*my_Fp::size_in_bits(); } + static bigint base_field_char() { return modulus; } + + friend std::ostream& operator<< (std::ostream &out, const Fp2_model &el); + friend std::istream& operator>> (std::istream &in, Fp2_model &el); +}; + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v); + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v); + +template& modulus> +Fp2_model operator*(const Fp_model &lhs, const Fp2_model &rhs); + +template& modulus> +bigint<2*n> Fp2_model::euler; + +template& modulus> +size_t Fp2_model::s; + +template& modulus> +bigint<2*n> Fp2_model::t; + +template& modulus> +bigint<2*n> Fp2_model::t_minus_1_over_2; + +template& modulus> +Fp_model Fp2_model::non_residue; + +template& modulus> +Fp2_model Fp2_model::nqr; + +template& modulus> +Fp2_model Fp2_model::nqr_to_t; + +template& modulus> +Fp_model Fp2_model::Frobenius_coeffs_c1[2]; + +} // libsnark +#include "algebra/fields/fp2.tcc" + +#endif // FP2_HPP_ diff --git a/privacy/zsl/zsl/algebra/fields/fp2.tcc b/privacy/zsl/zsl/algebra/fields/fp2.tcc new file mode 100644 index 0000000..5c2397e --- /dev/null +++ b/privacy/zsl/zsl/algebra/fields/fp2.tcc @@ -0,0 +1,257 @@ +/** @file + ***************************************************************************** + Implementation of arithmetic in the finite field F[p^2]. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP2_TCC_ +#define FP2_TCC_ + +#include "algebra/fields/field_utils.hpp" + +namespace libsnark { + +template& modulus> +Fp2_model Fp2_model::zero() +{ + return Fp2_model(my_Fp::zero(), my_Fp::zero()); +} + +template& modulus> +Fp2_model Fp2_model::one() +{ + return Fp2_model(my_Fp::one(), my_Fp::zero()); +} + +template& modulus> +Fp2_model Fp2_model::random_element() +{ + Fp2_model r; + r.c0 = my_Fp::random_element(); + r.c1 = my_Fp::random_element(); + + return r; +} + +template& modulus> +bool Fp2_model::operator==(const Fp2_model &other) const +{ + return (this->c0 == other.c0 && this->c1 == other.c1); +} + +template& modulus> +bool Fp2_model::operator!=(const Fp2_model &other) const +{ + return !(operator==(other)); +} + +template& modulus> +Fp2_model Fp2_model::operator+(const Fp2_model &other) const +{ + return Fp2_model(this->c0 + other.c0, + this->c1 + other.c1); +} + +template& modulus> +Fp2_model Fp2_model::operator-(const Fp2_model &other) const +{ + return Fp2_model(this->c0 - other.c0, + this->c1 - other.c1); +} + +template& modulus> +Fp2_model operator*(const Fp_model &lhs, const Fp2_model &rhs) +{ + return Fp2_model(lhs*rhs.c0, + lhs*rhs.c1); +} + +template& modulus> +Fp2_model Fp2_model::operator*(const Fp2_model &other) const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba) */ + const my_Fp + &A = other.c0, &B = other.c1, + &a = this->c0, &b = this->c1; + const my_Fp aA = a * A; + const my_Fp bB = b * B; + + return Fp2_model(aA + non_residue * bB, + (a + b)*(A+B) - aA - bB); +} + +template& modulus> +Fp2_model Fp2_model::operator-() const +{ + return Fp2_model(-this->c0, + -this->c1); +} + +template& modulus> +Fp2_model Fp2_model::squared() const +{ + return squared_complex(); +} + +template& modulus> +Fp2_model Fp2_model::squared_karatsuba() const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba squaring) */ + const my_Fp &a = this->c0, &b = this->c1; + const my_Fp asq = a.squared(); + const my_Fp bsq = b.squared(); + + return Fp2_model(asq + non_residue * bsq, + (a + b).squared() - asq - bsq); +} + +template& modulus> +Fp2_model Fp2_model::squared_complex() const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Complex squaring) */ + const my_Fp &a = this->c0, &b = this->c1; + const my_Fp ab = a * b; + + return Fp2_model((a + b) * (a + non_residue * b) - ab - non_residue * ab, + ab + ab); +} + +template& modulus> +Fp2_model Fp2_model::inverse() const +{ + const my_Fp &a = this->c0, &b = this->c1; + + /* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 8 */ + const my_Fp t0 = a.squared(); + const my_Fp t1 = b.squared(); + const my_Fp t2 = t0 - non_residue * t1; + const my_Fp t3 = t2.inverse(); + const my_Fp c0 = a * t3; + const my_Fp c1 = - (b * t3); + + return Fp2_model(c0, c1); +} + +template& modulus> +Fp2_model Fp2_model::Frobenius_map(unsigned long power) const +{ + return Fp2_model(c0, + Frobenius_coeffs_c1[power % 2] * c1); +} + +template& modulus> +Fp2_model Fp2_model::sqrt() const +{ + Fp2_model one = Fp2_model::one(); + + size_t v = Fp2_model::s; + Fp2_model z = Fp2_model::nqr_to_t; + Fp2_model w = (*this)^Fp2_model::t_minus_1_over_2; + Fp2_model x = (*this) * w; + Fp2_model b = x * w; // b = (*this)^t + +#if DEBUG + // check if square with euler's criterion + Fp2_model check = b; + for (size_t i = 0; i < v-1; ++i) + { + check = check.squared(); + } + if (check != one) + { + assert(0); + } +#endif + + // compute square root with Tonelli--Shanks + // (does not terminate if not a square!) + + while (b != one) + { + size_t m = 0; + Fp2_model b2m = b; + while (b2m != one) + { + /* invariant: b2m = b^(2^m) after entering this loop */ + b2m = b2m.squared(); + m += 1; + } + + int j = v-m-1; + w = z; + while (j > 0) + { + w = w.squared(); + --j; + } // w = z^2^(v-m-1) + + z = w.squared(); + b = b * z; + x = x * w; + v = m; + } + + return x; +} + +template& modulus> +template +Fp2_model Fp2_model::operator^(const bigint &pow) const +{ + return power, m>(*this, pow); +} + +template& modulus> +std::ostream& operator<<(std::ostream &out, const Fp2_model &el) +{ + out << el.c0 << OUTPUT_SEPARATOR << el.c1; + return out; +} + +template& modulus> +std::istream& operator>>(std::istream &in, Fp2_model &el) +{ + in >> el.c0 >> el.c1; + return in; +} + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v) +{ + out << v.size() << "\n"; + for (const Fp2_model& t : v) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v) +{ + v.clear(); + + size_t s; + in >> s; + + char b; + in.read(&b, 1); + + v.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + Fp2_model el; + in >> el; + v.emplace_back(el); + } + + return in; +} + +} // libsnark +#endif // FP2_TCC_ diff --git a/privacy/zsl/zsl/algebra/fields/fp3.hpp b/privacy/zsl/zsl/algebra/fields/fp3.hpp new file mode 100644 index 0000000..53b178a --- /dev/null +++ b/privacy/zsl/zsl/algebra/fields/fp3.hpp @@ -0,0 +1,122 @@ +/** @file + ***************************************************************************** + Declaration of arithmetic in the finite field F[p^3]. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP3_HPP_ +#define FP3_HPP_ +#include "algebra/fields/fp.hpp" +#include + +namespace libsnark { + +template& modulus> +class Fp3_model; + +template& modulus> +std::ostream& operator<<(std::ostream &, const Fp3_model &); + +template& modulus> +std::istream& operator>>(std::istream &, Fp3_model &); + +/** + * Arithmetic in the field F[p^3]. + * + * Let p := modulus. This interface provides arithmetic for the extension field + * Fp3 = Fp[U]/(U^3-non_residue), where non_residue is in Fp. + * + * ASSUMPTION: p = 1 (mod 6) + */ +template& modulus> +class Fp3_model { +public: + typedef Fp_model my_Fp; + + static bigint<3*n> euler; // (modulus^3-1)/2 + static size_t s; // modulus^3 = 2^s * t + 1 + static bigint<3*n> t; // with t odd + static bigint<3*n> t_minus_1_over_2; // (t-1)/2 + static my_Fp non_residue; // X^6-non_residue irreducible over Fp; used for constructing Fp3 = Fp[X] / (X^3 - non_residue) + static Fp3_model nqr; // a quadratic nonresidue in Fp3 + static Fp3_model nqr_to_t; // nqr^t + static my_Fp Frobenius_coeffs_c1[3]; // non_residue^((modulus^i-1)/3) for i=0,1,2 + static my_Fp Frobenius_coeffs_c2[3]; // non_residue^((2*modulus^i-2)/3) for i=0,1,2 + + my_Fp c0, c1, c2; + Fp3_model() {}; + Fp3_model(const my_Fp& c0, const my_Fp& c1, const my_Fp& c2) : c0(c0), c1(c1), c2(c2) {}; + + void clear() { c0.clear(); c1.clear(); c2.clear(); } + void print() const { printf("c0/c1/c2:\n"); c0.print(); c1.print(); c2.print(); } + + static Fp3_model zero(); + static Fp3_model one(); + static Fp3_model random_element(); + + bool is_zero() const { return c0.is_zero() && c1.is_zero() && c2.is_zero(); } + bool operator==(const Fp3_model &other) const; + bool operator!=(const Fp3_model &other) const; + + Fp3_model operator+(const Fp3_model &other) const; + Fp3_model operator-(const Fp3_model &other) const; + Fp3_model operator*(const Fp3_model &other) const; + Fp3_model operator-() const; + Fp3_model squared() const; + Fp3_model inverse() const; + Fp3_model Frobenius_map(unsigned long power) const; + Fp3_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate) + + template + Fp3_model operator^(const bigint &other) const; + + static size_t size_in_bits() { return 3*my_Fp::size_in_bits(); } + static bigint base_field_char() { return modulus; } + + friend std::ostream& operator<< (std::ostream &out, const Fp3_model &el); + friend std::istream& operator>> (std::istream &in, Fp3_model &el); +}; + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v); + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v); + +template& modulus> +Fp3_model operator*(const Fp_model &lhs, const Fp3_model &rhs); + +template& modulus> +bigint<3*n> Fp3_model::euler; + +template& modulus> +size_t Fp3_model::s; + +template& modulus> +bigint<3*n> Fp3_model::t; + +template& modulus> +bigint<3*n> Fp3_model::t_minus_1_over_2; + +template& modulus> +Fp_model Fp3_model::non_residue; + +template& modulus> +Fp3_model Fp3_model::nqr; + +template& modulus> +Fp3_model Fp3_model::nqr_to_t; + +template& modulus> +Fp_model Fp3_model::Frobenius_coeffs_c1[3]; + +template& modulus> +Fp_model Fp3_model::Frobenius_coeffs_c2[3]; + +} // libsnark +#include "algebra/fields/fp3.tcc" + +#endif // FP3_HPP_ diff --git a/privacy/zsl/zsl/algebra/fields/fp3.tcc b/privacy/zsl/zsl/algebra/fields/fp3.tcc new file mode 100644 index 0000000..590a2a9 --- /dev/null +++ b/privacy/zsl/zsl/algebra/fields/fp3.tcc @@ -0,0 +1,259 @@ +/** @file + ***************************************************************************** + Implementation of arithmetic in the finite field F[p^3]. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP3_TCC_ +#define FP3_TCC_ + +#include "algebra/fields/field_utils.hpp" + +namespace libsnark { + +template& modulus> +Fp3_model Fp3_model::zero() +{ + return Fp3_model(my_Fp::zero(), my_Fp::zero(), my_Fp::zero()); +} + +template& modulus> +Fp3_model Fp3_model::one() +{ + return Fp3_model(my_Fp::one(), my_Fp::zero(), my_Fp::zero()); +} + +template& modulus> +Fp3_model Fp3_model::random_element() +{ + Fp3_model r; + r.c0 = my_Fp::random_element(); + r.c1 = my_Fp::random_element(); + r.c2 = my_Fp::random_element(); + + return r; +} + +template& modulus> +bool Fp3_model::operator==(const Fp3_model &other) const +{ + return (this->c0 == other.c0 && this->c1 == other.c1 && this->c2 == other.c2); +} + +template& modulus> +bool Fp3_model::operator!=(const Fp3_model &other) const +{ + return !(operator==(other)); +} + +template& modulus> +Fp3_model Fp3_model::operator+(const Fp3_model &other) const +{ + return Fp3_model(this->c0 + other.c0, + this->c1 + other.c1, + this->c2 + other.c2); +} + +template& modulus> +Fp3_model Fp3_model::operator-(const Fp3_model &other) const +{ + return Fp3_model(this->c0 - other.c0, + this->c1 - other.c1, + this->c2 - other.c2); +} + +template& modulus> +Fp3_model operator*(const Fp_model &lhs, const Fp3_model &rhs) +{ + return Fp3_model(lhs*rhs.c0, + lhs*rhs.c1, + lhs*rhs.c2); +} + +template& modulus> +Fp3_model Fp3_model::operator*(const Fp3_model &other) const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (Karatsuba) */ + const my_Fp + &A = other.c0, &B = other.c1, &C = other.c2, + &a = this->c0, &b = this->c1, &c = this->c2; + const my_Fp aA = a*A; + const my_Fp bB = b*B; + const my_Fp cC = c*C; + + return Fp3_model(aA + non_residue*((b+c)*(B+C)-bB-cC), + (a+b)*(A+B)-aA-bB+non_residue*cC, + (a+c)*(A+C)-aA+bB-cC); +} + +template& modulus> +Fp3_model Fp3_model::operator-() const +{ + return Fp3_model(-this->c0, + -this->c1, + -this->c2); +} + +template& modulus> +Fp3_model Fp3_model::squared() const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (CH-SQR2) */ + const my_Fp + &a = this->c0, &b = this->c1, &c = this->c2; + const my_Fp s0 = a.squared(); + const my_Fp ab = a*b; + const my_Fp s1 = ab + ab; + const my_Fp s2 = (a - b + c).squared(); + const my_Fp bc = b*c; + const my_Fp s3 = bc + bc; + const my_Fp s4 = c.squared(); + + return Fp3_model(s0 + non_residue * s3, + s1 + non_residue * s4, + s1 + s2 + s3 - s0 - s4); +} + +template& modulus> +Fp3_model Fp3_model::inverse() const +{ + const my_Fp + &a = this->c0, &b = this->c1, &c = this->c2; + + /* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 17 */ + const my_Fp t0 = a.squared(); + const my_Fp t1 = b.squared(); + const my_Fp t2 = c.squared(); + const my_Fp t3 = a*b; + const my_Fp t4 = a*c; + const my_Fp t5 = b*c; + const my_Fp c0 = t0 - non_residue * t5; + const my_Fp c1 = non_residue * t2 - t3; + const my_Fp c2 = t1 - t4; // typo in paper referenced above. should be "-" as per Scott, but is "*" + const my_Fp t6 = (a * c0 + non_residue * (c * c1 + b * c2)).inverse(); + return Fp3_model(t6 * c0, t6 * c1, t6 * c2); +} + +template& modulus> +Fp3_model Fp3_model::Frobenius_map(unsigned long power) const +{ + return Fp3_model(c0, + Frobenius_coeffs_c1[power % 3] * c1, + Frobenius_coeffs_c2[power % 3] * c2); +} + +template& modulus> +Fp3_model Fp3_model::sqrt() const +{ + Fp3_model one = Fp3_model::one(); + + size_t v = Fp3_model::s; + Fp3_model z = Fp3_model::nqr_to_t; + Fp3_model w = (*this)^Fp3_model::t_minus_1_over_2; + Fp3_model x = (*this) * w; + Fp3_model b = x * w; // b = (*this)^t + +#if DEBUG + // check if square with euler's criterion + Fp3_model check = b; + for (size_t i = 0; i < v-1; ++i) + { + check = check.squared(); + } + if (check != one) + { + assert(0); + } +#endif + + // compute square root with Tonelli--Shanks + // (does not terminate if not a square!) + + while (b != one) + { + size_t m = 0; + Fp3_model b2m = b; + while (b2m != one) + { + /* invariant: b2m = b^(2^m) after entering this loop */ + b2m = b2m.squared(); + m += 1; + } + + int j = v-m-1; + w = z; + while (j > 0) + { + w = w.squared(); + --j; + } // w = z^2^(v-m-1) + + z = w.squared(); + b = b * z; + x = x * w; + v = m; + } + + return x; +} + +template& modulus> +template +Fp3_model Fp3_model::operator^(const bigint &pow) const +{ + return power >(*this, pow); +} + +template& modulus> +std::ostream& operator<<(std::ostream &out, const Fp3_model &el) +{ + out << el.c0 << OUTPUT_SEPARATOR << el.c1 << OUTPUT_SEPARATOR << el.c2; + return out; +} + +template& modulus> +std::istream& operator>>(std::istream &in, Fp3_model &el) +{ + in >> el.c0 >> el.c1 >> el.c2; + return in; +} + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v) +{ + out << v.size() << "\n"; + for (const Fp3_model& t : v) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v) +{ + v.clear(); + + size_t s; + in >> s; + + char b; + in.read(&b, 1); + + v.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + Fp3_model el; + in >> el; + v.emplace_back(el); + } + + return in; +} + +} // libsnark +#endif // FP3_TCC_ diff --git a/privacy/zsl/zsl/algebra/fields/fp4.hpp b/privacy/zsl/zsl/algebra/fields/fp4.hpp new file mode 100644 index 0000000..7e37807 --- /dev/null +++ b/privacy/zsl/zsl/algebra/fields/fp4.hpp @@ -0,0 +1,104 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the (extension) field Fp4. + + The field Fp4 equals Fp2[V]/(V^2-U) where Fp2 = Fp[U]/(U^2-non_residue) and non_residue is in Fp. + + ASSUMPTION: the modulus p is 1 mod 6. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP4_HPP_ +#define FP4_HPP_ + +#include "algebra/fields/fp.hpp" +#include "algebra/fields/fp2.hpp" + +namespace libsnark { + +template& modulus> +class Fp4_model; + +template& modulus> +std::ostream& operator<<(std::ostream &, const Fp4_model &); + +template& modulus> +std::istream& operator>>(std::istream &, Fp4_model &); + +template& modulus> +class Fp4_model { +public: + typedef Fp_model my_Fp; + typedef Fp2_model my_Fp2; + typedef my_Fp2 my_Fpe; + + static my_Fp non_residue; + static my_Fp Frobenius_coeffs_c1[4]; // non_residue^((modulus^i-1)/4) for i=0,1,2,3 + + my_Fp2 c0, c1; + Fp4_model() {}; + Fp4_model(const my_Fp2& c0, const my_Fp2& c1) : c0(c0), c1(c1) {}; + + void print() const { printf("c0/c1:\n"); c0.print(); c1.print(); } + void clear() { c0.clear(); c1.clear(); } + + static Fp4_model zero(); + static Fp4_model one(); + static Fp4_model random_element(); + + bool is_zero() const { return c0.is_zero() && c1.is_zero(); } + bool operator==(const Fp4_model &other) const; + bool operator!=(const Fp4_model &other) const; + + Fp4_model operator+(const Fp4_model &other) const; + Fp4_model operator-(const Fp4_model &other) const; + Fp4_model operator*(const Fp4_model &other) const; + Fp4_model mul_by_023(const Fp4_model &other) const; + Fp4_model operator-() const; + Fp4_model squared() const; + Fp4_model inverse() const; + Fp4_model Frobenius_map(unsigned long power) const; + Fp4_model unitary_inverse() const; + Fp4_model cyclotomic_squared() const; + + static my_Fp2 mul_by_non_residue(const my_Fp2 &elt); + + template + Fp4_model cyclotomic_exp(const bigint &exponent) const; + + static bigint base_field_char() { return modulus; } + static constexpr size_t extension_degree() { return 4; } + + friend std::ostream& operator<< (std::ostream &out, const Fp4_model &el); + friend std::istream& operator>> (std::istream &in, Fp4_model &el); +}; + +template& modulus> +Fp4_model operator*(const Fp_model &lhs, const Fp4_model &rhs); + +template& modulus> +Fp4_model operator*(const Fp2_model &lhs, const Fp4_model &rhs); + +template& modulus, mp_size_t m> +Fp4_model operator^(const Fp4_model &self, const bigint &exponent); + +template& modulus, mp_size_t m, const bigint& modulus_p> +Fp4_model operator^(const Fp4_model &self, const Fp_model &exponent); + +template& modulus> +Fp_model Fp4_model::non_residue; + +template& modulus> +Fp_model Fp4_model::Frobenius_coeffs_c1[4]; + + +} // libsnark + +#include "algebra/fields/fp4.tcc" + +#endif // FP4_HPP_ diff --git a/privacy/zsl/zsl/algebra/fields/fp4.tcc b/privacy/zsl/zsl/algebra/fields/fp4.tcc new file mode 100644 index 0000000..ffdec96 --- /dev/null +++ b/privacy/zsl/zsl/algebra/fields/fp4.tcc @@ -0,0 +1,245 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the (extension) field Fp4. + + See fp4.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP4_TCC_ +#define FP4_TCC_ + +#include "algebra/fields/field_utils.hpp" +#include "algebra/scalar_multiplication/wnaf.hpp" + +namespace libsnark { + +template& modulus> +Fp2_model Fp4_model::mul_by_non_residue(const Fp2_model &elt) +{ + return Fp2_model(non_residue * elt.c1, elt.c0); +} + +template& modulus> +Fp4_model Fp4_model::zero() +{ + return Fp4_model(my_Fp2::zero(), + my_Fp2::zero()); +} + +template& modulus> +Fp4_model Fp4_model::one() +{ + return Fp4_model(my_Fp2::one(), + my_Fp2::zero()); +} + +template& modulus> +Fp4_model Fp4_model::random_element() +{ + Fp4_model r; + r.c0 = my_Fp2::random_element(); + r.c1 = my_Fp2::random_element(); + + return r; +} + +template& modulus> +bool Fp4_model::operator==(const Fp4_model &other) const +{ + return (this->c0 == other.c0 && this->c1 == other.c1); +} + +template& modulus> +bool Fp4_model::operator!=(const Fp4_model &other) const +{ + return !(operator==(other)); +} + +template& modulus> +Fp4_model Fp4_model::operator+(const Fp4_model &other) const +{ + return Fp4_model(this->c0 + other.c0, + this->c1 + other.c1); +} + +template& modulus> +Fp4_model Fp4_model::operator-(const Fp4_model &other) const +{ + return Fp4_model(this->c0 - other.c0, + this->c1 - other.c1); +} + +template& modulus> +Fp4_model operator*(const Fp_model &lhs, const Fp4_model &rhs) +{ + return Fp4_model(lhs*rhs.c0, + lhs*rhs.c1); +} + +template& modulus> +Fp4_model operator*(const Fp2_model &lhs, const Fp4_model &rhs) +{ + return Fp4_model(lhs*rhs.c0, + lhs*rhs.c1); +} + +template& modulus> +Fp4_model Fp4_model::operator*(const Fp4_model &other) const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba) */ + + const my_Fp2 &B = other.c1, &A = other.c0, + &b = this->c1, &a = this->c0; + const my_Fp2 aA = a*A; + const my_Fp2 bB = b*B; + + const my_Fp2 beta_bB = Fp4_model::mul_by_non_residue(bB); + return Fp4_model(aA + beta_bB, + (a+b)*(A+B) - aA - bB); +} + +template& modulus> +Fp4_model Fp4_model::mul_by_023(const Fp4_model &other) const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba) */ + assert(other.c0.c1.is_zero()); + + const my_Fp2 &B = other.c1, &A = other.c0, + &b = this->c1, &a = this->c0; + const my_Fp2 aA = my_Fp2(a.c0 * A.c0, a.c1 * A.c0); + const my_Fp2 bB = b*B; + + const my_Fp2 beta_bB = Fp4_model::mul_by_non_residue(bB); + return Fp4_model(aA + beta_bB, + (a+b)*(A+B) - aA - bB); +} + +template& modulus> +Fp4_model Fp4_model::operator-() const +{ + return Fp4_model(-this->c0, + -this->c1); +} + +template& modulus> +Fp4_model Fp4_model::squared() const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Complex) */ + + const my_Fp2 &b = this->c1, &a = this->c0; + const my_Fp2 ab = a * b; + + return Fp4_model((a+b)*(a+Fp4_model::mul_by_non_residue(b))-ab-Fp4_model::mul_by_non_residue(ab), + ab + ab); +} + +template& modulus> +Fp4_model Fp4_model::inverse() const +{ + /* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 8 */ + const my_Fp2 &b = this->c1, &a = this->c0; + const my_Fp2 t1 = b.squared(); + const my_Fp2 t0 = a.squared() - Fp4_model::mul_by_non_residue(t1); + const my_Fp2 new_t1 = t0.inverse(); + + return Fp4_model(a * new_t1, - (b * new_t1)); +} + +template& modulus> +Fp4_model Fp4_model::Frobenius_map(unsigned long power) const +{ + return Fp4_model(c0.Frobenius_map(power), + Frobenius_coeffs_c1[power % 4] * c1.Frobenius_map(power)); +} + +template& modulus> +Fp4_model Fp4_model::unitary_inverse() const +{ + return Fp4_model(this->c0, + -this->c1); +} + +template& modulus> +Fp4_model Fp4_model::cyclotomic_squared() const +{ + const my_Fp2 A = this->c1.squared(); + const my_Fp2 B = this->c1 + this->c0; + const my_Fp2 C = B.squared() - A; + const my_Fp2 D = Fp4_model::mul_by_non_residue(A); // Fp2(A.c1 * non_residue, A.c0) + const my_Fp2 E = C - D; + const my_Fp2 F = D + D + my_Fp2::one(); + const my_Fp2 G = E - my_Fp2::one(); + + return Fp4_model(F, G); +} + +template& modulus> +template +Fp4_model Fp4_model::cyclotomic_exp(const bigint &exponent) const +{ + Fp4_model res = Fp4_model::one(); + Fp4_model this_inverse = this->unitary_inverse(); + + bool found_nonzero = false; + std::vector NAF = find_wnaf(1, exponent); + + for (long i = NAF.size() - 1; i >= 0; --i) + { + if (found_nonzero) + { + res = res.cyclotomic_squared(); + } + + if (NAF[i] != 0) + { + found_nonzero = true; + + if (NAF[i] > 0) + { + res = res * (*this); + } + else + { + res = res * this_inverse; + } + } + } + + return res; +} + +template& modulus, mp_size_t m> +Fp4_model operator^(const Fp4_model &self, const bigint &exponent) +{ + return power >(self, exponent); +} + +template& modulus, mp_size_t m, const bigint& modulus_p> +Fp4_model operator^(const Fp4_model &self, const Fp_model &exponent) +{ + return self^(exponent.as_bigint()); +} + +template& modulus> +std::ostream& operator<<(std::ostream &out, const Fp4_model &el) +{ + out << el.c0 << OUTPUT_SEPARATOR << el.c1; + return out; +} + +template& modulus> +std::istream& operator>>(std::istream &in, Fp4_model &el) +{ + in >> el.c0 >> el.c1; + return in; +} + +} // libsnark + +#endif // FP4_TCC_ diff --git a/privacy/zsl/zsl/algebra/fields/fp6_2over3.hpp b/privacy/zsl/zsl/algebra/fields/fp6_2over3.hpp new file mode 100644 index 0000000..61412b7 --- /dev/null +++ b/privacy/zsl/zsl/algebra/fields/fp6_2over3.hpp @@ -0,0 +1,108 @@ +/** @file + ***************************************************************************** + Declaration of arithmetic in the finite field F[(p^3)^2] + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP6_2OVER3_HPP_ +#define FP6_2OVER3_HPP_ +#include "algebra/fields/fp.hpp" +#include "algebra/fields/fp2.hpp" +#include "algebra/fields/fp3.hpp" + +namespace libsnark { + +/** + * Arithmetic in the finite field F[(p^3)^2]. + * + * Let p := modulus. This interface provides arithmetic for the extension field + * Fp6 = Fp3[Y]/(Y^2-X) where Fp3 = Fp[X]/(X^3-non_residue) and non_residue is in Fp. + * + * ASSUMPTION: p = 1 (mod 6) + */ +template& modulus> +class Fp6_2over3_model; + +template& modulus> +std::ostream& operator<<(std::ostream &, const Fp6_2over3_model &); + +template& modulus> +std::istream& operator>>(std::istream &, Fp6_2over3_model &); + +template& modulus> +class Fp6_2over3_model { +public: + typedef Fp_model my_Fp; + typedef Fp2_model my_Fp2; + typedef Fp3_model my_Fp3; + typedef my_Fp3 my_Fpe; + + static my_Fp non_residue; + static my_Fp Frobenius_coeffs_c1[6]; // non_residue^((modulus^i-1)/6) for i=0,1,2,3,4,5 + + my_Fp3 c0, c1; + Fp6_2over3_model() {}; + Fp6_2over3_model(const my_Fp3& c0, const my_Fp3& c1) : c0(c0), c1(c1) {}; + + void print() const { printf("c0/c1:\n"); c0.print(); c1.print(); } + void clear() { c0.clear(); c1.clear(); } + + static Fp6_2over3_model zero(); + static Fp6_2over3_model one(); + static Fp6_2over3_model random_element(); + + bool is_zero() const { return c0.is_zero() && c1.is_zero(); } + bool operator==(const Fp6_2over3_model &other) const; + bool operator!=(const Fp6_2over3_model &other) const; + + Fp6_2over3_model operator+(const Fp6_2over3_model &other) const; + Fp6_2over3_model operator-(const Fp6_2over3_model &other) const; + Fp6_2over3_model operator*(const Fp6_2over3_model &other) const; + Fp6_2over3_model mul_by_2345(const Fp6_2over3_model &other) const; + Fp6_2over3_model operator-() const; + Fp6_2over3_model squared() const; + Fp6_2over3_model inverse() const; + Fp6_2over3_model Frobenius_map(unsigned long power) const; + Fp6_2over3_model unitary_inverse() const; + Fp6_2over3_model cyclotomic_squared() const; + + static my_Fp3 mul_by_non_residue(const my_Fp3 &elem); + + template + Fp6_2over3_model cyclotomic_exp(const bigint &exponent) const; + + static bigint base_field_char() { return modulus; } + static constexpr size_t extension_degree() { return 6; } + + friend std::ostream& operator<< (std::ostream &out, const Fp6_2over3_model &el); + friend std::istream& operator>> (std::istream &in, Fp6_2over3_model &el); +}; + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v); + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v); + +template& modulus> +Fp6_2over3_model operator*(const Fp_model &lhs, const Fp6_2over3_model &rhs); + +template& modulus, mp_size_t m> +Fp6_2over3_model operator^(const Fp6_2over3_model &self, const bigint &exponent); + +template& modulus, mp_size_t m, const bigint& exp_modulus> +Fp6_2over3_model operator^(const Fp6_2over3_model &self, const Fp_model &exponent); + +template& modulus> +Fp_model Fp6_2over3_model::non_residue; + +template& modulus> +Fp_model Fp6_2over3_model::Frobenius_coeffs_c1[6]; + +} // libsnark +#include "algebra/fields/fp6_2over3.tcc" + +#endif // FP6_2OVER3_HPP_ diff --git a/privacy/zsl/zsl/algebra/fields/fp6_2over3.tcc b/privacy/zsl/zsl/algebra/fields/fp6_2over3.tcc new file mode 100644 index 0000000..cc4e46d --- /dev/null +++ b/privacy/zsl/zsl/algebra/fields/fp6_2over3.tcc @@ -0,0 +1,274 @@ +/** @file + ***************************************************************************** + Implementation of arithmetic in the finite field F[(p^3)^2]. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP6_2OVER3_TCC_ +#define FP6_2OVER3_TCC_ +#include "algebra/fields/field_utils.hpp" +#include "algebra/scalar_multiplication/wnaf.hpp" + +namespace libsnark { + +template& modulus> +Fp3_model Fp6_2over3_model::mul_by_non_residue(const Fp3_model &elem) +{ + return Fp3_model(non_residue * elem.c2, elem.c0, elem.c1); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::zero() +{ + return Fp6_2over3_model(my_Fp3::zero(), + my_Fp3::zero()); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::one() +{ + return Fp6_2over3_model(my_Fp3::one(), + my_Fp3::zero()); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::random_element() +{ + Fp6_2over3_model r; + r.c0 = my_Fp3::random_element(); + r.c1 = my_Fp3::random_element(); + + return r; +} + +template& modulus> +bool Fp6_2over3_model::operator==(const Fp6_2over3_model &other) const +{ + return (this->c0 == other.c0 && this->c1 == other.c1); +} + +template& modulus> +bool Fp6_2over3_model::operator!=(const Fp6_2over3_model &other) const +{ + return !(operator==(other)); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::operator+(const Fp6_2over3_model &other) const +{ + return Fp6_2over3_model(this->c0 + other.c0, + this->c1 + other.c1); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::operator-(const Fp6_2over3_model &other) const +{ + return Fp6_2over3_model(this->c0 - other.c0, + this->c1 - other.c1); +} + +template& modulus> +Fp6_2over3_model operator*(const Fp_model &lhs, const Fp6_2over3_model &rhs) +{ + return Fp6_2over3_model(lhs*rhs.c0, + lhs*rhs.c1); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::operator*(const Fp6_2over3_model &other) const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba) */ + + const my_Fp3 &B = other.c1, &A = other.c0, + &b = this->c1, &a = this->c0; + const my_Fp3 aA = a*A; + const my_Fp3 bB = b*B; + const my_Fp3 beta_bB = Fp6_2over3_model::mul_by_non_residue(bB); + + return Fp6_2over3_model(aA + beta_bB, + (a+b)*(A+B) - aA - bB); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::mul_by_2345(const Fp6_2over3_model &other) const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba) */ + assert(other.c0.c0.is_zero()); + assert(other.c0.c1.is_zero()); + + const my_Fp3 &B = other.c1, &A = other.c0, + &b = this->c1, &a = this->c0; + const my_Fp3 aA = my_Fp3(a.c1 * A.c2 * non_residue, a.c2 * A.c2 * non_residue, a.c0 * A.c2); + const my_Fp3 bB = b*B; + const my_Fp3 beta_bB = Fp6_2over3_model::mul_by_non_residue(bB); + + return Fp6_2over3_model(aA + beta_bB, + (a+b)*(A+B) - aA - bB); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::operator-() const +{ + return Fp6_2over3_model(-this->c0, + -this->c1); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::squared() const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Complex) */ + const my_Fp3 &b = this->c1, &a = this->c0; + const my_Fp3 ab = a * b; + + return Fp6_2over3_model((a+b)*(a+Fp6_2over3_model::mul_by_non_residue(b))-ab-Fp6_2over3_model::mul_by_non_residue(ab), + ab + ab); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::inverse() const +{ + /* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 8 */ + + const my_Fp3 &b = this->c1, &a = this->c0; + const my_Fp3 t1 = b.squared(); + const my_Fp3 t0 = a.squared() - Fp6_2over3_model::mul_by_non_residue(t1); + const my_Fp3 new_t1 = t0.inverse(); + + return Fp6_2over3_model(a * new_t1, + - (b * new_t1)); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::Frobenius_map(unsigned long power) const +{ + return Fp6_2over3_model(c0.Frobenius_map(power), + Frobenius_coeffs_c1[power % 6] * c1.Frobenius_map(power)); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::unitary_inverse() const +{ + return Fp6_2over3_model(this->c0, + -this->c1); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::cyclotomic_squared() const +{ + my_Fp2 a = my_Fp2(c0.c0, c1.c1); + //my_Fp a_a = c0.c0; // a = Fp2([c0[0],c1[1]]) + //my_Fp a_b = c1.c1; + + my_Fp2 b = my_Fp2(c1.c0, c0.c2); + //my_Fp b_a = c1.c0; // b = Fp2([c1[0],c0[2]]) + //my_Fp b_b = c0.c2; + + my_Fp2 c = my_Fp2(c0.c1, c1.c2); + //my_Fp c_a = c0.c1; // c = Fp2([c0[1],c1[2]]) + //my_Fp c_b = c1.c2; + + my_Fp2 asq = a.squared(); + my_Fp2 bsq = b.squared(); + my_Fp2 csq = c.squared(); + + // A = vector(3*a^2 - 2*Fp2([vector(a)[0],-vector(a)[1]])) + //my_Fp A_a = my_Fp(3l) * asq_a - my_Fp(2l) * a_a; + my_Fp A_a = asq.c0 - a.c0; + A_a = A_a + A_a + asq.c0; + //my_Fp A_b = my_Fp(3l) * asq_b + my_Fp(2l) * a_b; + my_Fp A_b = asq.c1 + a.c1; + A_b = A_b + A_b + asq.c1; + + // B = vector(3*Fp2([non_residue*c2[1],c2[0]]) + 2*Fp2([vector(b)[0],-vector(b)[1]])) + //my_Fp B_a = my_Fp(3l) * my_Fp3::non_residue * csq_b + my_Fp(2l) * b_a; + my_Fp B_tmp = my_Fp3::non_residue * csq.c1; + my_Fp B_a = B_tmp + b.c0; + B_a = B_a + B_a + B_tmp; + + //my_Fp B_b = my_Fp(3l) * csq_a - my_Fp(2l) * b_b; + my_Fp B_b = csq.c0 - b.c1; + B_b = B_b + B_b + csq.c0; + + // C = vector(3*b^2 - 2*Fp2([vector(c)[0],-vector(c)[1]])) + //my_Fp C_a = my_Fp(3l) * bsq_a - my_Fp(2l) * c_a; + my_Fp C_a = bsq.c0 - c.c0; + C_a = C_a + C_a + bsq.c0; + // my_Fp C_b = my_Fp(3l) * bsq_b + my_Fp(2l) * c_b; + my_Fp C_b = bsq.c1 + c.c1; + C_b = C_b + C_b + bsq.c1; + + // e0 = Fp3([A[0],C[0],B[1]]) + // e1 = Fp3([B[0],A[1],C[1]]) + // fin = Fp6e([e0,e1]) + // return fin + + return Fp6_2over3_model(my_Fp3(A_a, C_a, B_b), + my_Fp3(B_a, A_b, C_b)); +} + +template& modulus> +template +Fp6_2over3_model Fp6_2over3_model::cyclotomic_exp(const bigint &exponent) const +{ + Fp6_2over3_model res = Fp6_2over3_model::one(); + Fp6_2over3_model this_inverse = this->unitary_inverse(); + + bool found_nonzero = false; + std::vector NAF = find_wnaf(1, exponent); + + for (long i = NAF.size() - 1; i >= 0; --i) + { + if (found_nonzero) + { + res = res.cyclotomic_squared(); + } + + if (NAF[i] != 0) + { + found_nonzero = true; + + if (NAF[i] > 0) + { + res = res * (*this); + } + else + { + res = res * this_inverse; + } + } + } + + return res; +} + +template& modulus> +std::ostream& operator<<(std::ostream &out, const Fp6_2over3_model &el) +{ + out << el.c0 << OUTPUT_SEPARATOR << el.c1; + return out; +} + +template& modulus> +std::istream& operator>>(std::istream &in, Fp6_2over3_model &el) +{ + in >> el.c0 >> el.c1; + return in; +} + +template& modulus, mp_size_t m> +Fp6_2over3_model operator^(const Fp6_2over3_model &self, const bigint &exponent) +{ + return power, m>(self, exponent); +} + +template& modulus, mp_size_t m, const bigint& exp_modulus> +Fp6_2over3_model operator^(const Fp6_2over3_model &self, const Fp_model &exponent) +{ + return self^(exponent.as_bigint()); +} + +} // libsnark +#endif // FP6_2OVER3_TCC_ diff --git a/privacy/zsl/zsl/algebra/fields/fp6_3over2.hpp b/privacy/zsl/zsl/algebra/fields/fp6_3over2.hpp new file mode 100644 index 0000000..335d61c --- /dev/null +++ b/privacy/zsl/zsl/algebra/fields/fp6_3over2.hpp @@ -0,0 +1,104 @@ +/** @file + ***************************************************************************** + Declaration of arithmetic in the finite field F[(p^2)^3] + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP6_3OVER2_HPP_ +#define FP6_3OVER2_HPP_ +#include "algebra/fields/fp.hpp" +#include "algebra/fields/fp2.hpp" +#include + +namespace libsnark { + +template& modulus> +class Fp6_3over2_model; + +template& modulus> +std::ostream& operator<<(std::ostream &, const Fp6_3over2_model &); + +template& modulus> +std::istream& operator>>(std::istream &, Fp6_3over2_model &); + +/** + * Arithmetic in the finite field F[(p^2)^3]. + * + * Let p := modulus. This interface provides arithmetic for the extension field + * Fp6 = Fp2[V]/(V^3-non_residue) where non_residue is in Fp. + * + * ASSUMPTION: p = 1 (mod 6) + */ +template& modulus> +class Fp6_3over2_model { +public: + typedef Fp_model my_Fp; + typedef Fp2_model my_Fp2; + + static my_Fp2 non_residue; + static my_Fp2 Frobenius_coeffs_c1[6]; // non_residue^((modulus^i-1)/3) for i=0,1,2,3,4,5 + static my_Fp2 Frobenius_coeffs_c2[6]; // non_residue^((2*modulus^i-2)/3) for i=0,1,2,3,4,5 + + my_Fp2 c0, c1, c2; + Fp6_3over2_model() {}; + Fp6_3over2_model(const my_Fp2& c0, const my_Fp2& c1, const my_Fp2& c2) : c0(c0), c1(c1), c2(c2) {}; + + void clear() { c0.clear(); c1.clear(); c2.clear(); } + void print() const { printf("c0/c1/c2:\n"); c0.print(); c1.print(); c2.print(); } + + static Fp6_3over2_model zero(); + static Fp6_3over2_model one(); + static Fp6_3over2_model random_element(); + + bool is_zero() const { return c0.is_zero() && c1.is_zero() && c2.is_zero(); } + bool operator==(const Fp6_3over2_model &other) const; + bool operator!=(const Fp6_3over2_model &other) const; + + Fp6_3over2_model operator+(const Fp6_3over2_model &other) const; + Fp6_3over2_model operator-(const Fp6_3over2_model &other) const; + Fp6_3over2_model operator*(const Fp6_3over2_model &other) const; + Fp6_3over2_model operator-() const; + Fp6_3over2_model squared() const; + Fp6_3over2_model inverse() const; + Fp6_3over2_model Frobenius_map(unsigned long power) const; + + static my_Fp2 mul_by_non_residue(const my_Fp2 &elt); + + template + Fp6_3over2_model operator^(const bigint &other) const; + + static bigint base_field_char() { return modulus; } + static size_t extension_degree() { return 6; } + + friend std::ostream& operator<< (std::ostream &out, const Fp6_3over2_model &el); + friend std::istream& operator>> (std::istream &in, Fp6_3over2_model &el); +}; + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v); + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v); + +template& modulus> +Fp6_3over2_model operator*(const Fp_model &lhs, const Fp6_3over2_model &rhs); + +template& modulus> +Fp6_3over2_model operator*(const Fp2_model &lhs, const Fp6_3over2_model &rhs); + +template& modulus> +Fp2_model Fp6_3over2_model::non_residue; + +template& modulus> +Fp2_model Fp6_3over2_model::Frobenius_coeffs_c1[6]; + +template& modulus> +Fp2_model Fp6_3over2_model::Frobenius_coeffs_c2[6]; + +} // libsnark +#include "algebra/fields/fp6_3over2.tcc" + +#endif // FP6_3OVER2_HPP_ diff --git a/privacy/zsl/zsl/algebra/fields/fp6_3over2.tcc b/privacy/zsl/zsl/algebra/fields/fp6_3over2.tcc new file mode 100644 index 0000000..f4fffde --- /dev/null +++ b/privacy/zsl/zsl/algebra/fields/fp6_3over2.tcc @@ -0,0 +1,216 @@ +/** @file + ***************************************************************************** + Implementation of arithmetic in the finite field F[(p^2)^3]. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP6_3OVER2_TCC_ +#define FP6_3OVER2_TCC_ +#include "algebra/fields/field_utils.hpp" + +namespace libsnark { + +template& modulus> +Fp2_model Fp6_3over2_model::mul_by_non_residue(const Fp2_model &elt) +{ + return Fp2_model(non_residue * elt); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::zero() +{ + return Fp6_3over2_model(my_Fp2::zero(), my_Fp2::zero(), my_Fp2::zero()); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::one() +{ + return Fp6_3over2_model(my_Fp2::one(), my_Fp2::zero(), my_Fp2::zero()); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::random_element() +{ + Fp6_3over2_model r; + r.c0 = my_Fp2::random_element(); + r.c1 = my_Fp2::random_element(); + r.c2 = my_Fp2::random_element(); + + return r; +} + +template& modulus> +bool Fp6_3over2_model::operator==(const Fp6_3over2_model &other) const +{ + return (this->c0 == other.c0 && this->c1 == other.c1 && this->c2 == other.c2); +} + +template& modulus> +bool Fp6_3over2_model::operator!=(const Fp6_3over2_model &other) const +{ + return !(operator==(other)); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::operator+(const Fp6_3over2_model &other) const +{ + return Fp6_3over2_model(this->c0 + other.c0, + this->c1 + other.c1, + this->c2 + other.c2); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::operator-(const Fp6_3over2_model &other) const +{ + return Fp6_3over2_model(this->c0 - other.c0, + this->c1 - other.c1, + this->c2 - other.c2); +} + +template& modulus> +Fp6_3over2_model operator*(const Fp_model &lhs, const Fp6_3over2_model &rhs) +{ + return Fp6_3over2_model(lhs*rhs.c0, + lhs*rhs.c1, + lhs*rhs.c2); +} + +template& modulus> +Fp6_3over2_model operator*(const Fp2_model &lhs, const Fp6_3over2_model &rhs) +{ + return Fp6_3over2_model(lhs*rhs.c0, + lhs*rhs.c1, + lhs*rhs.c2); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::operator*(const Fp6_3over2_model &other) const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (Karatsuba) */ + + const my_Fp2 &A = other.c0, &B = other.c1, &C = other.c2, + &a = this->c0, &b = this->c1, &c = this->c2; + const my_Fp2 aA = a*A; + const my_Fp2 bB = b*B; + const my_Fp2 cC = c*C; + + return Fp6_3over2_model(aA + Fp6_3over2_model::mul_by_non_residue((b+c)*(B+C)-bB-cC), + (a+b)*(A+B)-aA-bB+Fp6_3over2_model::mul_by_non_residue(cC), + (a+c)*(A+C)-aA+bB-cC); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::operator-() const +{ + return Fp6_3over2_model(-this->c0, + -this->c1, + -this->c2); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::squared() const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (CH-SQR2) */ + + const my_Fp2 &a = this->c0, &b = this->c1, &c = this->c2; + const my_Fp2 s0 = a.squared(); + const my_Fp2 ab = a*b; + const my_Fp2 s1 = ab + ab; + const my_Fp2 s2 = (a - b + c).squared(); + const my_Fp2 bc = b*c; + const my_Fp2 s3 = bc + bc; + const my_Fp2 s4 = c.squared(); + + return Fp6_3over2_model(s0 + Fp6_3over2_model::mul_by_non_residue(s3), + s1 + Fp6_3over2_model::mul_by_non_residue(s4), + s1 + s2 + s3 - s0 - s4); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::inverse() const +{ + /* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 17 */ + + const my_Fp2 &a = this->c0, &b = this->c1, &c = this->c2; + const my_Fp2 t0 = a.squared(); + const my_Fp2 t1 = b.squared(); + const my_Fp2 t2 = c.squared(); + const my_Fp2 t3 = a*b; + const my_Fp2 t4 = a*c; + const my_Fp2 t5 = b*c; + const my_Fp2 c0 = t0 - Fp6_3over2_model::mul_by_non_residue(t5); + const my_Fp2 c1 = Fp6_3over2_model::mul_by_non_residue(t2) - t3; + const my_Fp2 c2 = t1 - t4; // typo in paper referenced above. should be "-" as per Scott, but is "*" + const my_Fp2 t6 = (a * c0 + Fp6_3over2_model::mul_by_non_residue((c * c1 + b * c2))).inverse(); + return Fp6_3over2_model(t6 * c0, t6 * c1, t6 * c2); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::Frobenius_map(unsigned long power) const +{ + return Fp6_3over2_model(c0.Frobenius_map(power), + Frobenius_coeffs_c1[power % 6] * c1.Frobenius_map(power), + Frobenius_coeffs_c2[power % 6] * c2.Frobenius_map(power)); +} + +template& modulus> +template +Fp6_3over2_model Fp6_3over2_model::operator^(const bigint &pow) const +{ + return power, m>(*this, pow); +} + +template& modulus> +std::ostream& operator<<(std::ostream &out, const Fp6_3over2_model &el) +{ + out << el.c0 << OUTPUT_SEPARATOR << el.c1 << OUTPUT_SEPARATOR << el.c2; + return out; +} + +template& modulus> +std::istream& operator>>(std::istream &in, Fp6_3over2_model &el) +{ + in >> el.c0 >> el.c1 >> el.c2; + return in; +} + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v) +{ + out << v.size() << "\n"; + for (const Fp6_3over2_model& t : v) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v) +{ + v.clear(); + + size_t s; + in >> s; + + char b; + in.read(&b, 1); + + v.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + Fp6_3over2_model el; + in >> el; + v.emplace_back(el); + } + + return in; +} + +} // libsnark +#endif // FP6_3_OVER_2_TCC_ diff --git a/privacy/zsl/zsl/algebra/fields/fp_aux.tcc b/privacy/zsl/zsl/algebra/fields/fp_aux.tcc new file mode 100644 index 0000000..7f8a3ea --- /dev/null +++ b/privacy/zsl/zsl/algebra/fields/fp_aux.tcc @@ -0,0 +1,389 @@ +/** @file + ***************************************************************************** + Assembly code snippets for F[p] finite field arithmetic, used by fp.tcc . + Specific to x86-64, and used only if USE_ASM is defined. + On other architectures or without USE_ASM, fp.tcc uses a portable + C++ implementation instead. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP_AUX_TCC_ +#define FP_AUX_TCC_ + +namespace libsnark { + +#define STR_HELPER(x) #x +#define STR(x) STR_HELPER(x) + +/* addq is faster than adcq, even if preceded by clc */ +#define ADD_FIRSTADD \ + "movq (%[B]), %%rax \n\t" \ + "addq %%rax, (%[A]) \n\t" + +#define ADD_NEXTADD(ofs) \ + "movq " STR(ofs) "(%[B]), %%rax \n\t" \ + "adcq %%rax, " STR(ofs) "(%[A]) \n\t" + +#define ADD_CMP(ofs) \ + "movq " STR(ofs) "(%[mod]), %%rax \n\t" \ + "cmpq %%rax, " STR(ofs) "(%[A]) \n\t" \ + "jb done%= \n\t" \ + "ja subtract%= \n\t" + +#define ADD_FIRSTSUB \ + "movq (%[mod]), %%rax \n\t" \ + "subq %%rax, (%[A]) \n\t" + +#define ADD_FIRSTSUB \ + "movq (%[mod]), %%rax \n\t" \ + "subq %%rax, (%[A]) \n\t" + +#define ADD_NEXTSUB(ofs) \ + "movq " STR(ofs) "(%[mod]), %%rax \n\t" \ + "sbbq %%rax, " STR(ofs) "(%[A]) \n\t" + +#define SUB_FIRSTSUB \ + "movq (%[B]), %%rax\n\t" \ + "subq %%rax, (%[A])\n\t" + +#define SUB_NEXTSUB(ofs) \ + "movq " STR(ofs) "(%[B]), %%rax\n\t" \ + "sbbq %%rax, " STR(ofs) "(%[A])\n\t" + +#define SUB_FIRSTADD \ + "movq (%[mod]), %%rax\n\t" \ + "addq %%rax, (%[A])\n\t" + +#define SUB_NEXTADD(ofs) \ + "movq " STR(ofs) "(%[mod]), %%rax\n\t" \ + "adcq %%rax, " STR(ofs) "(%[A])\n\t" + +#define MONT_CMP(ofs) \ + "movq " STR(ofs) "(%[M]), %%rax \n\t" \ + "cmpq %%rax, " STR(ofs) "(%[tmp]) \n\t" \ + "jb done%= \n\t" \ + "ja subtract%= \n\t" + +#define MONT_FIRSTSUB \ + "movq (%[M]), %%rax \n\t" \ + "subq %%rax, (%[tmp]) \n\t" + +#define MONT_NEXTSUB(ofs) \ + "movq " STR(ofs) "(%[M]), %%rax \n\t" \ + "sbbq %%rax, " STR(ofs) "(%[tmp]) \n\t" + +/* + The x86-64 Montgomery multiplication here is similar + to Algorithm 2 (CIOS method) in http://eprint.iacr.org/2012/140.pdf + and the PowerPC pseudocode of gmp-ecm library (c) Paul Zimmermann and Alexander Kruppa + (see comments on top of powerpc64/mulredc.m4). +*/ + +#define MONT_PRECOMPUTE \ + "xorq %[cy], %[cy] \n\t" \ + "movq 0(%[A]), %%rax \n\t" \ + "mulq 0(%[B]) \n\t" \ + "movq %%rax, %[T0] \n\t" \ + "movq %%rdx, %[T1] # T1:T0 <- A[0] * B[0] \n\t" \ + "mulq %[inv] \n\t" \ + "movq %%rax, %[u] # u <- T0 * inv \n\t" \ + "mulq 0(%[M]) \n\t" \ + "addq %[T0], %%rax \n\t" \ + "adcq %%rdx, %[T1] \n\t" \ + "adcq $0, %[cy] # cy:T1 <- (M[0]*u + T1 * b + T0) / b\n\t" + +#define MONT_FIRSTITER(j) \ + "xorq %[T0], %[T0] \n\t" \ + "movq 0(%[A]), %%rax \n\t" \ + "mulq " STR((j*8)) "(%[B]) \n\t" \ + "addq %[T1], %%rax \n\t" \ + "movq %%rax, " STR(((j-1)*8)) "(%[tmp]) \n\t" \ + "adcq $0, %%rdx \n\t" \ + "movq %%rdx, %[T1] # now T1:tmp[j-1] <-- X[0] * Y[j] + T1\n\t" \ + "movq " STR((j*8)) "(%[M]), %%rax \n\t" \ + "mulq %[u] \n\t" \ + "addq %%rax, " STR(((j-1)*8)) "(%[tmp]) \n\t" \ + "adcq %[cy], %%rdx \n\t" \ + "adcq $0, %[T0] \n\t" \ + "xorq %[cy], %[cy] \n\t" \ + "addq %%rdx, %[T1] \n\t" \ + "adcq %[T0], %[cy] # cy:T1:tmp[j-1] <---- (X[0] * Y[j] + T1) + (M[j] * u + cy * b) \n\t" + +#define MONT_ITERFIRST(i) \ + "xorq %[cy], %[cy] \n\t" \ + "movq " STR((i*8)) "(%[A]), %%rax \n\t" \ + "mulq 0(%[B]) \n\t" \ + "addq 0(%[tmp]), %%rax \n\t" \ + "adcq 8(%[tmp]), %%rdx \n\t" \ + "adcq $0, %[cy] \n\t" \ + "movq %%rax, %[T0] \n\t" \ + "movq %%rdx, %[T1] # cy:T1:T0 <- A[i] * B[0] + tmp[1] * b + tmp[0]\n\t" \ + "mulq %[inv] \n\t" \ + "movq %%rax, %[u] # u <- T0 * inv\n\t" \ + "mulq 0(%[M]) \n\t" \ + "addq %[T0], %%rax \n\t" \ + "adcq %%rdx, %[T1] \n\t" \ + "adcq $0, %[cy] # cy:T1 <- (M[0]*u + cy * b * b + T1 * b + T0) / b\n\t" + +#define MONT_ITERITER(i, j) \ + "xorq %[T0], %[T0] \n\t" \ + "movq " STR((i*8)) "(%[A]), %%rax \n\t" \ + "mulq " STR((j*8)) "(%[B]) \n\t" \ + "addq %[T1], %%rax \n\t" \ + "movq %%rax, " STR(((j-1)*8)) "(%[tmp]) \n\t" \ + "adcq $0, %%rdx \n\t" \ + "movq %%rdx, %[T1] # now T1:tmp[j-1] <-- X[i] * Y[j] + T1 \n\t" \ + "movq " STR((j*8)) "(%[M]), %%rax \n\t" \ + "mulq %[u] \n\t" \ + "addq %%rax, " STR(((j-1)*8)) "(%[tmp]) \n\t" \ + "adcq %[cy], %%rdx \n\t" \ + "adcq $0, %[T0] \n\t" \ + "xorq %[cy], %[cy] \n\t" \ + "addq %%rdx, %[T1] \n\t" \ + "adcq %[T0], %[cy] # cy:T1:tmp[j-1] <-- (X[i] * Y[j] + T1) + M[j] * u + cy * b \n\t" \ + "addq " STR(((j+1)*8)) "(%[tmp]), %[T1] \n\t" \ + "adcq $0, %[cy] # cy:T1:tmp[j-1] <-- (X[i] * Y[j] + T1) + M[j] * u + (tmp[j+1] + cy) * b \n\t" + +#define MONT_FINALIZE(j) \ + "movq %[T1], " STR((j*8)) "(%[tmp]) \n\t" \ + "movq %[cy], " STR(((j+1)*8)) "(%[tmp]) \n\t" + +/* + Comba multiplication and squaring routines are based on the + public-domain tomsfastmath library by Tom St Denis + + + + Compared to the above, we save 5-20% of cycles by using careful register + renaming to implement Comba forward operation. + */ + +#define COMBA_3_BY_3_MUL(c0_, c1_, c2_, res_, A_, B_) \ + asm volatile ( \ + "movq 0(%[A]), %%rax \n\t" \ + "mulq 0(%[B]) \n\t" \ + "movq %%rax, 0(%[res]) \n\t" \ + "movq %%rdx, %[c0] \n\t" \ + \ + "xorq %[c1], %[c1] \n\t" \ + "movq 0(%[A]), %%rax \n\t" \ + "mulq 8(%[B]) \n\t" \ + "addq %%rax, %[c0] \n\t" \ + "adcq %%rdx, %[c1] \n\t" \ + \ + "xorq %[c2], %[c2] \n\t" \ + "movq 8(%[A]), %%rax \n\t" \ + "mulq 0(%[B]) \n\t" \ + "addq %%rax, %[c0] \n\t" \ + "movq %[c0], 8(%[res]) \n\t" \ + "adcq %%rdx, %[c1] \n\t" \ + "adcq $0, %[c2] \n\t" \ + \ + "// register renaming (c1, c2, c0)\n\t" \ + "xorq %[c0], %[c0] \n\t" \ + "movq 0(%[A]), %%rax \n\t" \ + "mulq 16(%[B]) \n\t" \ + "addq %%rax, %[c1] \n\t" \ + "adcq %%rdx, %[c2] \n\t" \ + "adcq $0, %[c0] \n\t" \ + \ + "movq 8(%[A]), %%rax \n\t" \ + "mulq 8(%[B]) \n\t" \ + "addq %%rax, %[c1] \n\t" \ + "adcq %%rdx, %[c2] \n\t" \ + "adcq $0, %[c0] \n\t" \ + \ + "movq 16(%[A]), %%rax \n\t" \ + "mulq 0(%[B]) \n\t" \ + "addq %%rax, %[c1] \n\t" \ + "movq %[c1], 16(%[res]) \n\t" \ + "adcq %%rdx, %[c2] \n\t" \ + "adcq $0, %[c0] \n\t" \ + \ + "// register renaming (c2, c0, c1)\n\t" \ + "xorq %[c1], %[c1] \n\t" \ + "movq 8(%[A]), %%rax \n\t" \ + "mulq 16(%[B]) \n\t" \ + "addq %%rax, %[c2] \n\t" \ + "adcq %%rdx, %[c0] \n\t" \ + "adcq $0, %[c1] \n\t" \ + \ + "movq 16(%[A]), %%rax \n\t" \ + "mulq 8(%[B]) \n\t" \ + "addq %%rax, %[c2] \n\t" \ + "movq %[c2], 24(%[res]) \n\t" \ + "adcq %%rdx, %[c0] \n\t" \ + "adcq $0, %[c1] \n\t" \ + \ + "// register renaming (c0, c1, c2)\n\t" \ + "xorq %[c2], %[c2] \n\t" \ + "movq 16(%[A]), %%rax \n\t" \ + "mulq 16(%[B]) \n\t" \ + "addq %%rax, %[c0] \n\t" \ + "movq %[c0], 32(%[res]) \n\t" \ + "adcq %%rdx, %[c1] \n\t" \ + "movq %[c1], 40(%[res]) \n\t" \ + : [c0] "=&r" (c0_), [c1] "=&r" (c1_), [c2] "=&r" (c2_) \ + : [res] "r" (res_), [A] "r" (A_), [B] "r" (B_) \ + : "%rax", "%rdx", "cc", "memory") + +#define COMBA_3_BY_3_SQR(c0_, c1_, c2_, res_, A_) \ + asm volatile ( \ + "xorq %[c1], %[c1] \n\t" \ + "xorq %[c2], %[c2] \n\t" \ + "movq 0(%[A]), %%rax \n\t" \ + "mulq %%rax \n\t" \ + "movq %%rax, 0(%[res]) \n\t" \ + "movq %%rdx, %[c0] \n\t" \ + \ + "movq 0(%[A]), %%rax \n\t" \ + "mulq 8(%[A]) \n\t" \ + "addq %%rax, %[c0] \n\t" \ + "adcq %%rdx, %[c1] \n\t" \ + "addq %%rax, %[c0] \n\t" \ + "movq %[c0], 8(%[res]) \n\t" \ + "adcq %%rdx, %[c1] \n\t" \ + "adcq $0, %[c2] \n\t" \ + \ + "// register renaming (c1, c2, c0)\n\t" \ + "movq 0(%[A]), %%rax \n\t" \ + "xorq %[c0], %[c0] \n\t" \ + "mulq 16(%[A]) \n\t" \ + "addq %%rax, %[c1] \n\t" \ + "adcq %%rdx, %[c2] \n\t" \ + "adcq $0, %[c0] \n\t" \ + "addq %%rax, %[c1] \n\t" \ + "adcq %%rdx, %[c2] \n\t" \ + "adcq $0, %[c0] \n\t" \ + \ + "movq 8(%[A]), %%rax \n\t" \ + "mulq %%rax \n\t" \ + "addq %%rax, %[c1] \n\t" \ + "movq %[c1], 16(%[res]) \n\t" \ + "adcq %%rdx, %[c2] \n\t" \ + "adcq $0, %[c0] \n\t" \ + \ + "// register renaming (c2, c0, c1)\n\t" \ + "movq 8(%[A]), %%rax \n\t" \ + "xorq %[c1], %[c1] \n\t" \ + "mulq 16(%[A]) \n\t" \ + "addq %%rax, %[c2] \n\t" \ + "adcq %%rdx, %[c0] \n\t" \ + "adcq $0, %[c1] \n\t" \ + "addq %%rax, %[c2] \n\t" \ + "movq %[c2], 24(%[res]) \n\t" \ + "adcq %%rdx, %[c0] \n\t" \ + "adcq $0, %[c1] \n\t" \ + \ + "// register renaming (c0, c1, c2)\n\t" \ + "movq 16(%[A]), %%rax \n\t" \ + "mulq %%rax \n\t" \ + "addq %%rax, %[c0] \n\t" \ + "movq %[c0], 32(%[res]) \n\t" \ + "adcq %%rdx, %[c1] \n\t" \ + "movq %[c1], 40(%[res]) \n\t" \ + \ + : [c0] "=&r" (c0_), [c1] "=&r" (c1_), [c2] "=&r" (c2_) \ + : [res] "r" (res_), [A] "r" (A_) \ + : "%rax", "%rdx", "cc", "memory") + +/* + The Montgomery reduction here is based on Algorithm 14.32 in + Handbook of Applied Cryptography + . + */ +#define REDUCE_6_LIMB_PRODUCT(k_, tmp1_, tmp2_, tmp3_, inv_, res_, mod_) \ + __asm__ volatile \ + ("///////////////////////////////////\n\t" \ + "movq 0(%[res]), %%rax \n\t" \ + "mulq %[modprime] \n\t" \ + "movq %%rax, %[k] \n\t" \ + \ + "movq (%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "movq %%rax, %[tmp1] \n\t" \ + "movq %%rdx, %[tmp2] \n\t" \ + \ + "xorq %[tmp3], %[tmp3] \n\t" \ + "movq 8(%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "addq %[tmp1], 0(%[res]) \n\t" \ + "adcq %%rax, %[tmp2] \n\t" \ + "adcq %%rdx, %[tmp3] \n\t" \ + \ + "xorq %[tmp1], %[tmp1] \n\t" \ + "movq 16(%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "addq %[tmp2], 8(%[res]) \n\t" \ + "adcq %%rax, %[tmp3] \n\t" \ + "adcq %%rdx, %[tmp1] \n\t" \ + \ + "addq %[tmp3], 16(%[res]) \n\t" \ + "adcq %[tmp1], 24(%[res]) \n\t" \ + "adcq $0, 32(%[res]) \n\t" \ + "adcq $0, 40(%[res]) \n\t" \ + \ + "///////////////////////////////////\n\t" \ + "movq 8(%[res]), %%rax \n\t" \ + "mulq %[modprime] \n\t" \ + "movq %%rax, %[k] \n\t" \ + \ + "movq (%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "movq %%rax, %[tmp1] \n\t" \ + "movq %%rdx, %[tmp2] \n\t" \ + \ + "xorq %[tmp3], %[tmp3] \n\t" \ + "movq 8(%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "addq %[tmp1], 8(%[res]) \n\t" \ + "adcq %%rax, %[tmp2] \n\t" \ + "adcq %%rdx, %[tmp3] \n\t" \ + \ + "xorq %[tmp1], %[tmp1] \n\t" \ + "movq 16(%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "addq %[tmp2], 16(%[res]) \n\t" \ + "adcq %%rax, %[tmp3] \n\t" \ + "adcq %%rdx, %[tmp1] \n\t" \ + \ + "addq %[tmp3], 24(%[res]) \n\t" \ + "adcq %[tmp1], 32(%[res]) \n\t" \ + "adcq $0, 40(%[res]) \n\t" \ + \ + "///////////////////////////////////\n\t" \ + "movq 16(%[res]), %%rax \n\t" \ + "mulq %[modprime] \n\t" \ + "movq %%rax, %[k] \n\t" \ + \ + "movq (%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "movq %%rax, %[tmp1] \n\t" \ + "movq %%rdx, %[tmp2] \n\t" \ + \ + "xorq %[tmp3], %[tmp3] \n\t" \ + "movq 8(%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "addq %[tmp1], 16(%[res]) \n\t" \ + "adcq %%rax, %[tmp2] \n\t" \ + "adcq %%rdx, %[tmp3] \n\t" \ + \ + "xorq %[tmp1], %[tmp1] \n\t" \ + "movq 16(%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "addq %[tmp2], 24(%[res]) \n\t" \ + "adcq %%rax, %[tmp3] \n\t" \ + "adcq %%rdx, %[tmp1] \n\t" \ + \ + "addq %[tmp3], 32(%[res]) \n\t" \ + "adcq %[tmp1], 40(%[res]) \n\t" \ + : [k] "=&r" (k_), [tmp1] "=&r" (tmp1_), [tmp2] "=&r" (tmp2_), [tmp3] "=&r" (tmp3_) \ + : [modprime] "r" (inv_), [res] "r" (res_), [mod] "r" (mod_) \ + : "%rax", "%rdx", "cc", "memory") + +} // libsnark +#endif // FP_AUX_TCC_ diff --git a/privacy/zsl/zsl/algebra/fields/tests/test_fields.cpp b/privacy/zsl/zsl/algebra/fields/tests/test_fields.cpp new file mode 100644 index 0000000..a05f601 --- /dev/null +++ b/privacy/zsl/zsl/algebra/fields/tests/test_fields.cpp @@ -0,0 +1,245 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include "common/profiling.hpp" +#include "algebra/curves/edwards/edwards_pp.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +#ifdef CURVE_BN128 +#include "algebra/curves/bn128/bn128_pp.hpp" +#endif +#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" +#include "algebra/fields/fp6_3over2.hpp" +#include "algebra/fields/fp12_2over3over2.hpp" + +using namespace libsnark; + +template +void test_field() +{ + bigint<1> rand1 = bigint<1>("76749407"); + bigint<1> rand2 = bigint<1>("44410867"); + bigint<1> randsum = bigint<1>("121160274"); + + FieldT zero = FieldT::zero(); + FieldT one = FieldT::one(); + FieldT a = FieldT::random_element(); + FieldT a_ser; + a_ser = reserialize(a); + assert(a_ser == a); + + FieldT b = FieldT::random_element(); + FieldT c = FieldT::random_element(); + FieldT d = FieldT::random_element(); + + assert(a != zero); + assert(a != one); + + assert(a * a == a.squared()); + assert((a + b).squared() == a.squared() + a*b + b*a + b.squared()); + assert((a + b)*(c + d) == a*c + a*d + b*c + b*d); + assert(a - b == a + (-b)); + assert(a - b == (-b) + a); + + assert((a ^ rand1) * (a ^ rand2) == (a^randsum)); + + assert(a * a.inverse() == one); + assert((a + b) * c.inverse() == a * c.inverse() + (b.inverse() * c).inverse()); + +} + +template +void test_sqrt() +{ + for (size_t i = 0; i < 100; ++i) + { + FieldT a = FieldT::random_element(); + FieldT asq = a.squared(); + assert(asq.sqrt() == a || asq.sqrt() == -a); + } +} + +template +void test_two_squarings() +{ + FieldT a = FieldT::random_element(); + assert(a.squared() == a * a); + assert(a.squared() == a.squared_complex()); + assert(a.squared() == a.squared_karatsuba()); +} + +template +void test_Frobenius() +{ + FieldT a = FieldT::random_element(); + assert(a.Frobenius_map(0) == a); + FieldT a_q = a ^ FieldT::base_field_char(); + for (size_t power = 1; power < 10; ++power) + { + const FieldT a_qi = a.Frobenius_map(power); + assert(a_qi == a_q); + + a_q = a_q ^ FieldT::base_field_char(); + } +} + +template +void test_unitary_inverse() +{ + assert(FieldT::extension_degree() % 2 == 0); + FieldT a = FieldT::random_element(); + FieldT aqcubed_minus1 = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); + assert(aqcubed_minus1.inverse() == aqcubed_minus1.unitary_inverse()); +} + +template +void test_cyclotomic_squaring(); + +template<> +void test_cyclotomic_squaring >() +{ + typedef Fqk FieldT; + assert(FieldT::extension_degree() % 2 == 0); + FieldT a = FieldT::random_element(); + FieldT a_unitary = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); + // beta = a^((q^(k/2)-1)*(q+1)) + FieldT beta = a_unitary.Frobenius_map(1) * a_unitary; + assert(beta.cyclotomic_squared() == beta.squared()); +} + +template<> +void test_cyclotomic_squaring >() +{ + typedef Fqk FieldT; + assert(FieldT::extension_degree() % 2 == 0); + FieldT a = FieldT::random_element(); + FieldT a_unitary = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); + // beta = a^(q^(k/2)-1) + FieldT beta = a_unitary; + assert(beta.cyclotomic_squared() == beta.squared()); +} + +template<> +void test_cyclotomic_squaring >() +{ + typedef Fqk FieldT; + assert(FieldT::extension_degree() % 2 == 0); + FieldT a = FieldT::random_element(); + FieldT a_unitary = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); + // beta = a^((q^(k/2)-1)*(q+1)) + FieldT beta = a_unitary.Frobenius_map(1) * a_unitary; + assert(beta.cyclotomic_squared() == beta.squared()); +} + +template +void test_all_fields() +{ + test_field >(); + test_field >(); + test_field >(); + test_field >(); + + test_sqrt >(); + test_sqrt >(); + test_sqrt >(); + + test_Frobenius >(); + test_Frobenius >(); + + test_unitary_inverse >(); +} + +template +void test_Fp4_tom_cook() +{ + typedef typename Fp4T::my_Fp FieldT; + for (size_t i = 0; i < 100; ++i) + { + const Fp4T a = Fp4T::random_element(); + const Fp4T b = Fp4T::random_element(); + const Fp4T correct_res = a * b; + + Fp4T res; + + const FieldT + &a0 = a.c0.c0, + &a1 = a.c1.c0, + &a2 = a.c0.c1, + &a3 = a.c1.c1; + + const FieldT + &b0 = b.c0.c0, + &b1 = b.c1.c0, + &b2 = b.c0.c1, + &b3 = b.c1.c1; + + FieldT + &c0 = res.c0.c0, + &c1 = res.c1.c0, + &c2 = res.c0.c1, + &c3 = res.c1.c1; + + const FieldT v0 = a0 * b0; + const FieldT v1 = (a0 + a1 + a2 + a3) * (b0 + b1 + b2 + b3); + const FieldT v2 = (a0 - a1 + a2 - a3) * (b0 - b1 + b2 - b3); + const FieldT v3 = (a0 + FieldT(2)*a1 + FieldT(4)*a2 + FieldT(8)*a3) * (b0 + FieldT(2)*b1 + FieldT(4)*b2 + FieldT(8)*b3); + const FieldT v4 = (a0 - FieldT(2)*a1 + FieldT(4)*a2 - FieldT(8)*a3) * (b0 - FieldT(2)*b1 + FieldT(4)*b2 - FieldT(8)*b3); + const FieldT v5 = (a0 + FieldT(3)*a1 + FieldT(9)*a2 + FieldT(27)*a3) * (b0 + FieldT(3)*b1 + FieldT(9)*b2 + FieldT(27)*b3); + const FieldT v6 = a3 * b3; + + const FieldT beta = Fp4T::non_residue; + + c0 = v0 + beta*(FieldT(4).inverse()*v0 - FieldT(6).inverse()*(v1 + v2) + FieldT(24).inverse() * (v3 + v4) - FieldT(5) * v6); + c1 = - FieldT(3).inverse()*v0 + v1 - FieldT(2).inverse()*v2 - FieldT(4).inverse()*v3 + FieldT(20).inverse() * v4 + FieldT(30).inverse() * v5 - FieldT(12) * v6 + beta * ( - FieldT(12).inverse() * (v0 - v1) + FieldT(24).inverse()*(v2 - v3) - FieldT(120).inverse() * (v4 - v5) - FieldT(3) * v6); + c2 = - (FieldT(5)*(FieldT(4).inverse()))* v0 + (FieldT(2)*(FieldT(3).inverse()))*(v1 + v2) - FieldT(24).inverse()*(v3 + v4) + FieldT(4)*v6 + beta*v6; + c3 = FieldT(12).inverse() * (FieldT(5)*v0 - FieldT(7)*v1) - FieldT(24).inverse()*(v2 - FieldT(7)*v3 + v4 + v5) + FieldT(15)*v6; + + assert(res == correct_res); + + // {v0, v3, v4, v5} + const FieldT u = (FieldT::one() - beta).inverse(); + assert(v0 == u * c0 + beta * u * c2 - beta * u * FieldT(2).inverse() * v1 - beta * u * FieldT(2).inverse() * v2 + beta * v6); + assert(v3 == - FieldT(15) * u * c0 - FieldT(30) * u * c1 - FieldT(3) * (FieldT(4) + beta) * u * c2 - FieldT(6) * (FieldT(4) + beta) * u * c3 + (FieldT(24) - FieldT(3) * beta * FieldT(2).inverse()) * u * v1 + (-FieldT(8) + beta * FieldT(2).inverse()) * u * v2 + - FieldT(3) * (-FieldT(16) + beta) * v6); + assert(v4 == - FieldT(15) * u * c0 + FieldT(30) * u * c1 - FieldT(3) * (FieldT(4) + beta) * u * c2 + FieldT(6) * (FieldT(4) + beta) * u * c3 + (FieldT(24) - FieldT(3) * beta * FieldT(2).inverse()) * u * v2 + (-FieldT(8) + beta * FieldT(2).inverse()) * u * v1 + - FieldT(3) * (-FieldT(16) + beta) * v6); + assert(v5 == - FieldT(80) * u * c0 - FieldT(240) * u * c1 - FieldT(8) * (FieldT(9) + beta) * u * c2 - FieldT(24) * (FieldT(9) + beta) * u * c3 - FieldT(2) * (-FieldT(81) + beta) * u * v1 + (-FieldT(81) + beta) * u * v2 + - FieldT(8) * (-FieldT(81) + beta) * v6); + + // c0 + beta c2 - (beta v1)/2 - (beta v2)/ 2 - (-1 + beta) beta v6, + // -15 c0 - 30 c1 - 3 (4 + beta) c2 - 6 (4 + beta) c3 + (24 - (3 beta)/2) v1 + (-8 + beta/2) v2 + 3 (-16 + beta) (-1 + beta) v6, + // -15 c0 + 30 c1 - 3 (4 + beta) c2 + 6 (4 + beta) c3 + (-8 + beta/2) v1 + (24 - (3 beta)/2) v2 + 3 (-16 + beta) (-1 + beta) v6, + // -80 c0 - 240 c1 - 8 (9 + beta) c2 - 24 (9 + beta) c3 - 2 (-81 + beta) v1 + (-81 + beta) v2 + 8 (-81 + beta) (-1 + beta) v6 + } +} + +int main(void) +{ + edwards_pp::init_public_params(); + test_all_fields(); + test_cyclotomic_squaring >(); + + mnt4_pp::init_public_params(); + test_all_fields(); + test_Fp4_tom_cook(); + test_two_squarings >(); + test_cyclotomic_squaring >(); + + mnt6_pp::init_public_params(); + test_all_fields(); + test_cyclotomic_squaring >(); + + alt_bn128_pp::init_public_params(); + test_field(); + test_Frobenius(); + test_all_fields(); + +#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled + bn128_pp::init_public_params(); + test_field >(); + test_field >(); +#endif +} diff --git a/privacy/zsl/zsl/algebra/knowledge_commitment/knowledge_commitment.hpp b/privacy/zsl/zsl/algebra/knowledge_commitment/knowledge_commitment.hpp new file mode 100644 index 0000000..9024231 --- /dev/null +++ b/privacy/zsl/zsl/algebra/knowledge_commitment/knowledge_commitment.hpp @@ -0,0 +1,84 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for: + - a knowledge commitment, and + - a knowledge commitment vector. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef KNOWLEDGE_COMMITMENT_HPP_ +#define KNOWLEDGE_COMMITMENT_HPP_ + +#include "algebra/fields/fp.hpp" +#include "common/data_structures/sparse_vector.hpp" + +namespace libsnark { + +/********************** Knowledge commitment *********************************/ + +/** + * A knowledge commitment is a pair (g,h) where g is in T1 and h in T2, + * and T1 and T2 are groups (written additively). + * + * Such pairs form a group by defining: + * - "zero" = (0,0) + * - "one" = (1,1) + * - a * (g,h) + b * (g',h') := ( a * g + b * g', a * h + b * h'). + */ +template +struct knowledge_commitment { + + T1 g; + T2 h; + + knowledge_commitment() = default; + knowledge_commitment(const knowledge_commitment &other) = default; + knowledge_commitment(knowledge_commitment &&other) = default; + knowledge_commitment(const T1 &g, const T2 &h); + + knowledge_commitment& operator=(const knowledge_commitment &other) = default; + knowledge_commitment& operator=(knowledge_commitment &&other) = default; + knowledge_commitment operator+(const knowledge_commitment &other) const; + + bool is_zero() const; + bool operator==(const knowledge_commitment &other) const; + bool operator!=(const knowledge_commitment &other) const; + + static knowledge_commitment zero(); + static knowledge_commitment one(); + + void print() const; + + static size_t size_in_bits(); +}; + +template +knowledge_commitment operator*(const bigint &lhs, const knowledge_commitment &rhs); + +template &modulus_p> +knowledge_commitment operator*(const Fp_model &lhs, const knowledge_commitment &rhs); + +template +std::ostream& operator<<(std::ostream& out, const knowledge_commitment &kc); + +template +std::istream& operator>>(std::istream& in, knowledge_commitment &kc); + +/******************** Knowledge commitment vector ****************************/ + +/** + * A knowledge commitment vector is a sparse vector of knowledge commitments. + */ +template +using knowledge_commitment_vector = sparse_vector >; + +} // libsnark + +#include "algebra/knowledge_commitment/knowledge_commitment.tcc" + +#endif // KNOWLEDGE_COMMITMENT_HPP_ diff --git a/privacy/zsl/zsl/algebra/knowledge_commitment/knowledge_commitment.tcc b/privacy/zsl/zsl/algebra/knowledge_commitment/knowledge_commitment.tcc new file mode 100644 index 0000000..15b2926 --- /dev/null +++ b/privacy/zsl/zsl/algebra/knowledge_commitment/knowledge_commitment.tcc @@ -0,0 +1,111 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for: + - a knowledge commitment, and + - a knowledge commitment vector. + + See knowledge_commitment.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef KNOWLEDGE_COMMITMENT_TCC_ +#define KNOWLEDGE_COMMITMENT_TCC_ + +namespace libsnark { + +template +knowledge_commitment::knowledge_commitment(const T1 &g, const T2 &h) : + g(g), h(h) +{ +} + +template +knowledge_commitment knowledge_commitment::zero() +{ + return knowledge_commitment(T1::zero(), T2::zero()); +} + +template +knowledge_commitment knowledge_commitment::one() +{ + return knowledge_commitment(T1::one(), T2::one()); +} + +template +knowledge_commitment knowledge_commitment::operator+(const knowledge_commitment &other) const +{ + return knowledge_commitment(this->g + other.g, + this->h + other.h); +} + +template +bool knowledge_commitment::is_zero() const +{ + return (g.is_zero() && h.is_zero()); +} + +template +bool knowledge_commitment::operator==(const knowledge_commitment &other) const +{ + return (this->g == other.g && + this->h == other.h); +} + +template +bool knowledge_commitment::operator!=(const knowledge_commitment &other) const +{ + return !((*this) == other); +} + +template +knowledge_commitment operator*(const bigint &lhs, const knowledge_commitment &rhs) +{ + return knowledge_commitment(lhs * rhs.g, + lhs * rhs.h); +} + +template &modulus_p> +knowledge_commitment operator*(const Fp_model &lhs, const knowledge_commitment &rhs) +{ + return (lhs.as_bigint()) * rhs; +} + +template +void knowledge_commitment::print() const +{ + printf("knowledge_commitment.g:\n"); + g.print(); + printf("knowledge_commitment.h:\n"); + h.print(); +} + +template +size_t knowledge_commitment::size_in_bits() +{ + return T1::size_in_bits() + T2::size_in_bits(); +} + +template +std::ostream& operator<<(std::ostream& out, const knowledge_commitment &kc) +{ + out << kc.g << OUTPUT_SEPARATOR << kc.h; + return out; +} + +template +std::istream& operator>>(std::istream& in, knowledge_commitment &kc) +{ + in >> kc.g; + consume_OUTPUT_SEPARATOR(in); + in >> kc.h; + return in; +} + +} // libsnark + +#endif // KNOWLEDGE_COMMITMENT_TCC_ diff --git a/privacy/zsl/zsl/algebra/scalar_multiplication/kc_multiexp.hpp b/privacy/zsl/zsl/algebra/scalar_multiplication/kc_multiexp.hpp new file mode 100644 index 0000000..4e8b556 --- /dev/null +++ b/privacy/zsl/zsl/algebra/scalar_multiplication/kc_multiexp.hpp @@ -0,0 +1,55 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef KC_MULTIEXP_HPP_ +#define KC_MULTIEXP_HPP_ + +/* + Split out from multiexp to prevent cyclical + dependencies. I.e. previously multiexp dependend on + knowledge_commitment, which dependend on sparse_vector, which + dependend on multiexp (to do accumulate). + + Will probably go away in more general exp refactoring. +*/ + +#include "algebra/knowledge_commitment/knowledge_commitment.hpp" + +namespace libsnark { + +template +knowledge_commitment opt_window_wnaf_exp(const knowledge_commitment &base, + const bigint &scalar, const size_t scalar_bits); + +template +knowledge_commitment kc_multi_exp_with_mixed_addition(const knowledge_commitment_vector &vec, + const size_t min_idx, + const size_t max_idx, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end, + const size_t chunks, + const bool use_multiexp=false); + +template +void kc_batch_to_special(std::vector > &vec); + +template +knowledge_commitment_vector kc_batch_exp(const size_t scalar_size, + const size_t T1_window, + const size_t T2_window, + const window_table &T1_table, + const window_table &T2_table, + const FieldT &T1_coeff, + const FieldT &T2_coeff, + const std::vector &v, + const size_t suggested_num_chunks); + +} // libsnark + +#include "algebra/scalar_multiplication/kc_multiexp.tcc" + +#endif // KC_MULTIEXP_HPP_ diff --git a/privacy/zsl/zsl/algebra/scalar_multiplication/kc_multiexp.tcc b/privacy/zsl/zsl/algebra/scalar_multiplication/kc_multiexp.tcc new file mode 100644 index 0000000..e9c08d4 --- /dev/null +++ b/privacy/zsl/zsl/algebra/scalar_multiplication/kc_multiexp.tcc @@ -0,0 +1,274 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef KC_MULTIEXP_TCC_ +#define KC_MULTIEXP_TCC_ + +namespace libsnark { + +template +knowledge_commitment opt_window_wnaf_exp(const knowledge_commitment &base, + const bigint &scalar, const size_t scalar_bits) +{ + return knowledge_commitment(opt_window_wnaf_exp(base.g, scalar, scalar_bits), + opt_window_wnaf_exp(base.h, scalar, scalar_bits)); +} + +template +knowledge_commitment kc_multi_exp_with_mixed_addition(const knowledge_commitment_vector &vec, + const size_t min_idx, + const size_t max_idx, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end, + const size_t chunks, + const bool use_multiexp) +{ + enter_block("Process scalar vector"); + auto index_it = std::lower_bound(vec.indices.begin(), vec.indices.end(), min_idx); + const size_t offset = index_it - vec.indices.begin(); + + auto value_it = vec.values.begin() + offset; + + const FieldT zero = FieldT::zero(); + const FieldT one = FieldT::one(); + + std::vector p; + std::vector > g; + + knowledge_commitment acc = knowledge_commitment::zero(); + + size_t num_skip = 0; + size_t num_add = 0; + size_t num_other = 0; + + const size_t scalar_length = std::distance(scalar_start, scalar_end); + + while (index_it != vec.indices.end() && *index_it < max_idx) + { + const size_t scalar_position = (*index_it) - min_idx; + assert(scalar_position < scalar_length); + + const FieldT scalar = *(scalar_start + scalar_position); + + if (scalar == zero) + { + // do nothing + ++num_skip; + } + else if (scalar == one) + { +#ifdef USE_MIXED_ADDITION + acc.g = acc.g.mixed_add(value_it->g); + acc.h = acc.h.mixed_add(value_it->h); +#else + acc.g = acc.g + value_it->g; + acc.h = acc.h + value_it->h; +#endif + ++num_add; + } + else + { + p.emplace_back(scalar); + g.emplace_back(*value_it); + ++num_other; + } + + ++index_it; + ++value_it; + } + + //print_indent(); printf("* Elements of w skipped: %zu (%0.2f%%)\n", num_skip, 100.*num_skip/(num_skip+num_add+num_other)); + //print_indent(); printf("* Elements of w processed with special addition: %zu (%0.2f%%)\n", num_add, 100.*num_add/(num_skip+num_add+num_other)); + //print_indent(); printf("* Elements of w remaining: %zu (%0.2f%%)\n", num_other, 100.*num_other/(num_skip+num_add+num_other)); + leave_block("Process scalar vector"); + + return acc + multi_exp, FieldT>(g.begin(), g.end(), p.begin(), p.end(), chunks, use_multiexp); +} + +template +void kc_batch_to_special(std::vector > &vec) +{ + enter_block("Batch-convert knowledge-commitments to special form"); + + std::vector g_vec; + g_vec.reserve(vec.size()); + + for (size_t i = 0; i < vec.size(); ++i) + { + if (!vec[i].g.is_zero()) + { + g_vec.emplace_back(vec[i].g); + } + } + + batch_to_special_all_non_zeros(g_vec); + auto g_it = g_vec.begin(); + T1 T1_zero_special = T1::zero(); + T1_zero_special.to_special(); + + for (size_t i = 0; i < vec.size(); ++i) + { + if (!vec[i].g.is_zero()) + { + vec[i].g = *g_it; + ++g_it; + } + else + { + vec[i].g = T1_zero_special; + } + } + + g_vec.clear(); + + std::vector h_vec; + h_vec.reserve(vec.size()); + + for (size_t i = 0; i < vec.size(); ++i) + { + if (!vec[i].h.is_zero()) + { + h_vec.emplace_back(vec[i].h); + } + } + + batch_to_special_all_non_zeros(h_vec); + auto h_it = h_vec.begin(); + T2 T2_zero_special = T2::zero(); + T2_zero_special.to_special(); + + for (size_t i = 0; i < vec.size(); ++i) + { + if (!vec[i].h.is_zero()) + { + vec[i].h = *h_it; + ++h_it; + } + else + { + vec[i].h = T2_zero_special; + } + } + + g_vec.clear(); + + leave_block("Batch-convert knowledge-commitments to special form"); +} + +template +knowledge_commitment_vector kc_batch_exp_internal(const size_t scalar_size, + const size_t T1_window, + const size_t T2_window, + const window_table &T1_table, + const window_table &T2_table, + const FieldT &T1_coeff, + const FieldT &T2_coeff, + const std::vector &v, + const size_t start_pos, + const size_t end_pos, + const size_t expected_size) +{ + knowledge_commitment_vector res; + + res.values.reserve(expected_size); + res.indices.reserve(expected_size); + + for (size_t pos = start_pos; pos != end_pos; ++pos) + { + if (!v[pos].is_zero()) + { + res.values.emplace_back(knowledge_commitment(windowed_exp(scalar_size, T1_window, T1_table, T1_coeff * v[pos]), + windowed_exp(scalar_size, T2_window, T2_table, T2_coeff * v[pos]))); + res.indices.emplace_back(pos); + } + } + + return res; +} + +template +knowledge_commitment_vector kc_batch_exp(const size_t scalar_size, + const size_t T1_window, + const size_t T2_window, + const window_table &T1_table, + const window_table &T2_table, + const FieldT &T1_coeff, + const FieldT &T2_coeff, + const std::vector &v, + const size_t suggested_num_chunks) +{ + knowledge_commitment_vector res; + res.domain_size_ = v.size(); + + size_t nonzero = 0; + for (size_t i = 0; i < v.size(); ++i) + { + nonzero += (v[i].is_zero() ? 0 : 1); + } + + const size_t num_chunks = std::max((size_t)1, std::min(nonzero, suggested_num_chunks)); + + if (!inhibit_profiling_info) + { + print_indent(); printf("Non-zero coordinate count: %zu/%zu (%0.2f%%)\n", nonzero, v.size(), 100.*nonzero/v.size()); + } + + std::vector > tmp(num_chunks); + std::vector chunk_pos(num_chunks+1); + + const size_t chunk_size = nonzero / num_chunks; + const size_t last_chunk = nonzero - chunk_size * (num_chunks - 1); + + chunk_pos[0] = 0; + + size_t cnt = 0; + size_t chunkno = 1; + + for (size_t i = 0; i < v.size(); ++i) + { + cnt += (v[i].is_zero() ? 0 : 1); + if (cnt == chunk_size && chunkno < num_chunks) + { + chunk_pos[chunkno] = i; + cnt = 0; + ++chunkno; + } + } + + chunk_pos[num_chunks] = v.size(); + +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < num_chunks; ++i) + { + tmp[i] = kc_batch_exp_internal(scalar_size, T1_window, T2_window, T1_table, T2_table, T1_coeff, T2_coeff, v, + chunk_pos[i], chunk_pos[i+1], i == num_chunks - 1 ? last_chunk : chunk_size); +#ifdef USE_MIXED_ADDITION + kc_batch_to_special(tmp[i].values); +#endif + } + + if (num_chunks == 1) + { + tmp[0].domain_size_ = v.size(); + return tmp[0]; + } + else + { + for (size_t i = 0; i < num_chunks; ++i) + { + res.values.insert(res.values.end(), tmp[i].values.begin(), tmp[i].values.end()); + res.indices.insert(res.indices.end(), tmp[i].indices.begin(), tmp[i].indices.end()); + } + return res; + } +} + +} // libsnark + +#endif // KC_MULTIEXP_TCC_ diff --git a/privacy/zsl/zsl/algebra/scalar_multiplication/multiexp.hpp b/privacy/zsl/zsl/algebra/scalar_multiplication/multiexp.hpp new file mode 100644 index 0000000..eaf72d6 --- /dev/null +++ b/privacy/zsl/zsl/algebra/scalar_multiplication/multiexp.hpp @@ -0,0 +1,110 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for multi-exponentiation routines. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MULTIEXP_HPP_ +#define MULTIEXP_HPP_ + +namespace libsnark { + +/** + * Naive multi-exponentiation individually multiplies each base by the + * corresponding scalar and adds up the results. + */ +template +T naive_exp(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end); + +template +T naive_plain_exp(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end); + +/** + * Naive multi-exponentiation uses a variant of the Bos-Coster algorithm [1], + * and implementation suggestions from [2]. + * + * [1] = Bos and Coster, "Addition chain heuristics", CRYPTO '89 + * [2] = Bernstein, Duif, Lange, Schwabe, and Yang, "High-speed high-security signatures", CHES '11 + */ +template +T multi_exp(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end, + const size_t chunks, + const bool use_multiexp=false); + + +/** + * A variant of multi_exp that takes advantage of the method mixed_add (instead of the operator '+'). + */ +template +T multi_exp_with_mixed_addition(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end, + const size_t chunks, + const bool use_multiexp); + +/** + * A window table stores window sizes for different instance sizes for fixed-base multi-scalar multiplications. + */ +template +using window_table = std::vector >; + +/** + * Compute window size for the given number of scalars. + */ +template +size_t get_exp_window_size(const size_t num_scalars); + +/** + * Compute table of window sizes. + */ +template +window_table get_window_table(const size_t scalar_size, + const size_t window, + const T &g); + +template +T windowed_exp(const size_t scalar_size, + const size_t window, + const window_table &powers_of_g, + const FieldT &pow); + +template +std::vector batch_exp(const size_t scalar_size, + const size_t window, + const window_table &table, + const std::vector &v); + +template +std::vector batch_exp_with_coeff(const size_t scalar_size, + const size_t window, + const window_table &table, + const FieldT &coeff, + const std::vector &v); + +// defined in every curve +template +void batch_to_special_all_non_zeros(std::vector &vec); + +template +void batch_to_special(std::vector &vec); + +} // libsnark + +#include "algebra/scalar_multiplication/multiexp.tcc" + +#endif // MULTIEXP_HPP_ diff --git a/privacy/zsl/zsl/algebra/scalar_multiplication/multiexp.tcc b/privacy/zsl/zsl/algebra/scalar_multiplication/multiexp.tcc new file mode 100644 index 0000000..a6b14c4 --- /dev/null +++ b/privacy/zsl/zsl/algebra/scalar_multiplication/multiexp.tcc @@ -0,0 +1,590 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for multi-exponentiation routines. + + See multiexp.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MULTIEXP_TCC_ +#define MULTIEXP_TCC_ + +#include "algebra/fields/fp_aux.tcc" + +#include +#include +#include + +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "algebra/scalar_multiplication/wnaf.hpp" + +namespace libsnark { + +template +class ordered_exponent { +// to use std::push_heap and friends later +public: + size_t idx; + bigint r; + + ordered_exponent(const size_t idx, const bigint &r) : idx(idx), r(r) {}; + + bool operator<(const ordered_exponent &other) const + { +#if defined(__x86_64__) && defined(USE_ASM) + if (n == 3) + { + long res; + __asm__ + ("// check for overflow \n\t" + "mov $0, %[res] \n\t" + ADD_CMP(16) + ADD_CMP(8) + ADD_CMP(0) + "jmp done%= \n\t" + "subtract%=: \n\t" + "mov $1, %[res] \n\t" + "done%=: \n\t" + : [res] "=&r" (res) + : [A] "r" (other.r.data), [mod] "r" (this->r.data) + : "cc", "%rax"); + return res; + } + else if (n == 4) + { + long res; + __asm__ + ("// check for overflow \n\t" + "mov $0, %[res] \n\t" + ADD_CMP(24) + ADD_CMP(16) + ADD_CMP(8) + ADD_CMP(0) + "jmp done%= \n\t" + "subtract%=: \n\t" + "mov $1, %[res] \n\t" + "done%=: \n\t" + : [res] "=&r" (res) + : [A] "r" (other.r.data), [mod] "r" (this->r.data) + : "cc", "%rax"); + return res; + } + else if (n == 5) + { + long res; + __asm__ + ("// check for overflow \n\t" + "mov $0, %[res] \n\t" + ADD_CMP(32) + ADD_CMP(24) + ADD_CMP(16) + ADD_CMP(8) + ADD_CMP(0) + "jmp done%= \n\t" + "subtract%=: \n\t" + "mov $1, %[res] \n\t" + "done%=: \n\t" + : [res] "=&r" (res) + : [A] "r" (other.r.data), [mod] "r" (this->r.data) + : "cc", "%rax"); + return res; + } + else +#endif + { + return (mpn_cmp(this->r.data, other.r.data, n) < 0); + } + } +}; + +template +T naive_exp(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end) +{ + T result(T::zero()); + + typename std::vector::const_iterator vec_it; + typename std::vector::const_iterator scalar_it; + + for (vec_it = vec_start, scalar_it = scalar_start; vec_it != vec_end; ++vec_it, ++scalar_it) + { + bigint scalar_bigint = scalar_it->as_bigint(); + result = result + opt_window_wnaf_exp(*vec_it, scalar_bigint, scalar_bigint.num_bits()); + } + assert(scalar_it == scalar_end); + + return result; +} + +template +T naive_plain_exp(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end) +{ + T result(T::zero()); + + typename std::vector::const_iterator vec_it; + typename std::vector::const_iterator scalar_it; + + for (vec_it = vec_start, scalar_it = scalar_start; vec_it != vec_end; ++vec_it, ++scalar_it) + { + result = result + (*scalar_it) * (*vec_it); + } + assert(scalar_it == scalar_end); + + return result; +} + +/* + The multi-exponentiation algorithm below is a variant of the Bos-Coster algorithm + [Bos and Coster, "Addition chain heuristics", CRYPTO '89]. + The implementation uses suggestions from + [Bernstein, Duif, Lange, Schwabe, and Yang, "High-speed high-security signatures", CHES '11]. +*/ +template +T multi_exp_inner(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end) +{ + const mp_size_t n = std::remove_reference::type::num_limbs; + + if (vec_start == vec_end) + { + return T::zero(); + } + + if (vec_start + 1 == vec_end) + { + return (*scalar_start)*(*vec_start); + } + + std::vector > opt_q; + const size_t vec_len = scalar_end - scalar_start; + const size_t odd_vec_len = (vec_len % 2 == 1 ? vec_len : vec_len + 1); + opt_q.reserve(odd_vec_len); + std::vector g; + g.reserve(odd_vec_len); + + typename std::vector::const_iterator vec_it; + typename std::vector::const_iterator scalar_it; + size_t i; + for (i=0, vec_it = vec_start, scalar_it = scalar_start; vec_it != vec_end; ++vec_it, ++scalar_it, ++i) + { + g.emplace_back(*vec_it); + + opt_q.emplace_back(ordered_exponent(i, scalar_it->as_bigint())); + } + std::make_heap(opt_q.begin(),opt_q.end()); + assert(scalar_it == scalar_end); + + if (vec_len != odd_vec_len) + { + g.emplace_back(T::zero()); + opt_q.emplace_back(ordered_exponent(odd_vec_len - 1, bigint(0ul))); + } + assert(g.size() % 2 == 1); + assert(opt_q.size() == g.size()); + + T opt_result = T::zero(); + + while (true) + { + ordered_exponent &a = opt_q[0]; + ordered_exponent &b = (opt_q[1] < opt_q[2] ? opt_q[2] : opt_q[1]); + + const size_t abits = a.r.num_bits(); + + if (b.r.is_zero()) + { + // opt_result = opt_result + (a.r * g[a.idx]); + opt_result = opt_result + opt_window_wnaf_exp(g[a.idx], a.r, abits); + break; + } + + const size_t bbits = b.r.num_bits(); + const size_t limit = (abits-bbits >= 20 ? 20 : abits-bbits); + + if (bbits < 1ul< (x-y) A + y (B+A) + mpn_sub_n(a.r.data, a.r.data, b.r.data, n); + g[b.idx] = g[b.idx] + g[a.idx]; + } + + // regardless of whether a was cleared or subtracted from we push it down, then take back up + + /* heapify A down */ + size_t a_pos = 0; + while (2*a_pos + 2< odd_vec_len) + { + // this is a max-heap so to maintain a heap property we swap with the largest of the two + if (opt_q[2*a_pos+1] < opt_q[2*a_pos+2]) + { + std::swap(opt_q[a_pos], opt_q[2*a_pos+2]); + a_pos = 2*a_pos+2; + } + else + { + std::swap(opt_q[a_pos], opt_q[2*a_pos+1]); + a_pos = 2*a_pos+1; + } + } + + /* now heapify A up appropriate amount of times */ + while (a_pos > 0 && opt_q[(a_pos-1)/2] < opt_q[a_pos]) + { + std::swap(opt_q[a_pos], opt_q[(a_pos-1)/2]); + a_pos = (a_pos-1) / 2; + } + } + + return opt_result; +} + +template +T multi_exp(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end, + const size_t chunks, + const bool use_multiexp) +{ + const size_t total = vec_end - vec_start; + if (total < chunks) + { + return naive_exp(vec_start, vec_end, scalar_start, scalar_end); + } + + const size_t one = total/chunks; + + std::vector partial(chunks, T::zero()); + + if (use_multiexp) + { +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < chunks; ++i) + { + partial[i] = multi_exp_inner(vec_start + i*one, + (i == chunks-1 ? vec_end : vec_start + (i+1)*one), + scalar_start + i*one, + (i == chunks-1 ? scalar_end : scalar_start + (i+1)*one)); + } + } + else + { +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < chunks; ++i) + { + partial[i] = naive_exp(vec_start + i*one, + (i == chunks-1 ? vec_end : vec_start + (i+1)*one), + scalar_start + i*one, + (i == chunks-1 ? scalar_end : scalar_start + (i+1)*one)); + } + } + + T final = T::zero(); + + for (size_t i = 0; i < chunks; ++i) + { + final = final + partial[i]; + } + + return final; +} + +template +T multi_exp_with_mixed_addition(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end, + const size_t chunks, + const bool use_multiexp) +{ + assert(std::distance(vec_start, vec_end) == std::distance(scalar_start, scalar_end)); + enter_block("Process scalar vector"); + auto value_it = vec_start; + auto scalar_it = scalar_start; + + const FieldT zero = FieldT::zero(); + const FieldT one = FieldT::one(); + std::vector p; + std::vector g; + + T acc = T::zero(); + + size_t num_skip = 0; + size_t num_add = 0; + size_t num_other = 0; + + for (; scalar_it != scalar_end; ++scalar_it, ++value_it) + { + if (*scalar_it == zero) + { + // do nothing + ++num_skip; + } + else if (*scalar_it == one) + { +#ifdef USE_MIXED_ADDITION + acc = acc.mixed_add(*value_it); +#else + acc = acc + (*value_it); +#endif + ++num_add; + } + else + { + p.emplace_back(*scalar_it); + g.emplace_back(*value_it); + ++num_other; + } + } + //print_indent(); printf("* Elements of w skipped: %zu (%0.2f%%)\n", num_skip, 100.*num_skip/(num_skip+num_add+num_other)); + //print_indent(); printf("* Elements of w processed with special addition: %zu (%0.2f%%)\n", num_add, 100.*num_add/(num_skip+num_add+num_other)); + //print_indent(); printf("* Elements of w remaining: %zu (%0.2f%%)\n", num_other, 100.*num_other/(num_skip+num_add+num_other)); + + leave_block("Process scalar vector"); + + return acc + multi_exp(g.begin(), g.end(), p.begin(), p.end(), chunks, use_multiexp); +} + +template +size_t get_exp_window_size(const size_t num_scalars) +{ + if (T::fixed_base_exp_window_table.empty()) + { +#ifdef LOWMEM + return 14; +#else + return 17; +#endif + } + size_t window = 1; + for (long i = T::fixed_base_exp_window_table.size()-1; i >= 0; --i) + { +#ifdef DEBUG + if (!inhibit_profiling_info) + { + printf("%ld %zu %zu\n", i, num_scalars, T::fixed_base_exp_window_table[i]); + } +#endif + if (T::fixed_base_exp_window_table[i] != 0 && num_scalars >= T::fixed_base_exp_window_table[i]) + { + window = i+1; + break; + } + } + + if (!inhibit_profiling_info) + { + print_indent(); printf("Choosing window size %zu for %zu elements\n", window, num_scalars); + } + +#ifdef LOWMEM + window = std::min((size_t)14, window); +#endif + return window; +} + +template +window_table get_window_table(const size_t scalar_size, + const size_t window, + const T &g) +{ + const size_t in_window = 1ul< powers_of_g(outerc, std::vector(in_window, T::zero())); + + T gouter = g; + + for (size_t outer = 0; outer < outerc; ++outer) + { + T ginner = T::zero(); + size_t cur_in_window = outer == outerc-1 ? last_in_window : in_window; + for (size_t inner = 0; inner < cur_in_window; ++inner) + { + powers_of_g[outer][inner] = ginner; + ginner = ginner + gouter; + } + + for (size_t i = 0; i < window; ++i) + { + gouter = gouter + gouter; + } + } + + return powers_of_g; +} + +template +T windowed_exp(const size_t scalar_size, + const size_t window, + const window_table &powers_of_g, + const FieldT &pow) +{ + const size_t outerc = (scalar_size+window-1)/window; + const bigint pow_val = pow.as_bigint(); + + /* exp */ + T res = powers_of_g[0][0]; + + for (size_t outer = 0; outer < outerc; ++outer) + { + size_t inner = 0; + for (size_t i = 0; i < window; ++i) + { + if (pow_val.test_bit(outer*window + i)) + { + inner |= 1u << i; + } + } + + res = res + powers_of_g[outer][inner]; + } + + return res; +} + +template +std::vector batch_exp(const size_t scalar_size, + const size_t window, + const window_table &table, + const std::vector &v) +{ + if (!inhibit_profiling_info) + { + print_indent(); + } + std::vector res(v.size(), table[0][0]); + +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < v.size(); ++i) + { + res[i] = windowed_exp(scalar_size, window, table, v[i]); + + if (!inhibit_profiling_info && (i % 10000 == 0)) + { + printf("."); + fflush(stdout); + } + } + + if (!inhibit_profiling_info) + { + printf(" DONE!\n"); + } + + return res; +} + +template +std::vector batch_exp_with_coeff(const size_t scalar_size, + const size_t window, + const window_table &table, + const FieldT &coeff, + const std::vector &v) +{ + if (!inhibit_profiling_info) + { + print_indent(); + } + std::vector res(v.size(), table[0][0]); + +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < v.size(); ++i) + { + res[i] = windowed_exp(scalar_size, window, table, coeff * v[i]); + + if (!inhibit_profiling_info && (i % 10000 == 0)) + { + printf("."); + fflush(stdout); + } + } + + if (!inhibit_profiling_info) + { + printf(" DONE!\n"); + } + + return res; +} + +template +void batch_to_special(std::vector &vec) +{ + enter_block("Batch-convert elements to special form"); + + std::vector non_zero_vec; + for (size_t i = 0; i < vec.size(); ++i) + { + if (!vec[i].is_zero()) + { + non_zero_vec.emplace_back(vec[i]); + } + } + + batch_to_special_all_non_zeros(non_zero_vec); + auto it = non_zero_vec.begin(); + T zero_special = T::zero(); + zero_special.to_special(); + + for (size_t i = 0; i < vec.size(); ++i) + { + if (!vec[i].is_zero()) + { + vec[i] = *it; + ++it; + } + else + { + vec[i] = zero_special; + } + } + leave_block("Batch-convert elements to special form"); +} + +} // libsnark + +#endif // MULTIEXP_TCC_ diff --git a/privacy/zsl/zsl/algebra/scalar_multiplication/wnaf.hpp b/privacy/zsl/zsl/algebra/scalar_multiplication/wnaf.hpp new file mode 100644 index 0000000..a7ecd59 --- /dev/null +++ b/privacy/zsl/zsl/algebra/scalar_multiplication/wnaf.hpp @@ -0,0 +1,39 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for wNAF ("width-w Non-Adjacent Form") exponentiation routines. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WNAF_HPP_ +#define WNAF_HPP_ + +namespace libsnark { + +/** + * Find the wNAF representation of the given scalar relative to the given window size. + */ +template +std::vector find_wnaf(const size_t window_size, const bigint &scalar); + +/** + * In additive notation, use wNAF exponentiation (with the given window size) to compute scalar * base. + */ +template +T fixed_window_wnaf_exp(const size_t window_size, const T &base, const bigint &scalar); + +/** + * In additive notation, use wNAF exponentiation (with the window size determined by T) to compute scalar * base. + */ +template +T opt_window_wnaf_exp(const T &base, const bigint &scalar, const size_t scalar_bits); + +} // libsnark + +#include "algebra/scalar_multiplication/wnaf.tcc" + +#endif // WNAF_HPP_ diff --git a/privacy/zsl/zsl/algebra/scalar_multiplication/wnaf.tcc b/privacy/zsl/zsl/algebra/scalar_multiplication/wnaf.tcc new file mode 100644 index 0000000..a5e47e8 --- /dev/null +++ b/privacy/zsl/zsl/algebra/scalar_multiplication/wnaf.tcc @@ -0,0 +1,123 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for wNAF ("weighted Non-Adjacent Form") exponentiation routines. + + See wnaf.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WNAF_TCC_ +#define WNAF_TCC_ + +namespace libsnark { + +template +std::vector find_wnaf(const size_t window_size, const bigint &scalar) +{ + const size_t length = scalar.max_bits(); // upper bound + std::vector res(length+1); + bigint c = scalar; + long j = 0; + while (!c.is_zero()) + { + long u; + if ((c.data[0] & 1) == 1) + { + u = c.data[0] % (1u << (window_size+1)); + if (u > (1 << window_size)) + { + u = u - (1 << (window_size+1)); + } + + if (u > 0) + { + mpn_sub_1(c.data, c.data, n, u); + } + else + { + mpn_add_1(c.data, c.data, n, -u); + } + } + else + { + u = 0; + } + res[j] = u; + ++j; + + mpn_rshift(c.data, c.data, n, 1); // c = c/2 + } + + return res; +} + +template +T fixed_window_wnaf_exp(const size_t window_size, const T &base, const bigint &scalar) +{ + std::vector naf = find_wnaf(window_size, scalar); + std::vector table(1ul<<(window_size-1)); + T tmp = base; + T dbl = base.dbl(); + for (size_t i = 0; i < 1ul<<(window_size-1); ++i) + { + table[i] = tmp; + tmp = tmp + dbl; + } + + T res = T::zero(); + bool found_nonzero = false; + for (long i = naf.size()-1; i >= 0; --i) + { + if (found_nonzero) + { + res = res.dbl(); + } + + if (naf[i] != 0) + { + found_nonzero = true; + if (naf[i] > 0) + { + res = res + table[naf[i]/2]; + } + else + { + res = res - table[(-naf[i])/2]; + } + } + } + + return res; +} + +template +T opt_window_wnaf_exp(const T &base, const bigint &scalar, const size_t scalar_bits) +{ + size_t best = 0; + for (long i = T::wnaf_window_table.size() - 1; i >= 0; --i) + { + if (scalar_bits >= T::wnaf_window_table[i]) + { + best = i+1; + break; + } + } + + if (best > 0) + { + return fixed_window_wnaf_exp(best, base, scalar); + } + else + { + return scalar * base; + } +} + +} // libsnark + +#endif // WNAF_TCC_ diff --git a/privacy/zsl/zsl/common/data_structures/accumulation_vector.hpp b/privacy/zsl/zsl/common/data_structures/accumulation_vector.hpp new file mode 100644 index 0000000..d46b406 --- /dev/null +++ b/privacy/zsl/zsl/common/data_structures/accumulation_vector.hpp @@ -0,0 +1,74 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for an accumulation vector. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ACCUMULATION_VECTOR_HPP_ +#define ACCUMULATION_VECTOR_HPP_ + +#include "common/data_structures/sparse_vector.hpp" + +namespace libsnark { + +template +class accumulation_vector; + +template +std::ostream& operator<<(std::ostream &out, const accumulation_vector &v); + +template +std::istream& operator>>(std::istream &in, accumulation_vector &v); + +/** + * An accumulation vector comprises an accumulation value and a sparse vector. + * The method "accumulate_chunk" allows one to accumulate portions of the sparse + * vector into the accumulation value. + */ +template +class accumulation_vector { +public: + T first; + sparse_vector rest; + + accumulation_vector() = default; + accumulation_vector(const accumulation_vector &other) = default; + accumulation_vector(accumulation_vector &&other) = default; + accumulation_vector(T &&first, sparse_vector &&rest) : first(std::move(first)), rest(std::move(rest)) {}; + accumulation_vector(T &&first, std::vector &&v) : first(std::move(first)), rest(std::move(v)) {} + accumulation_vector(std::vector &&v) : first(T::zero()), rest(std::move(v)) {}; + + accumulation_vector& operator=(const accumulation_vector &other) = default; + accumulation_vector& operator=(accumulation_vector &&other) = default; + + bool operator==(const accumulation_vector &other) const; + + bool is_fully_accumulated() const; + + size_t domain_size() const; + size_t size() const; + size_t size_in_bits() const; + + template + accumulation_vector accumulate_chunk(const typename std::vector::const_iterator &it_begin, + const typename std::vector::const_iterator &it_end, + const size_t offset) const; + +}; + +template +std::ostream& operator<<(std::ostream &out, const accumulation_vector &v); + +template +std::istream& operator>>(std::istream &in, accumulation_vector &v); + +} // libsnark + +#include "common/data_structures/accumulation_vector.tcc" + +#endif // ACCUMULATION_VECTOR_HPP_ diff --git a/privacy/zsl/zsl/common/data_structures/accumulation_vector.tcc b/privacy/zsl/zsl/common/data_structures/accumulation_vector.tcc new file mode 100644 index 0000000..9e524ab --- /dev/null +++ b/privacy/zsl/zsl/common/data_structures/accumulation_vector.tcc @@ -0,0 +1,84 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for an accumulation vector. + + See accumulation_vector.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ACCUMULATION_VECTOR_TCC_ +#define ACCUMULATION_VECTOR_TCC_ + +namespace libsnark { + +template +bool accumulation_vector::operator==(const accumulation_vector &other) const +{ + return (this->first == other.first && this->rest == other.rest); +} + +template +bool accumulation_vector::is_fully_accumulated() const +{ + return rest.empty(); +} + +template +size_t accumulation_vector::domain_size() const +{ + return rest.domain_size(); +} + +template +size_t accumulation_vector::size() const +{ + return rest.domain_size(); +} + +template +size_t accumulation_vector::size_in_bits() const +{ + const size_t first_size_in_bits = T::size_in_bits(); + const size_t rest_size_in_bits = rest.size_in_bits(); + return first_size_in_bits + rest_size_in_bits; +} + +template +template +accumulation_vector accumulation_vector::accumulate_chunk(const typename std::vector::const_iterator &it_begin, + const typename std::vector::const_iterator &it_end, + const size_t offset) const +{ + std::pair > acc_result = rest.template accumulate(it_begin, it_end, offset); + T new_first = first + acc_result.first; + return accumulation_vector(std::move(new_first), std::move(acc_result.second)); +} + +template +std::ostream& operator<<(std::ostream& out, const accumulation_vector &v) +{ + out << v.first << OUTPUT_NEWLINE; + out << v.rest << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream& in, accumulation_vector &v) +{ + in >> v.first; + consume_OUTPUT_NEWLINE(in); + in >> v.rest; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +} // libsnark + +#endif // ACCUMULATION_VECTOR_TCC_ diff --git a/privacy/zsl/zsl/common/data_structures/integer_permutation.cpp b/privacy/zsl/zsl/common/data_structures/integer_permutation.cpp new file mode 100644 index 0000000..378ea7e --- /dev/null +++ b/privacy/zsl/zsl/common/data_structures/integer_permutation.cpp @@ -0,0 +1,121 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a permutation of the integers in {min_element,...,max_element}. + + See integer_permutation.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "common/data_structures/integer_permutation.hpp" + +#include +#include +#include +#include + +namespace libsnark { + +integer_permutation::integer_permutation(const size_t size) : + min_element(0), max_element(size-1) +{ + contents.resize(size); + std::iota(contents.begin(), contents.end(), 0); +} + +integer_permutation::integer_permutation(const size_t min_element, const size_t max_element) : + min_element(min_element), max_element(max_element) +{ + assert(min_element <= max_element); + const size_t size = max_element - min_element + 1; + contents.resize(size); + std::iota(contents.begin(), contents.end(), min_element); +} + +size_t integer_permutation::size() const +{ + return max_element - min_element + 1; +} + +bool integer_permutation::operator==(const integer_permutation &other) const +{ + return (this->min_element == other.min_element && + this->max_element == other.max_element && + this->contents == other.contents); +} + +void integer_permutation::set(const size_t position, const size_t value) +{ + assert(min_element <= position && position <= max_element); + contents[position - min_element] = value; +} + +size_t integer_permutation::get(const size_t position) const +{ + assert(min_element <= position && position <= max_element); + return contents[position - min_element]; +} + + +bool integer_permutation::is_valid() const +{ + std::unordered_set elems; + + for (auto &el : contents) + { + if (el < min_element || el > max_element || elems.find(el) != elems.end()) + { + return false; + } + + elems.insert(el); + } + + return true; +} + +integer_permutation integer_permutation::inverse() const +{ + integer_permutation result(min_element, max_element); + + for (size_t position = min_element; position <= max_element; ++position) + { + result.contents[this->contents[position - min_element] - min_element] = position; + } + +#ifdef DEBUG + assert(result.is_valid()); +#endif + + return result; +} + +integer_permutation integer_permutation::slice(const size_t slice_min_element, const size_t slice_max_element) const +{ + assert(min_element <= slice_min_element && slice_min_element <= slice_max_element && slice_max_element <= max_element); + integer_permutation result(slice_min_element, slice_max_element); + std::copy(this->contents.begin() + (slice_min_element - min_element), + this->contents.begin() + (slice_max_element - min_element) + 1, + result.contents.begin()); +#ifdef DEBUG + assert(result.is_valid()); +#endif + + return result; +} + +bool integer_permutation::next_permutation() +{ + return std::next_permutation(contents.begin(), contents.end()); +} + +void integer_permutation::random_shuffle() +{ + return std::random_shuffle(contents.begin(), contents.end()); +} + +} // libsnark diff --git a/privacy/zsl/zsl/common/data_structures/integer_permutation.d b/privacy/zsl/zsl/common/data_structures/integer_permutation.d new file mode 100644 index 0000000..7118001 --- /dev/null +++ b/privacy/zsl/zsl/common/data_structures/integer_permutation.d @@ -0,0 +1,3 @@ +src/common/data_structures/integer_permutation.o: \ + src/common/data_structures/integer_permutation.cpp \ + src/common/data_structures/integer_permutation.hpp diff --git a/privacy/zsl/zsl/common/data_structures/integer_permutation.hpp b/privacy/zsl/zsl/common/data_structures/integer_permutation.hpp new file mode 100644 index 0000000..f55a750 --- /dev/null +++ b/privacy/zsl/zsl/common/data_structures/integer_permutation.hpp @@ -0,0 +1,54 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a permutation of the integers in {min_element,...,max_element}. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef INTEGER_PERMUTATION_HPP_ +#define INTEGER_PERMUTATION_HPP_ + +#include +#include + +namespace libsnark { + +class integer_permutation { +private: + std::vector contents; /* offset by min_element */ + +public: + size_t min_element; + size_t max_element; + + integer_permutation(const size_t size = 0); + integer_permutation(const size_t min_element, const size_t max_element); + + integer_permutation& operator=(const integer_permutation &other) = default; + + size_t size() const; + bool operator==(const integer_permutation &other) const; + + void set(const size_t position, const size_t value); + size_t get(const size_t position) const; + + bool is_valid() const; + integer_permutation inverse() const; + integer_permutation slice(const size_t slice_min_element, const size_t slice_max_element) const; + + /* Similarly to std::next_permutation this transforms the current + integer permutation into the next lexicographically oredered + permutation; returns false if the last permutation was reached and + this is now the identity permutation on [min_element .. max_element] */ + bool next_permutation(); + + void random_shuffle(); +}; + +} // libsnark + +#endif // INTEGER_PERMUTATION_HPP_ diff --git a/privacy/zsl/zsl/common/data_structures/merkle_tree.hpp b/privacy/zsl/zsl/common/data_structures/merkle_tree.hpp new file mode 100644 index 0000000..6f0c851 --- /dev/null +++ b/privacy/zsl/zsl/common/data_structures/merkle_tree.hpp @@ -0,0 +1,71 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a Merkle tree. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MERKLE_TREE_HPP_ +#define MERKLE_TREE_HPP_ + +#include +#include +#include "common/utils.hpp" + +namespace libsnark { + +/** + * A Merkle tree is maintained as two maps: + * - a map from addresses to values, and + * - a map from addresses to hashes. + * + * The second map maintains the intermediate hashes of a Merkle tree + * built atop the values currently stored in the tree (the + * implementation admits a very efficient support for sparse + * trees). Besides offering methods to load and store values, the + * class offers methods to retrieve the root of the Merkle tree and to + * obtain the authentication paths for (the value at) a given address. + */ + +typedef bit_vector merkle_authentication_node; +typedef std::vector merkle_authentication_path; + +template +class merkle_tree { +private: + + typedef typename HashT::hash_value_type hash_value_type; + typedef typename HashT::merkle_authentication_path_type merkle_authentication_path_type; + +public: + + std::vector hash_defaults; + std::map values; + std::map hashes; + + size_t depth; + size_t value_size; + size_t digest_size; + + merkle_tree(const size_t depth, const size_t value_size); + merkle_tree(const size_t depth, const size_t value_size, const std::vector &contents_as_vector); + merkle_tree(const size_t depth, const size_t value_size, const std::map &contents); + + bit_vector get_value(const size_t address) const; + void set_value(const size_t address, const bit_vector &value); + + hash_value_type get_root() const; + merkle_authentication_path_type get_path(const size_t address) const; + + void dump() const; +}; + +} // libsnark + +#include "common/data_structures/merkle_tree.tcc" + +#endif // MERKLE_TREE_HPP_ diff --git a/privacy/zsl/zsl/common/data_structures/merkle_tree.tcc b/privacy/zsl/zsl/common/data_structures/merkle_tree.tcc new file mode 100644 index 0000000..281700b --- /dev/null +++ b/privacy/zsl/zsl/common/data_structures/merkle_tree.tcc @@ -0,0 +1,246 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for Merkle tree. + + See merkle_tree.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MERKLE_TREE_TCC +#define MERKLE_TREE_TCC + +#include + +#include "common/profiling.hpp" +#include "common/utils.hpp" + +namespace libsnark { + +template +typename HashT::hash_value_type two_to_one_CRH(const typename HashT::hash_value_type &l, + const typename HashT::hash_value_type &r) +{ + typename HashT::hash_value_type new_input; + new_input.insert(new_input.end(), l.begin(), l.end()); + new_input.insert(new_input.end(), r.begin(), r.end()); + + const size_t digest_size = HashT::get_digest_len(); + assert(l.size() == digest_size); + assert(r.size() == digest_size); + + return HashT::get_hash(new_input); +} + +template +merkle_tree::merkle_tree(const size_t depth, const size_t value_size) : + depth(depth), value_size(value_size) +{ + assert(depth < sizeof(size_t) * 8); + + digest_size = HashT::get_digest_len(); + assert(value_size <= digest_size); + + hash_value_type last(digest_size); + hash_defaults.reserve(depth+1); + hash_defaults.emplace_back(last); + for (size_t i = 0; i < depth; ++i) + { + last = two_to_one_CRH(last, last); + hash_defaults.emplace_back(last); + } + + std::reverse(hash_defaults.begin(), hash_defaults.end()); +} + +template +merkle_tree::merkle_tree(const size_t depth, + const size_t value_size, + const std::vector &contents_as_vector) : + merkle_tree(depth, value_size) +{ + assert(log2(contents_as_vector.size()) <= depth); + for (size_t address = 0; address < contents_as_vector.size(); ++address) + { + const size_t idx = address + (1ul< 0; --layer) + { + for (size_t idx = idx_begin; idx < idx_end; idx += 2) + { + hash_value_type l = hashes[idx]; // this is sound, because idx_begin is always a left child + hash_value_type r = (idx + 1 < idx_end ? hashes[idx+1] : hash_defaults[layer]); + + hash_value_type h = two_to_one_CRH(l, r); + hashes[(idx-1)/2] = h; + } + + idx_begin = (idx_begin-1)/2; + idx_end = (idx_end-1)/2; + } +} + +template +merkle_tree::merkle_tree(const size_t depth, + const size_t value_size, + const std::map &contents) : + merkle_tree(depth, value_size) +{ + + if (!contents.empty()) + { + assert(contents.rbegin()->first < 1ul<first; + const bit_vector value = it->second; + const size_t idx = address + (1ul< 0; --layer) + { + auto next_last_it = hashes.begin(); + + for (auto it = hashes.begin(); it != last_it; ++it) + { + const size_t idx = it->first; + const hash_value_type hash = it->second; + + if (idx % 2 == 0) + { + // this is the right child of its parent and by invariant we are missing the left child + hashes[(idx-1)/2] = two_to_one_CRH(hash_defaults[layer], hash); + } + else + { + if (std::next(it) == last_it || std::next(it)->first != idx + 1) + { + // this is the left child of its parent and is missing its right child + hashes[(idx-1)/2] = two_to_one_CRH(hash, hash_defaults[layer]); + } + else + { + // typical case: this is the left child of the parent and adjecent to it there is a right child + hashes[(idx-1)/2] = two_to_one_CRH(hash, std::next(it)->second); + ++it; + } + } + } + + last_it = next_last_it; + } + } +} + +template +bit_vector merkle_tree::get_value(const size_t address) const +{ + assert(log2(address) <= depth); + + auto it = values.find(address); + bit_vector padded_result = (it == values.end() ? bit_vector(digest_size) : it->second); + padded_result.resize(value_size); + + return padded_result; +} + +template +void merkle_tree::set_value(const size_t address, + const bit_vector &value) +{ + assert(log2(address) <= depth); + size_t idx = address + (1ul<=0; --layer) + { + idx = (idx-1)/2; + + auto it = hashes.find(2*idx+1); + hash_value_type l = (it == hashes.end() ? hash_defaults[layer+1] : it->second); + + it = hashes.find(2*idx+2); + hash_value_type r = (it == hashes.end() ? hash_defaults[layer+1] : it->second); + + hash_value_type h = two_to_one_CRH(l, r); + hashes[idx] = h; + } +} + +template +typename HashT::hash_value_type merkle_tree::get_root() const +{ + auto it = hashes.find(0); + return (it == hashes.end() ? hash_defaults[0] : it->second); +} + +template +typename HashT::merkle_authentication_path_type merkle_tree::get_path(const size_t address) const +{ + typename HashT::merkle_authentication_path_type result(depth); + assert(log2(address) <= depth); + size_t idx = address + (1ul< 0; --layer) + { + size_t sibling_idx = ((idx + 1) ^ 1) - 1; + auto it = hashes.find(sibling_idx); + if (layer == depth) + { + auto it2 = values.find(sibling_idx - ((1ul<second); + result[layer-1].resize(digest_size); + } + else + { + result[layer-1] = (it == hashes.end() ? hash_defaults[layer] : it->second); + } + + idx = (idx-1)/2; + } + + return result; +} + +template +void merkle_tree::dump() const +{ + for (size_t i = 0; i < 1ul< ", i); + const bit_vector value = (it == values.end() ? bit_vector(value_size) : it->second); + for (bool b : value) + { + printf("%d", b ? 1 : 0); + } + printf("\n"); + } + printf("\n"); +} + +} // libsnark + +#endif // MERKLE_TREE_TCC diff --git a/privacy/zsl/zsl/common/data_structures/set_commitment.cpp b/privacy/zsl/zsl/common/data_structures/set_commitment.cpp new file mode 100644 index 0000000..07e3e1e --- /dev/null +++ b/privacy/zsl/zsl/common/data_structures/set_commitment.cpp @@ -0,0 +1,60 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "common/data_structures/set_commitment.hpp" +#include "common/serialization.hpp" + +namespace libsnark { + +bool set_membership_proof::operator==(const set_membership_proof &other) const +{ + return (this->address == other.address && + this->merkle_path == other.merkle_path); +} + +size_t set_membership_proof::size_in_bits() const +{ + if (merkle_path.empty()) + { + return (8 * sizeof(address)); + } + else + { + return (8 * sizeof(address) + merkle_path[0].size() * merkle_path.size()); + } +} + +std::ostream& operator<<(std::ostream &out, const set_membership_proof &proof) +{ + out << proof.address << "\n"; + out << proof.merkle_path.size() << "\n"; + for (size_t i = 0; i < proof.merkle_path.size(); ++i) + { + output_bool_vector(out, proof.merkle_path[i]); + } + + return out; +} + +std::istream& operator>>(std::istream &in, set_membership_proof &proof) +{ + in >> proof.address; + consume_newline(in); + size_t tree_depth; + in >> tree_depth; + consume_newline(in); + proof.merkle_path.resize(tree_depth); + + for (size_t i = 0; i < tree_depth; ++i) + { + input_bool_vector(in, proof.merkle_path[i]); + } + + return in; +} + +} // libsnark diff --git a/privacy/zsl/zsl/common/data_structures/set_commitment.d b/privacy/zsl/zsl/common/data_structures/set_commitment.d new file mode 100644 index 0000000..87e2f2b --- /dev/null +++ b/privacy/zsl/zsl/common/data_structures/set_commitment.d @@ -0,0 +1,18 @@ +src/common/data_structures/set_commitment.o: \ + src/common/data_structures/set_commitment.cpp \ + src/common/data_structures/set_commitment.hpp src/common/utils.hpp \ + src/common/utils.tcc src/common/data_structures/merkle_tree.hpp \ + src/common/data_structures/merkle_tree.tcc src/common/profiling.hpp \ + src/gadgetlib1/gadgets/hashes/hash_io.hpp \ + src/gadgetlib1/gadgets/basic_gadgets.hpp src/gadgetlib1/gadget.hpp \ + src/gadgetlib1/protoboard.hpp src/gadgetlib1/pb_variable.hpp \ + src/relations/variable.hpp src/relations/variable.tcc \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/algebra/fields/bigint.tcc \ + src/gadgetlib1/pb_variable.tcc \ + src/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp \ + src/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc \ + src/gadgetlib1/protoboard.tcc src/gadgetlib1/gadget.tcc \ + src/gadgetlib1/gadgets/basic_gadgets.tcc \ + src/gadgetlib1/gadgets/hashes/hash_io.tcc \ + src/common/data_structures/set_commitment.tcc diff --git a/privacy/zsl/zsl/common/data_structures/set_commitment.hpp b/privacy/zsl/zsl/common/data_structures/set_commitment.hpp new file mode 100644 index 0000000..c9c21f4 --- /dev/null +++ b/privacy/zsl/zsl/common/data_structures/set_commitment.hpp @@ -0,0 +1,60 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a Merkle tree based set commitment scheme. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SET_COMMITMENT_HPP_ +#define SET_COMMITMENT_HPP_ + +#include "common/utils.hpp" +#include "common/data_structures/merkle_tree.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" // TODO: the current structure is suboptimal + +namespace libsnark { + +typedef bit_vector set_commitment; + +struct set_membership_proof { + size_t address; + merkle_authentication_path merkle_path; + + bool operator==(const set_membership_proof &other) const; + size_t size_in_bits() const; + friend std::ostream& operator<<(std::ostream &out, const set_membership_proof &other); + friend std::istream& operator>>(std::istream &in, set_membership_proof &other); +}; + +template +class set_commitment_accumulator { +private: + std::shared_ptr > tree; + std::map hash_to_pos; +public: + + size_t depth; + size_t digest_size; + size_t value_size; + + set_commitment_accumulator(const size_t max_entries, const size_t value_size=0); + + void add(const bit_vector &value); + bool is_in_set(const bit_vector &value) const; + set_commitment get_commitment() const; + + set_membership_proof get_membership_proof(const bit_vector &value) const; +}; + +} // libsnark + +/* note that set_commitment has both .cpp, for implementation of + non-templatized code (methods of set_membership_proof) and .tcc + (implementation of set_commitment_accumulator */ +#include "common/data_structures/set_commitment.tcc" + +#endif // SET_COMMITMENT_HPP_ diff --git a/privacy/zsl/zsl/common/data_structures/set_commitment.tcc b/privacy/zsl/zsl/common/data_structures/set_commitment.tcc new file mode 100644 index 0000000..756509e --- /dev/null +++ b/privacy/zsl/zsl/common/data_structures/set_commitment.tcc @@ -0,0 +1,70 @@ +/** @file + ***************************************************************************** + + Implementation of a Merkle tree based set commitment scheme. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SET_COMMITMENT_TCC_ +#define SET_COMMITMENT_TCC_ + +namespace libsnark { + +template +set_commitment_accumulator::set_commitment_accumulator(const size_t max_entries, const size_t value_size) : + value_size(value_size) +{ + depth = log2(max_entries); + digest_size = HashT::get_digest_len(); + + tree.reset(new merkle_tree(depth, digest_size)); +} + +template +void set_commitment_accumulator::add(const bit_vector &value) +{ + assert(value_size == 0 || value.size() == value_size); + const bit_vector hash = HashT::get_hash(value); + if (hash_to_pos.find(hash) == hash_to_pos.end()) + { + const size_t pos = hash_to_pos.size(); + tree->set_value(pos, hash); + hash_to_pos[hash] = pos; + } +} + +template +bool set_commitment_accumulator::is_in_set(const bit_vector &value) const +{ + assert(value_size == 0 || value.size() == value_size); + const bit_vector hash = HashT::get_hash(value); + return (hash_to_pos.find(hash) != hash_to_pos.end()); +} + +template +set_commitment set_commitment_accumulator::get_commitment() const +{ + return tree->get_root(); +} + +template +set_membership_proof set_commitment_accumulator::get_membership_proof(const bit_vector &value) const +{ + const bit_vector hash = HashT::get_hash(value); + auto it = hash_to_pos.find(hash); + assert(it != hash_to_pos.end()); + + set_membership_proof proof; + proof.address = it->second; + proof.merkle_path = tree->get_path(it->second); + + return proof; +} + +} // libsnark + +#endif // SET_COMMITMENT_TCC_ diff --git a/privacy/zsl/zsl/common/data_structures/sparse_vector.hpp b/privacy/zsl/zsl/common/data_structures/sparse_vector.hpp new file mode 100644 index 0000000..552a8ae --- /dev/null +++ b/privacy/zsl/zsl/common/data_structures/sparse_vector.hpp @@ -0,0 +1,79 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a sparse vector. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SPARSE_VECTOR_HPP_ +#define SPARSE_VECTOR_HPP_ + +#include + +namespace libsnark { + +template +struct sparse_vector; + +template +std::ostream& operator<<(std::ostream &out, const sparse_vector &v); + +template +std::istream& operator>>(std::istream &in, sparse_vector &v); + +/** + * A sparse vector is a list of indices along with corresponding values. + * The indices are selected from the set {0,1,...,domain_size-1}. + */ +template +struct sparse_vector { + + std::vector indices; + std::vector values; + size_t domain_size_; + + sparse_vector() = default; + sparse_vector(const sparse_vector &other) = default; + sparse_vector(sparse_vector &&other) = default; + sparse_vector(std::vector &&v); /* constructor from std::vector */ + + sparse_vector& operator=(const sparse_vector &other) = default; + sparse_vector& operator=(sparse_vector &&other) = default; + + T operator[](const size_t idx) const; + + bool operator==(const sparse_vector &other) const; + bool operator==(const std::vector &other) const; + + bool is_valid() const; + bool empty() const; + + size_t domain_size() const; // return domain_size_ + size_t size() const; // return the number of indices (representing the number of non-zero entries) + size_t size_in_bits() const; // return the number bits needed to store the sparse vector + + /* return a pair consisting of the accumulated value and the sparse vector of non-accumuated values */ + template + std::pair > accumulate(const typename std::vector::const_iterator &it_begin, + const typename std::vector::const_iterator &it_end, + const size_t offset) const; + + friend std::ostream& operator<< (std::ostream &out, const sparse_vector &v); + friend std::istream& operator>> (std::istream &in, sparse_vector &v); +}; + +template +std::ostream& operator<<(std::ostream& out, const sparse_vector &v); + +template +std::istream& operator>>(std::istream& in, sparse_vector &v); + +} // libsnark + +#include "common/data_structures/sparse_vector.tcc" + +#endif // SPARSE_VECTOR_HPP_ diff --git a/privacy/zsl/zsl/common/data_structures/sparse_vector.tcc b/privacy/zsl/zsl/common/data_structures/sparse_vector.tcc new file mode 100644 index 0000000..cfc5d75 --- /dev/null +++ b/privacy/zsl/zsl/common/data_structures/sparse_vector.tcc @@ -0,0 +1,316 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a sparse vector. + + See sparse_vector.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SPARSE_VECTOR_TCC_ +#define SPARSE_VECTOR_TCC_ + +#include "algebra/scalar_multiplication/multiexp.hpp" + +#include + +namespace libsnark { + +template +sparse_vector::sparse_vector(std::vector &&v) : + values(std::move(v)), domain_size_(values.size()) +{ + indices.resize(domain_size_); + std::iota(indices.begin(), indices.end(), 0); +} + +template +T sparse_vector::operator[](const size_t idx) const +{ + auto it = std::lower_bound(indices.begin(), indices.end(), idx); + return (it != indices.end() && *it == idx) ? values[it - indices.begin()] : T(); +} + +template +bool sparse_vector::operator==(const sparse_vector &other) const +{ + if (this->domain_size_ != other.domain_size_) + { + return false; + } + + size_t this_pos = 0, other_pos = 0; + while (this_pos < this->indices.size() && other_pos < other.indices.size()) + { + if (this->indices[this_pos] == other.indices[other_pos]) + { + if (this->values[this_pos] != other.values[other_pos]) + { + return false; + } + ++this_pos; + ++other_pos; + } + else if (this->indices[this_pos] < other.indices[other_pos]) + { + if (!this->values[this_pos].is_zero()) + { + return false; + } + ++this_pos; + } + else + { + if (!other.values[other_pos].is_zero()) + { + return false; + } + ++other_pos; + } + } + + /* at least one of the vectors has been exhausted, so other must be empty */ + while (this_pos < this->indices.size()) + { + if (!this->values[this_pos].is_zero()) + { + return false; + } + ++this_pos; + } + + while (other_pos < other.indices.size()) + { + if (!other.values[other_pos].is_zero()) + { + return false; + } + ++other_pos; + } + + return true; +} + +template +bool sparse_vector::operator==(const std::vector &other) const +{ + if (this->domain_size_ < other.size()) + { + return false; + } + + size_t j = 0; + for (size_t i = 0; i < other.size(); ++i) + { + if (this->indices[j] == i) + { + if (this->values[j] != other[j]) + { + return false; + } + ++j; + } + else + { + if (!other[j].is_zero()) + { + return false; + } + } + } + + return true; +} + +template +bool sparse_vector::is_valid() const +{ + if (values.size() == indices.size() && values.size() <= domain_size_) + { + return false; + } + + for (size_t i = 0; i + 1 < indices.size(); ++i) + { + if (indices[i] >= indices[i+1]) + { + return false; + } + } + + if (!indices.empty() && indices[indices.size()-1] >= domain_size_) + { + return false; + } + + return true; +} + +template +bool sparse_vector::empty() const +{ + return indices.empty(); +} + +template +size_t sparse_vector::domain_size() const +{ + return domain_size_; +} + +template +size_t sparse_vector::size() const +{ + return indices.size(); +} + +template +size_t sparse_vector::size_in_bits() const +{ + return indices.size() * (sizeof(size_t) * 8 + T::size_in_bits()); +} + +template +template +std::pair > sparse_vector::accumulate(const typename std::vector::const_iterator &it_begin, + const typename std::vector::const_iterator &it_end, + const size_t offset) const +{ + // TODO: does not really belong here. + const size_t chunks = 1; + const bool use_multiexp = true; + + T accumulated_value = T::zero(); + sparse_vector resulting_vector; + resulting_vector.domain_size_ = domain_size_; + + const size_t range_len = it_end - it_begin; + bool in_block = false; + size_t first_pos = -1, last_pos = -1; // g++ -flto emits unitialized warning, even though in_block guards for such cases. + + for (size_t i = 0; i < indices.size(); ++i) + { + const bool matching_pos = (offset <= indices[i] && indices[i] < offset + range_len); + // printf("i = %zu, pos[i] = %zu, offset = %zu, w_size = %zu\n", i, indices[i], offset, w_size); + bool copy_over; + + if (in_block) + { + if (matching_pos && last_pos == i-1) + { + // block can be extended, do it + last_pos = i; + copy_over = false; + } + else + { + // block has ended here + in_block = false; + copy_over = true; + +#ifdef DEBUG + print_indent(); printf("doing multiexp for w_%zu ... w_%zu\n", indices[first_pos], indices[last_pos]); +#endif + accumulated_value = accumulated_value + multi_exp(values.begin() + first_pos, + values.begin() + last_pos + 1, + it_begin + (indices[first_pos] - offset), + it_begin + (indices[last_pos] - offset) + 1, + chunks, use_multiexp); + } + } + else + { + if (matching_pos) + { + // block can be started + first_pos = i; + last_pos = i; + in_block = true; + copy_over = false; + } + else + { + copy_over = true; + } + } + + if (copy_over) + { + resulting_vector.indices.emplace_back(indices[i]); + resulting_vector.values.emplace_back(values[i]); + } + } + + if (in_block) + { +#ifdef DEBUG + print_indent(); printf("doing multiexp for w_%zu ... w_%zu\n", indices[first_pos], indices[last_pos]); +#endif + accumulated_value = accumulated_value + multi_exp(values.begin() + first_pos, + values.begin() + last_pos + 1, + it_begin + (indices[first_pos] - offset), + it_begin + (indices[last_pos] - offset) + 1, + chunks, use_multiexp); + } + + return std::make_pair(accumulated_value, resulting_vector); +} + +template +std::ostream& operator<<(std::ostream& out, const sparse_vector &v) +{ + out << v.domain_size_ << "\n"; + out << v.indices.size() << "\n"; + for (const size_t& i : v.indices) + { + out << i << "\n"; + } + + out << v.values.size() << "\n"; + for (const T& t : v.values) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +template +std::istream& operator>>(std::istream& in, sparse_vector &v) +{ + in >> v.domain_size_; + consume_newline(in); + + size_t s; + in >> s; + consume_newline(in); + v.indices.resize(s); + for (size_t i = 0; i < s; ++i) + { + in >> v.indices[i]; + consume_newline(in); + } + + v.values.clear(); + in >> s; + consume_newline(in); + v.values.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + T t; + in >> t; + consume_OUTPUT_NEWLINE(in); + v.values.emplace_back(t); + } + + return in; +} + +} // libsnark + +#endif // SPARSE_VECTOR_TCC_ diff --git a/privacy/zsl/zsl/common/default_types/bacs_ppzksnark_pp.hpp b/privacy/zsl/zsl/common/default_types/bacs_ppzksnark_pp.hpp new file mode 100644 index 0000000..c393b28 --- /dev/null +++ b/privacy/zsl/zsl/common/default_types/bacs_ppzksnark_pp.hpp @@ -0,0 +1,23 @@ + +/** @file + ***************************************************************************** + + This file defines default_bacs_ppzksnark_pp based on the elliptic curve + choice selected in ec_pp.hpp. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BACS_PPZKSNARK_PP_HPP_ +#define BACS_PPZKSNARK_PP_HPP_ + +#include "common/default_types/ec_pp.hpp" + +namespace libsnark { +typedef default_ec_pp default_bacs_ppzksnark_pp; +} // libsnark + +#endif // BACS_PPZKSNARK_PP_HPP_ diff --git a/privacy/zsl/zsl/common/default_types/ec_pp.hpp b/privacy/zsl/zsl/common/default_types/ec_pp.hpp new file mode 100644 index 0000000..b08c2da --- /dev/null +++ b/privacy/zsl/zsl/common/default_types/ec_pp.hpp @@ -0,0 +1,53 @@ +/** @file + ***************************************************************************** + + This file defines default_ec_pp based on the CURVE=... make flag, which selects + which elliptic curve is used to implement group arithmetic and pairings. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EC_PP_HPP_ +#define EC_PP_HPP_ + +/************************ Pick the elliptic curve ****************************/ + +#ifdef CURVE_ALT_BN128 +#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" +namespace libsnark { +typedef alt_bn128_pp default_ec_pp; +} // libsnark +#endif + +#ifdef CURVE_BN128 +#include "algebra/curves/bn128/bn128_pp.hpp" +namespace libsnark { +typedef bn128_pp default_ec_pp; +} // libsnark +#endif + +#ifdef CURVE_EDWARDS +#include "algebra/curves/edwards/edwards_pp.hpp" +namespace libsnark { +typedef edwards_pp default_ec_pp; +} // libsnark +#endif + +#ifdef CURVE_MNT4 +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" +namespace libsnark { +typedef mnt4_pp default_ec_pp; +} // libsnark +#endif + +#ifdef CURVE_MNT6 +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +namespace libsnark { +typedef mnt6_pp default_ec_pp; +} // libsnark +#endif + +#endif // EC_PP_HPP_ diff --git a/privacy/zsl/zsl/common/default_types/r1cs_gg_ppzksnark_pp.hpp b/privacy/zsl/zsl/common/default_types/r1cs_gg_ppzksnark_pp.hpp new file mode 100644 index 0000000..72cb704 --- /dev/null +++ b/privacy/zsl/zsl/common/default_types/r1cs_gg_ppzksnark_pp.hpp @@ -0,0 +1,22 @@ +/** @file + ***************************************************************************** + + This file defines default_r1cs_gg_ppzksnark_pp based on the elliptic curve + choice selected in ec_pp.hpp. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_GG_PPZKSNARK_PP_HPP_ +#define R1CS_GG_PPZKSNARK_PP_HPP_ + +#include "common/default_types/ec_pp.hpp" + +namespace libsnark { +typedef default_ec_pp default_r1cs_gg_ppzksnark_pp; +} // libsnark + +#endif // R1CS_GG_PPZKSNARK_PP_HPP_ diff --git a/privacy/zsl/zsl/common/default_types/r1cs_ppzkadsnark_pp.cpp b/privacy/zsl/zsl/common/default_types/r1cs_ppzkadsnark_pp.cpp new file mode 100644 index 0000000..aab2efe --- /dev/null +++ b/privacy/zsl/zsl/common/default_types/r1cs_ppzkadsnark_pp.cpp @@ -0,0 +1,21 @@ +/** @file + ***************************************************************************** + + This file provides the initialization methods for the default ADSNARK params. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "common/default_types/r1cs_ppzkadsnark_pp.hpp" + +namespace libsnark { + +void default_r1cs_ppzkadsnark_pp::init_public_params() +{ + snark_pp::init_public_params(); +} + +} // libsnark diff --git a/privacy/zsl/zsl/common/default_types/r1cs_ppzkadsnark_pp.d b/privacy/zsl/zsl/common/default_types/r1cs_ppzkadsnark_pp.d new file mode 100644 index 0000000..cdf8451 --- /dev/null +++ b/privacy/zsl/zsl/common/default_types/r1cs_ppzkadsnark_pp.d @@ -0,0 +1,28 @@ +src/common/default_types/r1cs_ppzkadsnark_pp.o: \ + src/common/default_types/r1cs_ppzkadsnark_pp.cpp \ + src/common/default_types/r1cs_ppzkadsnark_pp.hpp \ + src/common/default_types/r1cs_ppzksnark_pp.hpp \ + src/common/default_types/ec_pp.hpp src/algebra/curves/bn128/bn128_pp.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/bn128/bn128_init.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc depinst/include/bn.h \ + depinst/include/zm2.h depinst/include/zm.h \ + src/algebra/curves/bn128/bn128_g1.hpp src/algebra/curves/curve_utils.hpp \ + src/algebra/curves/curve_utils.tcc src/algebra/curves/bn128/bn128_g2.hpp \ + src/algebra/curves/bn128/bn128_gt.hpp \ + src/algebra/curves/bn128/bn128_pairing.hpp \ + src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/prf/aes_ctr_prf.hpp \ + src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_prf.hpp \ + src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_params.hpp \ + src/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp \ + src/relations/variable.hpp src/relations/variable.tcc \ + src/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc \ + src/common/profiling.hpp \ + src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/signature/ed25519_signature.hpp \ + src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_signature.hpp diff --git a/privacy/zsl/zsl/common/default_types/r1cs_ppzkadsnark_pp.hpp b/privacy/zsl/zsl/common/default_types/r1cs_ppzkadsnark_pp.hpp new file mode 100644 index 0000000..b35d3d7 --- /dev/null +++ b/privacy/zsl/zsl/common/default_types/r1cs_ppzkadsnark_pp.hpp @@ -0,0 +1,35 @@ +/** @file + ***************************************************************************** + + This file defines default_r1cs_ppzkadsnark_pp based on the elliptic curve + choice selected in ec_pp.hpp. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_PPZKADSNARK_PP_HPP_ +#define R1CS_PPZKADSNARK_PP_HPP_ + +#include "common/default_types/r1cs_ppzksnark_pp.hpp" +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/prf/aes_ctr_prf.hpp" +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/signature/ed25519_signature.hpp" + +namespace libsnark { + + class default_r1cs_ppzkadsnark_pp { + public: + typedef default_r1cs_ppzksnark_pp snark_pp; + typedef ed25519_skT skT; + typedef ed25519_vkT vkT; + typedef ed25519_sigT sigT; + typedef aesPrfKeyT prfKeyT; + + static void init_public_params(); + }; + +}; // libsnark + +#endif // R1CS_PPZKADSNARK_PP_HPP_ diff --git a/privacy/zsl/zsl/common/default_types/r1cs_ppzkpcd_pp.cpp b/privacy/zsl/zsl/common/default_types/r1cs_ppzkpcd_pp.cpp new file mode 100644 index 0000000..9281f5a --- /dev/null +++ b/privacy/zsl/zsl/common/default_types/r1cs_ppzkpcd_pp.cpp @@ -0,0 +1,22 @@ +/** @file + ***************************************************************************** + + This file provides the initialization methods for the default PCD cycle. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "common/default_types/r1cs_ppzkpcd_pp.hpp" + +namespace libsnark { + +void default_r1cs_ppzkpcd_pp::init_public_params() +{ + curve_A_pp::init_public_params(); + curve_B_pp::init_public_params(); +} + +} // libsnark diff --git a/privacy/zsl/zsl/common/default_types/r1cs_ppzkpcd_pp.d b/privacy/zsl/zsl/common/default_types/r1cs_ppzkpcd_pp.d new file mode 100644 index 0000000..0f2d19d --- /dev/null +++ b/privacy/zsl/zsl/common/default_types/r1cs_ppzkpcd_pp.d @@ -0,0 +1,27 @@ +src/common/default_types/r1cs_ppzkpcd_pp.o: \ + src/common/default_types/r1cs_ppzkpcd_pp.cpp \ + src/common/default_types/r1cs_ppzkpcd_pp.hpp \ + src/algebra/curves/mnt/mnt4/mnt4_pp.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/mnt/mnt4/mnt4_init.hpp \ + src/algebra/curves/mnt/mnt46_common.hpp src/algebra/fields/bigint.hpp \ + src/common/serialization.hpp src/common/serialization.tcc \ + src/common/utils.hpp src/common/utils.tcc src/algebra/fields/bigint.tcc \ + src/algebra/fields/fp.hpp src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc src/algebra/fields/fp2.hpp \ + src/algebra/fields/fp2.tcc src/algebra/fields/fp4.hpp \ + src/algebra/fields/fp4.tcc src/algebra/scalar_multiplication/wnaf.hpp \ + src/algebra/scalar_multiplication/wnaf.tcc \ + src/algebra/curves/mnt/mnt4/mnt4_g1.hpp \ + src/algebra/curves/curve_utils.hpp src/algebra/curves/curve_utils.tcc \ + src/algebra/curves/mnt/mnt4/mnt4_g2.hpp \ + src/algebra/curves/mnt/mnt4/mnt4_pairing.hpp \ + src/algebra/curves/mnt/mnt6/mnt6_pp.hpp \ + src/algebra/curves/mnt/mnt6/mnt6_init.hpp src/algebra/fields/fp3.hpp \ + src/algebra/fields/fp3.tcc src/algebra/fields/fp6_2over3.hpp \ + src/algebra/fields/fp6_2over3.tcc \ + src/algebra/curves/mnt/mnt6/mnt6_g1.hpp \ + src/algebra/curves/mnt/mnt6/mnt6_g2.hpp \ + src/algebra/curves/mnt/mnt6/mnt6_pairing.hpp diff --git a/privacy/zsl/zsl/common/default_types/r1cs_ppzkpcd_pp.hpp b/privacy/zsl/zsl/common/default_types/r1cs_ppzkpcd_pp.hpp new file mode 100644 index 0000000..f8d3fd0 --- /dev/null +++ b/privacy/zsl/zsl/common/default_types/r1cs_ppzkpcd_pp.hpp @@ -0,0 +1,35 @@ +/** @file + ***************************************************************************** + + This file defines the default PCD cycle. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_PPZKPCD_PP_HPP_ +#define R1CS_PPZKPCD_PP_HPP_ + +/*********************** Define default PCD cycle ***************************/ + +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" + +namespace libsnark { + +class default_r1cs_ppzkpcd_pp { +public: + typedef mnt4_pp curve_A_pp; + typedef mnt6_pp curve_B_pp; + + typedef Fr scalar_field_A; + typedef Fr scalar_field_B; + + static void init_public_params(); +}; + +} // libsnark + +#endif // R1CS_PPZKPCD_PP_HPP_ diff --git a/privacy/zsl/zsl/common/default_types/r1cs_ppzksnark_pp.hpp b/privacy/zsl/zsl/common/default_types/r1cs_ppzksnark_pp.hpp new file mode 100644 index 0000000..c819b4a --- /dev/null +++ b/privacy/zsl/zsl/common/default_types/r1cs_ppzksnark_pp.hpp @@ -0,0 +1,22 @@ +/** @file + ***************************************************************************** + + This file defines default_r1cs_ppzksnark_pp based on the elliptic curve + choice selected in ec_pp.hpp. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_PPZKSNARK_PP_HPP_ +#define R1CS_PPZKSNARK_PP_HPP_ + +#include "common/default_types/ec_pp.hpp" + +namespace libsnark { +typedef default_ec_pp default_r1cs_ppzksnark_pp; +} // libsnark + +#endif // R1CS_PPZKSNARK_PP_HPP_ diff --git a/privacy/zsl/zsl/common/default_types/ram_ppzksnark_pp.hpp b/privacy/zsl/zsl/common/default_types/ram_ppzksnark_pp.hpp new file mode 100644 index 0000000..2e7c15b --- /dev/null +++ b/privacy/zsl/zsl/common/default_types/ram_ppzksnark_pp.hpp @@ -0,0 +1,24 @@ +/** @file + ***************************************************************************** + + This file defines the default architecture and curve choices for RAM + ppzk-SNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_PPZKSNARK_PP_HPP_ +#define RAM_PPZKSNARK_PP_HPP_ + +#include "common/default_types/tinyram_ppzksnark_pp.hpp" + +namespace libsnark { + +typedef default_tinyram_ppzksnark_pp default_ram_ppzksnark_pp; + +} // libsnark + +#endif // RAM_PPZKSNARK_PP_HPP_ diff --git a/privacy/zsl/zsl/common/default_types/ram_zksnark_pp.hpp b/privacy/zsl/zsl/common/default_types/ram_zksnark_pp.hpp new file mode 100644 index 0000000..806b978 --- /dev/null +++ b/privacy/zsl/zsl/common/default_types/ram_zksnark_pp.hpp @@ -0,0 +1,24 @@ +/** @file + ***************************************************************************** + + This file defines the default architecture and curve choices for RAM + zk-SNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_ZKSNARK_PP_HPP_ +#define RAM_ZKSNARK_PP_HPP_ + +#include "common/default_types/tinyram_zksnark_pp.hpp" + +namespace libsnark { + +typedef default_tinyram_zksnark_pp default_ram_zksnark_pp; + +} // libsnark + +#endif // RAM_ZKSNARK_PP_HPP_ diff --git a/privacy/zsl/zsl/common/default_types/tbcs_ppzksnark_pp.hpp b/privacy/zsl/zsl/common/default_types/tbcs_ppzksnark_pp.hpp new file mode 100644 index 0000000..f7ac0d1 --- /dev/null +++ b/privacy/zsl/zsl/common/default_types/tbcs_ppzksnark_pp.hpp @@ -0,0 +1,23 @@ + +/** @file + ***************************************************************************** + + This file defines default_tbcs_ppzksnark_pp based on the elliptic curve + choice selected in ec_pp.hpp. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TBCS_PPZKSNARK_PP_HPP_ +#define TBCS_PPZKSNARK_PP_HPP_ + +#include "common/default_types/ec_pp.hpp" + +namespace libsnark { +typedef default_ec_pp default_tbcs_ppzksnark_pp; +} // libsnark + +#endif // TBCS_PPZKSNARK_PP_HPP_ diff --git a/privacy/zsl/zsl/common/default_types/tinyram_ppzksnark_pp.cpp b/privacy/zsl/zsl/common/default_types/tinyram_ppzksnark_pp.cpp new file mode 100644 index 0000000..5daba1a --- /dev/null +++ b/privacy/zsl/zsl/common/default_types/tinyram_ppzksnark_pp.cpp @@ -0,0 +1,21 @@ +/** @file + ***************************************************************************** + + This file provides the initialization methods for the default TinyRAM ppzk-SNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "common/default_types/tinyram_ppzksnark_pp.hpp" + +namespace libsnark { + +void default_tinyram_ppzksnark_pp::init_public_params() +{ + snark_pp::init_public_params(); +} + +} // libsnark diff --git a/privacy/zsl/zsl/common/default_types/tinyram_ppzksnark_pp.d b/privacy/zsl/zsl/common/default_types/tinyram_ppzksnark_pp.d new file mode 100644 index 0000000..6c53837 --- /dev/null +++ b/privacy/zsl/zsl/common/default_types/tinyram_ppzksnark_pp.d @@ -0,0 +1,49 @@ +src/common/default_types/tinyram_ppzksnark_pp.o: \ + src/common/default_types/tinyram_ppzksnark_pp.cpp \ + src/common/default_types/tinyram_ppzksnark_pp.hpp \ + src/common/default_types/r1cs_ppzksnark_pp.hpp \ + src/common/default_types/ec_pp.hpp src/algebra/curves/bn128/bn128_pp.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/bn128/bn128_init.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc depinst/include/bn.h \ + depinst/include/zm2.h depinst/include/zm.h \ + src/algebra/curves/bn128/bn128_g1.hpp src/algebra/curves/curve_utils.hpp \ + src/algebra/curves/curve_utils.tcc src/algebra/curves/bn128/bn128_g2.hpp \ + src/algebra/curves/bn128/bn128_gt.hpp \ + src/algebra/curves/bn128/bn128_pairing.hpp \ + src/relations/ram_computations/rams/tinyram/tinyram_params.hpp \ + src/relations/ram_computations/rams/ram_params.hpp \ + src/relations/ram_computations/memory/memory_store_trace.hpp \ + src/relations/ram_computations/memory/memory_interface.hpp \ + src/relations/ram_computations/rams/tinyram/tinyram_aux.hpp \ + src/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp \ + src/relations/variable.hpp src/relations/variable.tcc \ + src/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc \ + src/common/profiling.hpp \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/tinyram_cpu_checker.hpp \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.hpp \ + src/gadgetlib1/protoboard.hpp src/gadgetlib1/pb_variable.hpp \ + src/gadgetlib1/pb_variable.tcc src/gadgetlib1/protoboard.tcc \ + src/gadgetlib1/gadgets/basic_gadgets.hpp src/gadgetlib1/gadget.hpp \ + src/gadgetlib1/gadget.tcc src/gadgetlib1/gadgets/basic_gadgets.tcc \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.tcc \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/word_variable_gadget.hpp \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_gadget.hpp \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_arithmetic.hpp \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_arithmetic.tcc \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_control_flow.hpp \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_control_flow.tcc \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_gadget.tcc \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/argument_decoder_gadget.hpp \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/argument_decoder_gadget.tcc \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/consistency_enforcer_gadget.hpp \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/consistency_enforcer_gadget.tcc \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/memory_masking_gadget.hpp \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/memory_masking_gadget.tcc \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/tinyram_cpu_checker.tcc diff --git a/privacy/zsl/zsl/common/default_types/tinyram_ppzksnark_pp.hpp b/privacy/zsl/zsl/common/default_types/tinyram_ppzksnark_pp.hpp new file mode 100644 index 0000000..7953d4f --- /dev/null +++ b/privacy/zsl/zsl/common/default_types/tinyram_ppzksnark_pp.hpp @@ -0,0 +1,32 @@ +/** @file + ***************************************************************************** + + This file defines the default architecture and curve choices for RAM + ppzk-SNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TINYRAM_PPZKSNARK_PP_HPP_ +#define TINYRAM_PPZKSNARK_PP_HPP_ + +#include "common/default_types/r1cs_ppzksnark_pp.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_params.hpp" + +namespace libsnark { + +class default_tinyram_ppzksnark_pp { +public: + typedef default_r1cs_ppzksnark_pp snark_pp; + typedef Fr FieldT; + typedef ram_tinyram machine_pp; + + static void init_public_params(); +}; + +} // libsnark + +#endif // TINYRAM_PPZKSNARK_PP_HPP_ diff --git a/privacy/zsl/zsl/common/default_types/tinyram_zksnark_pp.cpp b/privacy/zsl/zsl/common/default_types/tinyram_zksnark_pp.cpp new file mode 100644 index 0000000..2373833 --- /dev/null +++ b/privacy/zsl/zsl/common/default_types/tinyram_zksnark_pp.cpp @@ -0,0 +1,21 @@ +/** @file + ***************************************************************************** + + This file provides the initialization methods for the default TinyRAM zk-SNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "common/default_types/tinyram_zksnark_pp.hpp" + +namespace libsnark { + +void default_tinyram_zksnark_pp::init_public_params() +{ + PCD_pp::init_public_params(); +} + +} // libsnark diff --git a/privacy/zsl/zsl/common/default_types/tinyram_zksnark_pp.d b/privacy/zsl/zsl/common/default_types/tinyram_zksnark_pp.d new file mode 100644 index 0000000..c218bf3 --- /dev/null +++ b/privacy/zsl/zsl/common/default_types/tinyram_zksnark_pp.d @@ -0,0 +1,58 @@ +src/common/default_types/tinyram_zksnark_pp.o: \ + src/common/default_types/tinyram_zksnark_pp.cpp \ + src/common/default_types/tinyram_zksnark_pp.hpp \ + src/common/default_types/r1cs_ppzkpcd_pp.hpp \ + src/algebra/curves/mnt/mnt4/mnt4_pp.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/mnt/mnt4/mnt4_init.hpp \ + src/algebra/curves/mnt/mnt46_common.hpp src/algebra/fields/bigint.hpp \ + src/common/serialization.hpp src/common/serialization.tcc \ + src/common/utils.hpp src/common/utils.tcc src/algebra/fields/bigint.tcc \ + src/algebra/fields/fp.hpp src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc src/algebra/fields/fp2.hpp \ + src/algebra/fields/fp2.tcc src/algebra/fields/fp4.hpp \ + src/algebra/fields/fp4.tcc src/algebra/scalar_multiplication/wnaf.hpp \ + src/algebra/scalar_multiplication/wnaf.tcc \ + src/algebra/curves/mnt/mnt4/mnt4_g1.hpp \ + src/algebra/curves/curve_utils.hpp src/algebra/curves/curve_utils.tcc \ + src/algebra/curves/mnt/mnt4/mnt4_g2.hpp \ + src/algebra/curves/mnt/mnt4/mnt4_pairing.hpp \ + src/algebra/curves/mnt/mnt6/mnt6_pp.hpp \ + src/algebra/curves/mnt/mnt6/mnt6_init.hpp src/algebra/fields/fp3.hpp \ + src/algebra/fields/fp3.tcc src/algebra/fields/fp6_2over3.hpp \ + src/algebra/fields/fp6_2over3.tcc \ + src/algebra/curves/mnt/mnt6/mnt6_g1.hpp \ + src/algebra/curves/mnt/mnt6/mnt6_g2.hpp \ + src/algebra/curves/mnt/mnt6/mnt6_pairing.hpp \ + src/relations/ram_computations/rams/tinyram/tinyram_params.hpp \ + src/relations/ram_computations/rams/ram_params.hpp \ + src/relations/ram_computations/memory/memory_store_trace.hpp \ + src/relations/ram_computations/memory/memory_interface.hpp \ + src/relations/ram_computations/rams/tinyram/tinyram_aux.hpp \ + src/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp \ + src/relations/variable.hpp src/relations/variable.tcc \ + src/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc \ + src/common/profiling.hpp \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/tinyram_cpu_checker.hpp \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.hpp \ + src/gadgetlib1/protoboard.hpp src/gadgetlib1/pb_variable.hpp \ + src/gadgetlib1/pb_variable.tcc src/gadgetlib1/protoboard.tcc \ + src/gadgetlib1/gadgets/basic_gadgets.hpp src/gadgetlib1/gadget.hpp \ + src/gadgetlib1/gadget.tcc src/gadgetlib1/gadgets/basic_gadgets.tcc \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.tcc \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/word_variable_gadget.hpp \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_gadget.hpp \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_arithmetic.hpp \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_arithmetic.tcc \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_control_flow.hpp \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_control_flow.tcc \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_gadget.tcc \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/argument_decoder_gadget.hpp \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/argument_decoder_gadget.tcc \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/consistency_enforcer_gadget.hpp \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/consistency_enforcer_gadget.tcc \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/memory_masking_gadget.hpp \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/memory_masking_gadget.tcc \ + src/gadgetlib1/gadgets/cpu_checkers/tinyram/tinyram_cpu_checker.tcc diff --git a/privacy/zsl/zsl/common/default_types/tinyram_zksnark_pp.hpp b/privacy/zsl/zsl/common/default_types/tinyram_zksnark_pp.hpp new file mode 100644 index 0000000..e382472 --- /dev/null +++ b/privacy/zsl/zsl/common/default_types/tinyram_zksnark_pp.hpp @@ -0,0 +1,31 @@ +/** @file + ***************************************************************************** + + This file defines the default choices of TinyRAM zk-SNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TINYRAM_PPZKSNARK_PP_HPP_ +#define TINYRAM_PPZKSNARK_PP_HPP_ + +#include "common/default_types/r1cs_ppzkpcd_pp.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_params.hpp" + +namespace libsnark { + +class default_tinyram_zksnark_pp { +public: + typedef default_r1cs_ppzkpcd_pp PCD_pp; + typedef typename PCD_pp::scalar_field_A FieldT; + typedef ram_tinyram machine_pp; + + static void init_public_params(); +}; + +} // libsnark + +#endif // TINYRAM_PPZKSNARK_PP_HPP_ diff --git a/privacy/zsl/zsl/common/default_types/uscs_ppzksnark_pp.hpp b/privacy/zsl/zsl/common/default_types/uscs_ppzksnark_pp.hpp new file mode 100644 index 0000000..59d1917 --- /dev/null +++ b/privacy/zsl/zsl/common/default_types/uscs_ppzksnark_pp.hpp @@ -0,0 +1,23 @@ + +/** @file + ***************************************************************************** + + This file defines default_uscs_ppzksnark_pp based on the elliptic curve + choice selected in ec_pp.hpp. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef USCS_PPZKSNARK_PP_HPP_ +#define USCS_PPZKSNARK_PP_HPP_ + +#include "common/default_types/ec_pp.hpp" + +namespace libsnark { +typedef default_ec_pp default_uscs_ppzksnark_pp; +} // libsnark + +#endif // USCS_PPZKSNARK_PP_HPP_ diff --git a/privacy/zsl/zsl/common/profiling.cpp b/privacy/zsl/zsl/common/profiling.cpp new file mode 100644 index 0000000..3aca302 --- /dev/null +++ b/privacy/zsl/zsl/common/profiling.cpp @@ -0,0 +1,379 @@ +/** @file + ***************************************************************************** + + Implementation of functions for profiling code blocks. + + See profiling.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "common/profiling.hpp" +#include +#include +#include +#include +#include +#include +#include +#include "common/default_types/ec_pp.hpp" +#include "common/utils.hpp" + +#ifndef NO_PROCPS +#include +#endif + +namespace libsnark { + +long long get_nsec_time() +{ + auto timepoint = std::chrono::high_resolution_clock::now(); + return std::chrono::duration_cast(timepoint.time_since_epoch()).count(); +} + +/* Return total CPU time consumsed by all threads of the process, in nanoseconds. */ +long long get_nsec_cpu_time() +{ + ::timespec ts; + if ( ::clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) ) + throw ::std::runtime_error("clock_gettime(CLOCK_PROCESS_CPUTIME_ID) failed"); + // If we expected this to work, don't silently ignore failures, because that would hide the problem and incur an unnecessarily system-call overhead. So if we ever observe this exception, we should probably add a suitable #ifdef . + //TODO: clock_gettime(CLOCK_PROCESS_CPUTIME_ID) is not supported by native Windows. What about Cygwin? Should we #ifdef on CLOCK_PROCESS_CPUTIME_ID or on __linux__? + return ts.tv_sec * 1000000000ll + ts.tv_nsec; +} + +long long start_time, last_time; +long long start_cpu_time, last_cpu_time; + +void start_profiling() +{ + printf("Reset time counters for profiling\n"); + + last_time = start_time = get_nsec_time(); + last_cpu_time = start_cpu_time = get_nsec_cpu_time(); +} + +std::map invocation_counts; +std::map enter_times; +std::map last_times; +std::map cumulative_times; +//TODO: Instead of analogous maps for time and cpu_time, use a single struct-valued map +std::map enter_cpu_times; +std::map last_cpu_times; +std::map, long long> op_counts; +std::map, long long> cumulative_op_counts; // ((msg, data_point), value) + // TODO: Convert op_counts and cumulative_op_counts from pair to structs +size_t indentation = 0; + +std::vector block_names; + +std::list > op_data_points = { +#ifdef PROFILE_OP_COUNTS + std::make_pair("Fradd", &Fr::add_cnt), + std::make_pair("Frsub", &Fr::sub_cnt), + std::make_pair("Frmul", &Fr::mul_cnt), + std::make_pair("Frinv", &Fr::inv_cnt), + std::make_pair("Fqadd", &Fq::add_cnt), + std::make_pair("Fqsub", &Fq::sub_cnt), + std::make_pair("Fqmul", &Fq::mul_cnt), + std::make_pair("Fqinv", &Fq::inv_cnt), + std::make_pair("G1add", &G1::add_cnt), + std::make_pair("G1dbl", &G1::dbl_cnt), + std::make_pair("G2add", &G2::add_cnt), + std::make_pair("G2dbl", &G2::dbl_cnt) +#endif +}; + +bool inhibit_profiling_info = false; +bool inhibit_profiling_counters = false; + +void clear_profiling_counters() +{ + invocation_counts.clear(); + last_times.clear(); + last_cpu_times.clear(); + cumulative_times.clear(); +} + +void print_cumulative_time_entry(const std::string &key, const long long factor) +{ + const double total_ms = (cumulative_times.at(key) * 1e-6); + const size_t cnt = invocation_counts.at(key); + const double avg_ms = total_ms / cnt; + printf(" %-45s: %12.5fms = %lld * %0.5fms (%zu invocations, %0.5fms = %lld * %0.5fms per invocation)\n", key.c_str(), total_ms, factor, total_ms/factor, cnt, avg_ms, factor, avg_ms/factor); +} + +void print_cumulative_times(const long long factor) +{ + printf("Dumping times:\n"); + for (auto& kv : cumulative_times) + { + print_cumulative_time_entry(kv.first, factor); + } +} + +void print_cumulative_op_counts(const bool only_fq) +{ +#ifdef PROFILE_OP_COUNTS + printf("Dumping operation counts:\n"); + for (auto& msg : invocation_counts) + { + printf(" %-45s: ", msg.first.c_str()); + bool first = true; + for (auto& data_point : op_data_points) + { + if (only_fq && data_point.first.compare(0, 2, "Fq") != 0) + { + continue; + } + + if (!first) + { + printf(", "); + } + printf("%-5s = %7.0f (%3zu)", + data_point.first.c_str(), + 1. * cumulative_op_counts[std::make_pair(msg.first, data_point.first)] / msg.second, + msg.second); + first = false; + } + printf("\n"); + } +#else + UNUSED(only_fq); +#endif +} + +void print_op_profiling(const std::string &msg) +{ +#ifdef PROFILE_OP_COUNTS + printf("\n"); + print_indent(); + + printf("(opcounts) = ("); + bool first = true; + for (std::pair p : op_data_points) + { + if (!first) + { + printf(", "); + } + + printf("%s=%lld", p.first.c_str(), *(p.second)-op_counts[std::make_pair(msg, p.first)]); + first = false; + } + printf(")"); +#else + UNUSED(msg); +#endif +} + +static void print_times_from_last_and_start(long long now, long long last, + long long cpu_now, long long cpu_last) +{ + long long time_from_start = now - start_time; + long long time_from_last = now - last; + + long long cpu_time_from_start = cpu_now - start_cpu_time; + long long cpu_time_from_last = cpu_now - cpu_last; + + if (time_from_last != 0) { + double parallelism_from_last = 1.0 * cpu_time_from_last / time_from_last; + printf("[%0.4fs x%0.2f]", time_from_last * 1e-9, parallelism_from_last); + } else { + printf("[ ]"); + } + if (time_from_start != 0) { + double parallelism_from_start = 1.0 * cpu_time_from_start / time_from_start; + printf("\t(%0.4fs x%0.2f from start)", time_from_start * 1e-9, parallelism_from_start); + } +} + +void print_time(const char* msg) +{ + if (inhibit_profiling_info) + { + return; + } + + long long now = get_nsec_time(); + long long cpu_now = get_nsec_cpu_time(); + + printf("%-35s\t", msg); + print_times_from_last_and_start(now, last_time, cpu_now, last_cpu_time); +#ifdef PROFILE_OP_COUNTS + print_op_profiling(msg); +#endif + printf("\n"); + + fflush(stdout); + last_time = now; + last_cpu_time = cpu_now; +} + +void print_header(const char *msg) +{ + printf("\n================================================================================\n"); + printf("%s\n", msg); + printf("================================================================================\n\n"); +} + +void print_indent() +{ + for (size_t i = 0; i < indentation; ++i) + { + printf(" "); + } +} + +void op_profiling_enter(const std::string &msg) +{ + for (std::pair p : op_data_points) + { + op_counts[std::make_pair(msg, p.first)] = *(p.second); + } +} + +void enter_block(const std::string &msg, const bool indent) +{ + if (inhibit_profiling_counters) + { + return; + } + + block_names.emplace_back(msg); + long long t = get_nsec_time(); + enter_times[msg] = t; + long long cpu_t = get_nsec_cpu_time(); + enter_cpu_times[msg] = cpu_t; + + if (inhibit_profiling_info) + { + return; + } + +#ifdef MULTICORE +#pragma omp critical +#endif + { + op_profiling_enter(msg); + + print_indent(); + printf("(enter) %-35s\t", msg.c_str()); + print_times_from_last_and_start(t, t, cpu_t, cpu_t); + printf("\n"); + fflush(stdout); + + if (indent) + { + ++indentation; + } + } +} + +void leave_block(const std::string &msg, const bool indent) +{ + if (inhibit_profiling_counters) + { + return; + } + +#ifndef MULTICORE + assert(*(--block_names.end()) == msg); +#endif + block_names.pop_back(); + + ++invocation_counts[msg]; + + long long t = get_nsec_time(); + last_times[msg] = (t - enter_times[msg]); + cumulative_times[msg] += (t - enter_times[msg]); + + long long cpu_t = get_nsec_cpu_time(); + last_cpu_times[msg] = (cpu_t - enter_cpu_times[msg]); + +#ifdef PROFILE_OP_COUNTS + for (std::pair p : op_data_points) + { + cumulative_op_counts[std::make_pair(msg, p.first)] += *(p.second)-op_counts[std::make_pair(msg, p.first)]; + } +#endif + + if (inhibit_profiling_info) + { + return; + } + +#ifdef MULTICORE +#pragma omp critical +#endif + { + if (indent) + { + --indentation; + } + + print_indent(); + printf("(leave) %-35s\t", msg.c_str()); + print_times_from_last_and_start(t, enter_times[msg], cpu_t, enter_cpu_times[msg]); + print_op_profiling(msg); + printf("\n"); + fflush(stdout); + } +} + +void print_mem(const std::string &s) +{ +#ifndef NO_PROCPS + struct proc_t usage; + look_up_our_self(&usage); + if (s.empty()) + { + printf("* Peak vsize (physical memory+swap) in mebibytes: %lu\n", usage.vsize >> 20); + } + else + { + printf("* Peak vsize (physical memory+swap) in mebibytes (%s): %lu\n", s.c_str(), usage.vsize >> 20); + } +#else + printf("* Memory profiling not supported in NO_PROCPS mode\n"); +#endif +} + +void print_compilation_info() +{ +#ifdef __GNUC__ + printf("g++ version: %s\n", __VERSION__); + printf("Compiled on %s %s\n", __DATE__, __TIME__); +#endif +#ifdef STATIC + printf("STATIC: yes\n"); +#else + printf("STATIC: no\n"); +#endif +#ifdef MULTICORE + printf("MULTICORE: yes\n"); +#else + printf("MULTICORE: no\n"); +#endif +#ifdef DEBUG + printf("DEBUG: yes\n"); +#else + printf("DEBUG: no\n"); +#endif +#ifdef PROFILE_OP_COUNTS + printf("PROFILE_OP_COUNTS: yes\n"); +#else + printf("PROFILE_OP_COUNTS: no\n"); +#endif +#ifdef _GLIBCXX_DEBUG + printf("_GLIBCXX_DEBUG: yes\n"); +#else + printf("_GLIBCXX_DEBUG: no\n"); +#endif +} + +} // libsnark diff --git a/privacy/zsl/zsl/common/profiling.d b/privacy/zsl/zsl/common/profiling.d new file mode 100644 index 0000000..9735173 --- /dev/null +++ b/privacy/zsl/zsl/common/profiling.d @@ -0,0 +1,16 @@ +src/common/profiling.o: src/common/profiling.cpp src/common/profiling.hpp \ + src/common/default_types/ec_pp.hpp src/algebra/curves/bn128/bn128_pp.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/bn128/bn128_init.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc depinst/include/bn.h \ + depinst/include/zm2.h depinst/include/zm.h \ + src/algebra/curves/bn128/bn128_g1.hpp src/algebra/curves/curve_utils.hpp \ + src/algebra/curves/curve_utils.tcc src/algebra/curves/bn128/bn128_g2.hpp \ + src/algebra/curves/bn128/bn128_gt.hpp \ + src/algebra/curves/bn128/bn128_pairing.hpp diff --git a/privacy/zsl/zsl/common/profiling.hpp b/privacy/zsl/zsl/common/profiling.hpp new file mode 100644 index 0000000..9619117 --- /dev/null +++ b/privacy/zsl/zsl/common/profiling.hpp @@ -0,0 +1,51 @@ +/** @file + ***************************************************************************** + + Declaration of functions for profiling code blocks. + + Reports time, operation counts, memory usage, and others. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PROFILING_HPP_ +#define PROFILING_HPP_ + +#include +#include +#include +#include + +namespace libsnark { + +void start_profiling(); +long long get_nsec_time(); +void print_time(const char* msg); +void print_header(const char* msg); + +void print_indent(); + +extern bool inhibit_profiling_info; +extern bool inhibit_profiling_counters; +extern std::map invocation_counts; +extern std::map last_times; +extern std::map cumulative_times; + +void clear_profiling_counters(); + +void print_cumulative_time_entry(const std::string &key, const long long factor=1); +void print_cumulative_times(const long long factor=1); +void print_cumulative_op_counts(const bool only_fq=false); + +void enter_block(const std::string &msg, const bool indent=true); +void leave_block(const std::string &msg, const bool indent=true); + +void print_mem(const std::string &s = ""); +void print_compilation_info(); + +} // libsnark + +#endif // PROFILING_HPP_ diff --git a/privacy/zsl/zsl/common/rng.hpp b/privacy/zsl/zsl/common/rng.hpp new file mode 100644 index 0000000..6d0896f --- /dev/null +++ b/privacy/zsl/zsl/common/rng.hpp @@ -0,0 +1,26 @@ +/** @file + ***************************************************************************** + + Declaration of functions for generating randomness. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RNG_HPP_ +#define RNG_HPP_ + +#include + +namespace libsnark { + +template +FieldT SHA512_rng(const uint64_t idx); + +} // libsnark + +#include "common/rng.tcc" + +#endif // RNG_HPP_ diff --git a/privacy/zsl/zsl/common/rng.tcc b/privacy/zsl/zsl/common/rng.tcc new file mode 100644 index 0000000..44020da --- /dev/null +++ b/privacy/zsl/zsl/common/rng.tcc @@ -0,0 +1,69 @@ +/** @file + ***************************************************************************** + + Implementation of functions for generating randomness. + + See rng.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RNG_TCC_ +#define RNG_TCC_ + +#include + +namespace libsnark { + +template +FieldT SHA512_rng(const uint64_t idx) +{ + assert(GMP_NUMB_BITS == 64); // current Python code cannot handle larger values, so testing here for some assumptions. + assert(is_little_endian()); + + assert(FieldT::size_in_bits() <= SHA512_DIGEST_LENGTH * 8); + + bigint rval; + uint64_t iter = 0; + do + { + mp_limb_t hash[((SHA512_DIGEST_LENGTH*8) + GMP_NUMB_BITS - 1)/GMP_NUMB_BITS]; + + SHA512_CTX sha512; + SHA512_Init(&sha512); + SHA512_Update(&sha512, &idx, sizeof(idx)); + SHA512_Update(&sha512, &iter, sizeof(iter)); + SHA512_Final((unsigned char*)hash, &sha512); + + for (mp_size_t i = 0; i < FieldT::num_limbs; ++i) + { + rval.data[i] = hash[i]; + } + + /* clear all bits higher than MSB of modulus */ + size_t bitno = GMP_NUMB_BITS * FieldT::num_limbs; + while (FieldT::mod.test_bit(bitno) == false) + { + const std::size_t part = bitno/GMP_NUMB_BITS; + const std::size_t bit = bitno - (GMP_NUMB_BITS*part); + + rval.data[part] &= ~(1ul<= modulus -- repeat (rejection sampling) */ + while (mpn_cmp(rval.data, FieldT::mod.data, FieldT::num_limbs) >= 0); + + return FieldT(rval); +} + +} // libsnark + +#endif // RNG_TCC_ diff --git a/privacy/zsl/zsl/common/routing_algorithms/as_waksman_routing_algorithm.cpp b/privacy/zsl/zsl/common/routing_algorithms/as_waksman_routing_algorithm.cpp new file mode 100644 index 0000000..3ff7985 --- /dev/null +++ b/privacy/zsl/zsl/common/routing_algorithms/as_waksman_routing_algorithm.cpp @@ -0,0 +1,549 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for functionality for routing on an arbitrary-size (AS) Waksman network. + + See as_waksman_routing_algorithm.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include + +#include "common/routing_algorithms/as_waksman_routing_algorithm.hpp" + +namespace libsnark { + +/** + * Return the height of the AS-Waksman network's top sub-network. + */ +size_t as_waksman_top_height(const size_t num_packets) +{ + return num_packets/2; +} + +/** + * Return the input wire of a left-hand side switch of an AS-Waksman network for + * a given number of packets. + * + * A switch is specified by a row index row_idx, relative to a "row_offset" that + * records the level of recursion. (The corresponding column index column_idx + * can be inferred from row_offset and num_packets, and it is easier to reason about + * implicitly.) + * + * If top = true, return the top wire, otherwise return bottom wire. + */ +size_t as_waksman_switch_output(const size_t num_packets, const size_t row_offset, const size_t row_idx, const bool use_top) +{ + size_t relpos = row_idx - row_offset; + assert(relpos % 2 == 0 && relpos + 1 < num_packets); + return row_offset + (relpos / 2) + (use_top ? 0 : as_waksman_top_height(num_packets)); +} + +/** + * Return the input wire of a right-hand side switch of an AS-Waksman network for + * a given number of packets. + * + * This function is analogous to as_waksman_switch_output above. + */ +size_t as_waksman_switch_input(const size_t num_packets, const size_t row_offset, const size_t row_idx, const bool use_top) +{ + /* Due to symmetry, this function equals as_waksman_switch_output. */ + return as_waksman_switch_output(num_packets, row_offset, row_idx, use_top); +} + +size_t as_waksman_num_columns(const size_t num_packets) +{ + return (num_packets > 1 ? 2*log2(num_packets)-1 : 0); +} + +/** + * Construct AS-Waksman subnetwork occupying switch columns + * [left,left+1, ..., right] + * that will route + * - from left-hand side inputs [lo,lo+1,...,hi] + * - to right-hand side destinations rhs_dests[0],rhs_dests[1],...,rhs_dests[hi-lo+1]. + * That is, rhs_dests are 0-indexed w.r.t. row_offset of lo. + * + * Note that rhs_dests is *not* a permutation of [lo, lo+1, ... hi]. + * + * This function fills out neighbors[left] and neighbors[right-1]. + */ +void construct_as_waksman_inner(const size_t left, + const size_t right, + const size_t lo, + const size_t hi, + const std::vector rhs_dests, + as_waksman_topology &neighbors) +{ + if (left > right) + { + return; + } + + const size_t subnetwork_size = (hi - lo + 1); + assert(rhs_dests.size() == subnetwork_size); + const size_t subnetwork_width = as_waksman_num_columns(subnetwork_size); + assert(right - left + 1 >= subnetwork_width); + + if (right - left + 1 > subnetwork_width) + { + /** + * If there is more space for the routing network than needed, + * just add straight edges. This also handles the size-1 base case. + */ + for (size_t packet_idx = lo; packet_idx <= hi; ++packet_idx) + { + neighbors[left][packet_idx].first = neighbors[left][packet_idx].second = packet_idx; + neighbors[right][packet_idx].first = neighbors[right][packet_idx].second = rhs_dests[packet_idx - lo]; + } + + std::vector new_rhs_dests(subnetwork_size, -1); + for (size_t packet_idx = lo; packet_idx <= hi; ++packet_idx) + { + new_rhs_dests[packet_idx-lo] = packet_idx; + } + + construct_as_waksman_inner(left+1, right-1, lo, hi, new_rhs_dests, neighbors); + } + else if (subnetwork_size == 2) + { + /* Non-trivial base case: routing a 2-element permutation. */ + neighbors[left][lo].first = neighbors[left][hi].second = rhs_dests[0]; + neighbors[left][lo].second = neighbors[left][hi].first = rhs_dests[1]; + } + else + { + /** + * Networks of size sz > 2 are handled by adding two columns of + * switches alongside the network and recursing. + */ + std::vector new_rhs_dests(subnetwork_size, -1); + + /** + * This adds floor(sz/2) switches alongside the network. + * + * As per the AS-Waksman construction, one of the switches in the + * even case can be eliminated (i.e., set to a constant). We handle + * this later. + */ + for (size_t row_idx = lo; row_idx < (subnetwork_size % 2 == 1 ? hi : hi + 1); row_idx += 2) + { + neighbors[left][row_idx].first = neighbors[left][row_idx+1].second = as_waksman_switch_output(subnetwork_size, lo, row_idx, true); + neighbors[left][row_idx].second = neighbors[left][row_idx+1].first = as_waksman_switch_output(subnetwork_size, lo, row_idx, false); + + new_rhs_dests[as_waksman_switch_input(subnetwork_size, lo, row_idx, true)-lo] = row_idx; + new_rhs_dests[as_waksman_switch_input(subnetwork_size, lo, row_idx, false)-lo] = row_idx + 1; + + neighbors[right][row_idx].first = neighbors[right][row_idx+1].second = rhs_dests[row_idx-lo]; + neighbors[right][row_idx].second = neighbors[right][row_idx+1].first = rhs_dests[row_idx+1-lo]; + } + + if (subnetwork_size % 2 == 1) + { + /** + * Odd special case: + * the last wire is not connected to any switch, + * and the the wire is mereley routed "straight". + */ + neighbors[left][hi].first = neighbors[left][hi].second = hi; + neighbors[right][hi].first = neighbors[right][hi].second = rhs_dests[hi-lo]; + new_rhs_dests[hi-lo] = hi; + } + else + { + /** + * Even special case: + * fix the bottom-most left-hand-side switch + * to a constant "straight" setting. + */ + neighbors[left][hi-1].second = neighbors[left][hi-1].first; + neighbors[left][hi].second = neighbors[left][hi].first; + } + + const size_t d = as_waksman_top_height(subnetwork_size); + const std::vector new_rhs_dests_top(new_rhs_dests.begin(), new_rhs_dests.begin()+d); + const std::vector new_rhs_dests_bottom(new_rhs_dests.begin()+d, new_rhs_dests.end()); + + construct_as_waksman_inner(left+1, right-1, lo, lo+d-1, new_rhs_dests_top, neighbors); + construct_as_waksman_inner(left+1, right-1, lo+d, hi, new_rhs_dests_bottom, neighbors); + } +} + +as_waksman_topology generate_as_waksman_topology(const size_t num_packets) +{ + assert(num_packets > 1); + const size_t width = as_waksman_num_columns(num_packets); + + as_waksman_topology neighbors(width, std::vector >(num_packets, std::make_pair(-1, -1))); + + std::vector rhs_dests(num_packets); + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + rhs_dests[packet_idx] = packet_idx; + } + + construct_as_waksman_inner(0, width-1, 0, num_packets-1, rhs_dests, neighbors); + + return neighbors; +} + +/** + * Given either a position occupied either by its top or bottom ports, + * return the row index of its canonical position. + * + * This function is agnostic to column_idx, given row_offset, so we omit + * column_idx. + */ +size_t as_waksman_get_canonical_row_idx(const size_t row_offset, const size_t row_idx) +{ + /* translate back relative to row_offset, clear LSB, and then translate forward */ + return (((row_idx - row_offset) & ~1) + row_offset); +} + +/** + * Return a switch value that makes switch row_idx = + * as_waksman_switch_position_from_wire_position(row_offset, packet_idx) to + * route the wire packet_idx via the top (if top = true), resp., + * bottom (if top = false) subnetwork. + * + * NOTE: pos is assumed to be + * - the input position for the LHS switches, and + * - the output position for the RHS switches. + */ +bool as_waksman_get_switch_setting_from_top_bottom_decision(const size_t row_offset, const size_t packet_idx, const bool use_top) +{ + const size_t row_idx = as_waksman_get_canonical_row_idx(row_offset, packet_idx); + return (packet_idx == row_idx) ^ use_top; +} + +/** + * Return true if the switch with input port at (column_idx, row_idx) + * when set to "straight" (if top = true), resp., "cross" (if top = + * false), routes the packet at (column_idx, row_idx) via the top + * subnetwork. + * + * NOTE: packet_idx is assumed to be + * - the input position for the RHS switches, and + * - the output position for the LHS switches. + */ +bool as_waksman_get_top_bottom_decision_from_switch_setting(const size_t row_offset, const size_t packet_idx, const bool switch_setting) +{ + const size_t row_idx = as_waksman_get_canonical_row_idx(row_offset, packet_idx); + return (row_idx == packet_idx) ^ switch_setting; +} + +/** + * Given an output wire of a RHS switch, compute and return the output + * position of the other wire also connected to this switch. + */ +size_t as_waksman_other_output_position(const size_t row_offset, const size_t packet_idx) +{ + const size_t row_idx = as_waksman_get_canonical_row_idx(row_offset, packet_idx); + return (1 - (packet_idx - row_idx)) + row_idx; +} + +/** + * Given an input wire of a LHS switch, compute and return the input + * position of the other wire also connected to this switch. + */ +size_t as_waksman_other_input_position(const size_t row_offset, const size_t packet_idx) +{ + /* Due to symmetry, this function equals as_waksman_other_output_position. */ + return as_waksman_other_output_position(row_offset, packet_idx); +} + +/** + * Compute AS-Waksman switch settings for the subnetwork occupying switch columns + * [left,left+1,...,right] + * that will route + * - from left-hand side inputs [lo,lo+1,...,hi] + * - to right-hand side destinations pi[lo],pi[lo+1],...,pi[hi]. + * + * The permutation + * - pi maps [lo, lo+1, ... hi] to itself, offset by lo, and + * - piinv is the inverse of pi. + * + * NOTE: due to offsets, neither pi or piinv are instances of integer_permutation. + */ +void as_waksman_route_inner(const size_t left, + const size_t right, + const size_t lo, + const size_t hi, + const integer_permutation &permutation, + const integer_permutation &permutation_inv, + as_waksman_routing &routing) +{ + if (left > right) + { + return; + } + + const size_t subnetwork_size = (hi - lo + 1); + const size_t subnetwork_width = as_waksman_num_columns(subnetwork_size); + assert(right - left + 1 >= subnetwork_width); + +#ifdef DEBUG + assert(permutation.min_element == lo); + assert(permutation.max_element == hi); + assert(permutation.size() == subnetwork_size); + assert(permutation.is_valid()); + assert(permutation.inverse() == permutation_inv); +#endif + + if (right - left + 1 > subnetwork_width) + { + /** + * If there is more space for the routing network than required, + * then the topology for this subnetwork includes straight edges + * along its sides and no switches, so it suffices to recurse. + */ + as_waksman_route_inner(left+1, right-1, lo, hi, permutation, permutation_inv, routing); + } + else if (subnetwork_size == 2) + { + /** + * Non-trivial base case: switch settings for a 2-element permutation + */ + assert(permutation.get(lo) == lo || permutation.get(lo) == lo+1); + assert(permutation.get(lo+1) == lo || permutation.get(lo+1) == lo + 1); + assert(permutation.get(lo) != permutation.get(lo+1)); + + routing[left][lo] = (permutation.get(lo) != lo); + } + else + { + /** + * The algorithm first assigns a setting to a LHS switch, + * route its target to RHS, which will enforce a RHS switch setting. + * Then, it back-routes the RHS value back to LHS. + * If this enforces a LHS switch setting, then forward-route that; + * otherwise we will select the next value from LHS to route. + */ + integer_permutation new_permutation(lo, hi); + integer_permutation new_permutation_inv(lo, hi); + std::vector lhs_routed(subnetwork_size, false); /* offset by lo, i.e. lhs_routed[packet_idx-lo] is set if packet packet_idx is routed */ + + size_t to_route; + size_t max_unrouted; + bool route_left; + + if (subnetwork_size % 2 == 1) + { + /** + * ODD CASE: we first deal with the bottom-most straight wire, + * which is not connected to any of the switches at this level + * of recursion and just passed into the lower subnetwork. + */ + if (permutation.get(hi) == hi) + { + /** + * Easy sub-case: it is routed directly to the bottom-most + * wire on RHS, so no switches need to be touched. + */ + new_permutation.set(hi, hi); + new_permutation_inv.set(hi, hi); + to_route = hi - 1; + route_left = true; + } + else + { + /** + * Other sub-case: the straight wire is routed to a switch + * on RHS, so route the other value from that switch + * using the lower subnetwork. + */ + const size_t rhs_switch = as_waksman_get_canonical_row_idx(lo, permutation.get(hi)); + const bool rhs_switch_setting = as_waksman_get_switch_setting_from_top_bottom_decision(lo, permutation.get(hi), false); + routing[right][rhs_switch] = rhs_switch_setting; + size_t tprime = as_waksman_switch_input(subnetwork_size, lo, rhs_switch, false); + new_permutation.set(hi, tprime); + new_permutation_inv.set(tprime, hi); + + to_route = as_waksman_other_output_position(lo, permutation.get(hi)); + route_left = false; + } + + lhs_routed[hi-lo] = true; + max_unrouted = hi - 1; + } + else + { + /** + * EVEN CASE: the bottom-most switch is fixed to a constant + * straight setting. So we route wire hi accordingly. + */ + routing[left][hi-1] = false; + to_route = hi; + route_left = true; + max_unrouted = hi; + } + + while (1) + { + /** + * INVARIANT: the wire `to_route' on LHS (if route_left = true), + * resp., RHS (if route_left = false) can be routed. + */ + if (route_left) + { + /* If switch value has not been assigned, assign it arbitrarily. */ + const size_t lhs_switch = as_waksman_get_canonical_row_idx(lo, to_route); + if (routing[left].find(lhs_switch) == routing[left].end()) + { + routing[left][lhs_switch] = false; + } + const bool lhs_switch_setting = routing[left][lhs_switch]; + const bool use_top = as_waksman_get_top_bottom_decision_from_switch_setting(lo, to_route, lhs_switch_setting); + const size_t t = as_waksman_switch_output(subnetwork_size, lo, lhs_switch, use_top); + if (permutation.get(to_route) == hi) + { + /** + * We have routed to the straight wire for the odd case, + * so now we back-route from it. + */ + new_permutation.set(t, hi); + new_permutation_inv.set(hi, t); + lhs_routed[to_route-lo] = true; + to_route = max_unrouted; + route_left = true; + } + else + { + const size_t rhs_switch = as_waksman_get_canonical_row_idx(lo, permutation.get(to_route)); + /** + * We know that the corresponding switch on the right-hand side + * cannot be set, so we set it according to the incoming wire. + */ + assert(routing[right].find(rhs_switch) == routing[right].end()); + routing[right][rhs_switch] = as_waksman_get_switch_setting_from_top_bottom_decision(lo, permutation.get(to_route), use_top); + const size_t tprime = as_waksman_switch_input(subnetwork_size, lo, rhs_switch, use_top); + new_permutation.set(t, tprime); + new_permutation_inv.set(tprime, t); + + lhs_routed[to_route-lo] = true; + to_route = as_waksman_other_output_position(lo, permutation.get(to_route)); + route_left = false; + } + } + else + { + /** + * We have arrived on the right-hand side, so the switch setting is fixed. + * Next, we back route from here. + */ + const size_t rhs_switch = as_waksman_get_canonical_row_idx(lo, to_route); + const size_t lhs_switch = as_waksman_get_canonical_row_idx(lo, permutation_inv.get(to_route)); + assert(routing[right].find(rhs_switch) != routing[right].end()); + const bool rhs_switch_setting = routing[right][rhs_switch]; + const bool use_top = as_waksman_get_top_bottom_decision_from_switch_setting(lo, to_route, rhs_switch_setting); + const bool lhs_switch_setting = as_waksman_get_switch_setting_from_top_bottom_decision(lo, permutation_inv.get(to_route), use_top); + + /* The value on the left-hand side is either the same or not set. */ + auto it = routing[left].find(lhs_switch); + assert(it == routing[left].end() || it->second == lhs_switch_setting); + routing[left][lhs_switch] = lhs_switch_setting; + + const size_t t = as_waksman_switch_input(subnetwork_size, lo, rhs_switch, use_top); + const size_t tprime = as_waksman_switch_output(subnetwork_size, lo, lhs_switch, use_top); + new_permutation.set(tprime, t); + new_permutation_inv.set(t, tprime); + + lhs_routed[permutation_inv.get(to_route)-lo] = true; + to_route = as_waksman_other_input_position(lo, permutation_inv.get(to_route)); + route_left = true; + } + + /* If the next packet to be routed hasn't been routed before, then try routing it. */ + if (!route_left || !lhs_routed[to_route-lo]) + { + continue; + } + + /* Otherwise just find the next unrouted packet. */ + while (max_unrouted > lo && lhs_routed[max_unrouted-lo]) + { + --max_unrouted; + } + + if (max_unrouted < lo || (max_unrouted == lo && lhs_routed[0])) /* lhs_routed[0] = corresponds to lo shifted by lo */ + { + /* All routed! */ + break; + } + else + { + to_route = max_unrouted; + route_left = true; + } + } + + if (subnetwork_size % 2 == 0) + { + /* Remove the AS-Waksman switch with the fixed value. */ + routing[left].erase(hi-1); + } + + const size_t d = as_waksman_top_height(subnetwork_size); + const integer_permutation new_permutation_upper = new_permutation.slice(lo, lo + d - 1); + const integer_permutation new_permutation_lower = new_permutation.slice(lo + d, hi); + + const integer_permutation new_permutation_inv_upper = new_permutation_inv.slice(lo, lo + d - 1); + const integer_permutation new_permutation_inv_lower = new_permutation_inv.slice(lo + d, hi); + + as_waksman_route_inner(left+1, right-1, lo, lo + d - 1, new_permutation_upper, new_permutation_inv_upper, routing); + as_waksman_route_inner(left+1, right-1, lo + d, hi, new_permutation_lower, new_permutation_inv_lower, routing); + } +} + +as_waksman_routing get_as_waksman_routing(const integer_permutation &permutation) +{ + const size_t num_packets = permutation.size(); + const size_t width = as_waksman_num_columns(num_packets); + + as_waksman_routing routing(width); + as_waksman_route_inner(0, width-1, 0, num_packets-1, permutation, permutation.inverse(), routing); + return routing; +} + +bool valid_as_waksman_routing(const integer_permutation &permutation, const as_waksman_routing &routing) +{ + const size_t num_packets = permutation.size(); + const size_t width = as_waksman_num_columns(num_packets); + as_waksman_topology neighbors = generate_as_waksman_topology(num_packets); + + integer_permutation curperm(num_packets); + + for (size_t column_idx = 0; column_idx < width; ++column_idx) + { + integer_permutation nextperm(num_packets); + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + size_t routed_packet_idx; + if (neighbors[column_idx][packet_idx].first == neighbors[column_idx][packet_idx].second) + { + routed_packet_idx = neighbors[column_idx][packet_idx].first; + } + else + { + auto it = routing[column_idx].find(packet_idx); + auto it2 = routing[column_idx].find(packet_idx-1); + assert((it != routing[column_idx].end()) ^ (it2 != routing[column_idx].end())); + const bool switch_setting = (it != routing[column_idx].end() ? it->second : it2->second); + + routed_packet_idx = (switch_setting ? neighbors[column_idx][packet_idx].second : neighbors[column_idx][packet_idx].first); + } + + nextperm.set(routed_packet_idx, curperm.get(packet_idx)); + } + + curperm = nextperm; + } + + return (curperm == permutation.inverse()); +} + +} // libsnark diff --git a/privacy/zsl/zsl/common/routing_algorithms/as_waksman_routing_algorithm.d b/privacy/zsl/zsl/common/routing_algorithms/as_waksman_routing_algorithm.d new file mode 100644 index 0000000..0de9a99 --- /dev/null +++ b/privacy/zsl/zsl/common/routing_algorithms/as_waksman_routing_algorithm.d @@ -0,0 +1,5 @@ +src/common/routing_algorithms/as_waksman_routing_algorithm.o: \ + src/common/routing_algorithms/as_waksman_routing_algorithm.cpp \ + src/common/routing_algorithms/as_waksman_routing_algorithm.hpp \ + src/common/utils.hpp src/common/utils.tcc \ + src/common/data_structures/integer_permutation.hpp diff --git a/privacy/zsl/zsl/common/routing_algorithms/as_waksman_routing_algorithm.hpp b/privacy/zsl/zsl/common/routing_algorithms/as_waksman_routing_algorithm.hpp new file mode 100644 index 0000000..073bda1 --- /dev/null +++ b/privacy/zsl/zsl/common/routing_algorithms/as_waksman_routing_algorithm.hpp @@ -0,0 +1,132 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for functionality for routing on an arbitrary-size (AS) Waksman network. + + AS-Waksman networks were introduced in \[BD02]. An AS-Waksman network for + N packets is recursively defined as follows: place a column of floor(N/2) switches on + the left, and a column of floor(N/2) switches on the right; then place two AS-Waksman + sub-networks, for floor(N/2) and ceil(N/2) packets respectively, in the middle. + + Note that unlike for BeneÅ¡ networks where each switch handles routing + of one packet to one of its two possible destinations, AS-Waksman + network employs switches with two input ports and two output ports + and operate either in "straight" or "cross mode". + + Routing is performed in a way that is similar to routing on Benes networks: + one first computes the switch settings for the left and right columns, + and then one recursively computes routings for the top and bottom sub-networks. + More precisely, as in \[BD02], we treat the problem of determining the switch + settings of the left and right columns as a 2-coloring problem on a certain + bipartite graph. The coloring is found by performing a depth-first search on + the graph and alternating the color at every step. For performance reasons + the graph in our implementation is implicitly represented. + + References: + + \[BD02]: + "On arbitrary size {W}aksman networks and their vulnerability", + Bruno Beauquier, Eric Darrot, + Parallel Processing Letters 2002 + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef AS_WAKSMAN_ROUTING_ALGORITHM_HPP_ +#define AS_WAKSMAN_ROUTING_ALGORITHM_HPP_ + +#include +#include +#include + +#include "common/utils.hpp" +#include "common/data_structures/integer_permutation.hpp" + +namespace libsnark { + +/** + * When laid out on num_packets \times num_columns grid, each switch + * occupies two positions: its top input and output ports are at + * position (column_idx, row_idx) and the bottom input and output + * ports are at position (column_idx, row_idx+1). + * + * We call the position assigned to the top ports of a switch its + * "canonical" position. + */ + +/** + * A data structure that stores the topology of an AS-Waksman network. + * + * For a given column index column_idx and packet index packet_idx, + * as_waksman_topology[column_idx][packet_idx] specifies the two + * possible destinations at column_idx+1-th column where the + * packet_idx-th packet in the column_idx-th column could be routed + * after passing the switch, which has (column_idx, packet_idx) as one + * of its occupied positions. + * + * This information is stored as a pair of indices, where: + * - the first index denotes the destination when the switch is + * operated in "straight" setting, and + * - the second index denotes the destination when the switch is + * operated in "cross" setting. + * + * If no switch occupies a position (column_idx, packet_idx), + * i.e. there is just a wire passing through that position, then the + * two indices are set to be equal and the packet is always routed to + * the specified destination at the column_idx+1-th column. + */ +typedef std::vector > > as_waksman_topology; + +/** + * A routing assigns a bit to each switch in the AS-Waksman routing network. + * + * More precisely: + * + * - as_waksman_routing[column_idx][packet_idx]=false, if switch with + * canonical position of (column_idx,packet_idx) is set to + * "straight" setting, and + * + * - as_waksman_routing[column_idx][packet_idx]=true, if switch with + * canonical position of (column_idx,packet_idx) is set to "cross" + * setting. + * + * Note that as_waksman_routing[column_idx][packet_idx] does contain + * entries for the positions associated with the bottom ports of the + * switches, i.e. only canonical positions are present. + */ +typedef std::vector > as_waksman_routing; + +/** + * Return the number of (switch) columns in a AS-Waksman network for a given number of packets. + * + * For example: + * - as_waksman_num_columns(2) = 1, + * - as_waksman_num_columns(3) = 3, + * - as_waksman_num_columns(4) = 3, + * and so on. + */ +size_t as_waksman_num_columns(const size_t num_packets); + +/** + * Return the topology of an AS-Waksman network for a given number of packets. + * + * See as_waksman_topology (above) for details. + */ +as_waksman_topology generate_as_waksman_topology(const size_t num_packets); + +/** + * Route the given permutation on an AS-Waksman network of suitable size. + */ +as_waksman_routing get_as_waksman_routing(const integer_permutation &permutation); + +/** + * Check if a routing "implements" the given permutation. + */ +bool valid_as_waksman_routing(const integer_permutation &permutation, const as_waksman_routing &routing); + +} // libsnark + +#endif // AS_WAKSMAN_ROUTING_ALGORITHM_HPP_ diff --git a/privacy/zsl/zsl/common/routing_algorithms/benes_routing_algorithm.cpp b/privacy/zsl/zsl/common/routing_algorithms/benes_routing_algorithm.cpp new file mode 100644 index 0000000..d787ab1 --- /dev/null +++ b/privacy/zsl/zsl/common/routing_algorithms/benes_routing_algorithm.cpp @@ -0,0 +1,316 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for functionality for routing on a Benes network. + + See benes_routing_algorithm.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "common/routing_algorithms/benes_routing_algorithm.hpp" +#include + +namespace libsnark { + +/** + * Compute the mask for all the cross edges originating at a + * particular column. + * + * Namely, the packet (column_idx, row_idx) (with column_idx < + * num_columns) can be routed to two destinations: + * + * - (column_idx+1, row_idx), if the switch handling that packet is + * set to the "straight" setting, and + * + * - (column_idx+1, row_idx XOR benes_cross_edge_mask(dimension, + * column_idx)) if the switch handling that packet is set to "cross" + * setting. + * + * For example, all cross edges in the 0-th column flip the most + * significant bit of row_idx. + */ +size_t benes_cross_edge_mask(const size_t dimension, const size_t column_idx) +{ + return (column_idx < dimension ? 1ul<<(dimension-1-column_idx) : 1ul<<(column_idx-dimension)); +} + +/** + * Return the specified destination of packet of the left-hand side of + * the routing network, based on the subnetwork (recall that each + * packet has two possible destinations -- one at the top subnetwork + * and one at the bottom subnetwork). + * + * That is for a packet located at column_idx-th column and row_idx-th + * row, return: + * + * - row_idx' of the destination packet (column_idx+1, row_idx') at + * the top subnetwork (if use_top = true) + * + * - row_idx' of the destination packet (column_idx+1, row_idx') at + * the bottom subnetwork (if use_top = false) + */ +size_t benes_lhs_packet_destination(const size_t dimension, const size_t column_idx, const size_t row_idx, const bool use_top) +{ + const size_t mask = benes_cross_edge_mask(dimension, column_idx); + return (use_top ? row_idx & ~mask : row_idx | mask); +} + +/** + * Return the specified source of packet of the right-hand side of the + * routing network, based on the subnetwork (recall that each packet + * has two possible source packets -- one at the top subnetwork and + * one at the bottom subnetwork). + * + * That is for a packet located at column_idx-th column and row_idx-th + * row, return: + * + * - row_idx' of the destination packet (column_idx-1, row_idx') at + * the top subnetwork (if use_top = true) + * + * - row_idx' of the destination packet (column_idx-1, row_idx') at + * the bottom subnetwork (if use_top = false) + */ +size_t benes_rhs_packet_source(const size_t dimension, const size_t column_idx, const size_t row_idx, const bool use_top) +{ + return benes_lhs_packet_destination(dimension, column_idx-1, row_idx, use_top); /* by symmetry */ +} + +/** + * For a switch located at column_idx-th column and row_idx-th row, + * return the switch setting that would route its packet using the top + * subnetwork. + */ +bool benes_get_switch_setting_from_subnetwork(const size_t dimension, const size_t column_idx, const size_t row_idx, const bool use_top) +{ + return (row_idx != benes_lhs_packet_destination(dimension, column_idx, row_idx, use_top)); +} + +/** + * A packet column_idx-th column and row_idx-th row of the routing + * network has two destinations (see comment by + * benes_cross_edge_mask), this returns row_idx' of the "cross" + * destination. + */ +size_t benes_packet_cross_destination(const size_t dimension, const size_t column_idx, const size_t row_idx) +{ + const size_t mask = benes_cross_edge_mask(dimension, column_idx); + return row_idx ^ mask; +} + +/** + * A packet column_idx-th column and row_idx-th row of the routing + * network has two source packets that could give rise to it (see + * comment by benes_cross_edge_mask), this returns row_idx' of the + * "cross" source packet. + */ +size_t benes_packet_cross_source(const size_t dimension, const size_t column_idx, const size_t packet_idx) +{ + return benes_packet_cross_destination(dimension, column_idx-1, packet_idx); /* by symmetry */ +} + +size_t benes_num_columns(const size_t num_packets) +{ + const size_t dimension = log2(num_packets); + assert(num_packets == 1ul< +std::vector > route_by_benes(const benes_routing &routing, const std::vector &start) +{ + const size_t num_packets = start.size(); + const size_t num_columns = benes_num_columns(num_packets); + const size_t dimension = log2(num_packets); + + std::vector > res(num_columns+1, std::vector(num_packets)); + res[0] = start; + + for (size_t column_idx = 0; column_idx < num_columns; ++column_idx) + { + const size_t mask = benes_cross_edge_mask(dimension, column_idx); + + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + size_t next_packet_idx = (routing[column_idx][packet_idx] == false) ? packet_idx : packet_idx ^ mask; + res[column_idx+1][next_packet_idx] = res[column_idx][packet_idx]; + } + } + + return res; +} + +bool valid_benes_routing(const integer_permutation &permutation, const benes_routing &routing) +{ + const size_t num_packets = permutation.size(); + const size_t num_columns = benes_num_columns(num_packets); + + std::vector input_packets(num_packets); + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + input_packets[packet_idx] = packet_idx; + } + + const std::vector > routed_packets = route_by_benes(routing, input_packets); + + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + if (routed_packets[num_columns][permutation.get(packet_idx)] != input_packets[packet_idx]) + { + return false; + } + } + + return true; +} + +} // libsnark diff --git a/privacy/zsl/zsl/common/routing_algorithms/benes_routing_algorithm.d b/privacy/zsl/zsl/common/routing_algorithms/benes_routing_algorithm.d new file mode 100644 index 0000000..0c1e6b9 --- /dev/null +++ b/privacy/zsl/zsl/common/routing_algorithms/benes_routing_algorithm.d @@ -0,0 +1,5 @@ +src/common/routing_algorithms/benes_routing_algorithm.o: \ + src/common/routing_algorithms/benes_routing_algorithm.cpp \ + src/common/routing_algorithms/benes_routing_algorithm.hpp \ + src/common/data_structures/integer_permutation.hpp src/common/utils.hpp \ + src/common/utils.tcc diff --git a/privacy/zsl/zsl/common/routing_algorithms/benes_routing_algorithm.hpp b/privacy/zsl/zsl/common/routing_algorithms/benes_routing_algorithm.hpp new file mode 100644 index 0000000..4d33f90 --- /dev/null +++ b/privacy/zsl/zsl/common/routing_algorithms/benes_routing_algorithm.hpp @@ -0,0 +1,91 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for functionality for routing on a Benes network. + + Routing is performed via the standard algorithm that computes a + routing by first computing the switch settings for the left and right + columns of the network and then recursively computing routings for + the top half and the bottom half of the network (each of which is a + Benes network of smaller size). + + References: + + \[Ben65]: + "Mathematical theory of connecting networks and telephone traffic", + Václav E. BeneÅ¡, + Academic Press 1965 + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BENES_ROUTING_ALGORITHM_HPP_ +#define BENES_ROUTING_ALGORITHM_HPP_ + +#include + +#include "common/data_structures/integer_permutation.hpp" +#include "common/utils.hpp" + +namespace libsnark { + +/** + * A data structure that stores the topology of a Benes network. + * + * For a given column index column_idx and packet index packet_idx, + * benes_topology[column_idx][packet_idx] specifies the two possible + * destinations where the packet_idx-th packet in the column_idx-th column + * could be routed. This information is stored as a pair of indices, where: + * - the first index denotes the destination when the switch is in "straight" mode, and + * - the second index denotes the destination when the switch is in "cross" mode. + * + * (The topology has a very succinct description and can be easily + * queried at an arbitrary position, see implementation of + * generate_benes_topology for details.) + */ +typedef std::vector > > benes_topology; + +/** + * A routing assigns a bit to each switch in a Benes network. + * + * For a d-dimensional Benes network, the switch bits are stored in a + * vector consisting of 2*d entries, and each entry contains 2^d bits. + * That is, we have one switch per packet, but switch settings are not + * independent. + */ +typedef std::vector benes_routing; + +/** + * Return the number of (switch) columns in a Benes network for a given number of packets. + * + * For example: + * - benes_num_columns(2) = 2, + * - benes_num_columns(4) = 4, + * - benes_num_columns(8) = 6, + * and so on. + */ +size_t benes_num_columns(const size_t num_packets); + +/** + * Return the topology of a Benes network for a given number of packets. + * + * See benes_topology (above) for details. + */ +benes_topology generate_benes_topology(const size_t num_packets); + +/** + * Route the given permutation on a Benes network of suitable size. + */ +benes_routing get_benes_routing(const integer_permutation &permutation); + +/** + * Check if a routing "implements" the given permutation. + */ +bool valid_benes_routing(const integer_permutation &permutation, const benes_routing &routing); + +} // libsnark + +#endif // BENES_ROUTING_ALGORITHM_HPP_ diff --git a/privacy/zsl/zsl/common/routing_algorithms/profiling/profile_routing_algorithms.cpp b/privacy/zsl/zsl/common/routing_algorithms/profiling/profile_routing_algorithms.cpp new file mode 100644 index 0000000..4d386c2 --- /dev/null +++ b/privacy/zsl/zsl/common/routing_algorithms/profiling/profile_routing_algorithms.cpp @@ -0,0 +1,63 @@ +/** @file + ***************************************************************************** + + Functions to profile the algorithms that route on Benes and AS-Waksman networks. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include + +#include "common/profiling.hpp" +#include "common/routing_algorithms/as_waksman_routing_algorithm.hpp" +#include "common/routing_algorithms/benes_routing_algorithm.hpp" + +using namespace libsnark; + +void profile_benes_algorithm(const size_t n) +{ + printf("* Size: %zu\n", n); + + assert(n == 1ul< + +#include "common/profiling.hpp" +#include "common/routing_algorithms/benes_routing_algorithm.hpp" +#include "common/routing_algorithms/as_waksman_routing_algorithm.hpp" + +using namespace libsnark; + +/** + * Test Benes network routing for all permutations on 2^log2(N) elements. + */ +void test_benes(const size_t N) +{ + integer_permutation permutation(1ul << log2(N)); + + do { + const benes_routing routing = get_benes_routing(permutation); + assert(valid_benes_routing(permutation, routing)); + } while (permutation.next_permutation()); +} + +/** + * Test AS-Waksman network routing for all permutations on N elements. + */ +void test_as_waksman(const size_t N) +{ + integer_permutation permutation(N); + + do { + const as_waksman_routing routing = get_as_waksman_routing(permutation); + assert(valid_as_waksman_routing(permutation, routing)); + } while (permutation.next_permutation()); +} + +int main(void) +{ + start_profiling(); + + enter_block("Test routing algorithms"); + + enter_block("Test Benes network routing algorithm"); + size_t bn_size = 8; + print_indent(); printf("* for all permutations on %zu elements\n", bn_size); + test_benes(bn_size); + leave_block("Test Benes network routing algorithm"); + + + enter_block("Test AS-Waksman network routing algorithm"); + size_t asw_max_size = 9; + for (size_t i = 2; i <= asw_max_size; ++i) + { + print_indent(); printf("* for all permutations on %zu elements\n", i); + test_as_waksman(i); + } + leave_block("Test AS-Waksman network routing algorithm"); + + leave_block("Test routing algorithms"); +} diff --git a/privacy/zsl/zsl/common/routing_algorithms/tests/test_routing_algorithms.py b/privacy/zsl/zsl/common/routing_algorithms/tests/test_routing_algorithms.py new file mode 100644 index 0000000..239b22e --- /dev/null +++ b/privacy/zsl/zsl/common/routing_algorithms/tests/test_routing_algorithms.py @@ -0,0 +1,406 @@ +#!/usr/bin/env python + +from __future__ import division +import math +import itertools +import random +import time +from collections import defaultdict + +def top_height(sz): + """Returns the height of the top part of size `sz' AS-Waksman network.""" + return sz // 2 + +def bottom_height(sz): + """Returns the height of the bottom part of size `sz' AS-Waksman + network.""" + return sz - top_height(sz) + +def switch_output(base, pos, sz, top): + """The recursive AS-Waksman construction AS-Waksman(sz) places two + lines of floor(sz/2) switches each and connects the outputs of + AS-Waksman(floor(sz/2)) and AS-Waksman(ceil(sz/2)) in between + them. + + Return the output wire of left-hand side switch `pos'(relative to + the base level `base' in the recursive call) in size `sz' + AS-Waksman network. + + If `top' = True, return the top wire, otherwise return bottom + wire. """ + relpos = pos - base + assert relpos % 2 == 0 and relpos + 1 < sz + if top: + return base + (relpos // 2) + else: + return base + top_height(sz) + (relpos // 2) + +def switch_input(base, pos, sz, top): + """This function is symmetric to switch_output(base, pos, sz, top), + but returns the input wire of the right-hand side switch (rather than + the output wire of the left-hand side switch).""" + # because of symmetry this coincides with switch_output + return switch_output(base, pos, sz, top) + +def width(sz): + """Returns width of size `sz' AS-Waksman network. For example, width(2) = + 1, width(3) = 3, width(4) = 3.""" + return 2*int(math.ceil(math.log(sz, 2)))-1 + +def construct_as_waksman_topology(n): + """Returns a pair (neighbors, switches) describing the topology of + AS-Waksman network of size n. + + neigbhors[i][j] lists the possible locations where a wire, at + position j before going through the i-th column, could be routed to + after passing through the column. neighbors[i][j] is a length 1 + list for straight wires and length 2 list for switches, where the + first element denotes the destination when the switch is operated + in "straight" mode and the second element denotes the destination + for the "cross" mode. + + switches[i] is the dictionary, whose keys are all positions of the + switches at the i-th column and keys are switch settings. This + function only returns the topology, so switch settings are all set + to be None.""" + + assert n > 1 + w = width(n) + + neighbors = [{} for i in xrange(w)] + switches = [{} for i in xrange(w)] + + def construct_as_waksman_topology_inner(left, right, lo, hi, rhs_dests): + """Construct AS-Waksman subnetwork occupying switch columns [left, + left+1, ..., right] that will route left-hand side inputs [lo, + lo+1, ..., hi] to right-hand side destinations rhs_dests[0], + rhs_dests[1], ..., rhs_dests[hi-lo+1]. (That is, rhs_dests are + 0-indexed w.r.t. base of lo.) + + This function will fill out neighbors[left], + neighbors[right-1] and add switches in columns switches[left], + switches[right].""" + if left > right: + return + + sz = (hi - lo + 1) + assert len(rhs_dests) == sz + + assert (right - left + 1) >= width(sz) + + if right - left + 1 > width(sz): + # If there is more space for the routing network than + # required, just add straight edges. This also takes care + # of size 1 routing network base case. + for i in xrange(lo, hi + 1): + neighbors[left][i] = [i] + neighbors[right][i] = [rhs_dests[i - lo]] + # Recurse to construct the corresponding subnetwork. + construct_as_waksman_topology_inner(left + 1, right - 1, lo, hi, range(lo, hi+1)) + elif sz == 2: + # Non-trivial base case: routing a 2-element permutation. + neighbors[left][lo] = [rhs_dests[0], rhs_dests[1]] + neighbors[left][hi] = [rhs_dests[1], rhs_dests[0]] + switches[left][lo] = None + else: + # Networks of size sz > 2 are handled by adding two lines + # of switches alongside the network and recursing. + new_rhs_dests = [None] * sz + + # This adds floor(sz/2) switches alongside the network. As + # per AS-Waksman construction one of the switches in the even + # case can be eliminated (i.e. set to be constant); this + # will be handled later. + for i in xrange(lo, hi, 2): + switches[left][i] = None + switches[right][i] = None + + neighbors[left][i] = [switch_output(lo, i, sz, True), switch_output(lo, i, sz, False)] + neighbors[left][i+1] = [switch_output(lo, i, sz, False), switch_output(lo, i, sz, True)] + + new_rhs_dests[switch_input(lo, i, sz, True)-lo] = i + new_rhs_dests[switch_input(lo, i, sz, False)-lo] = i+1 + + neighbors[right][i] = [rhs_dests[i-lo], rhs_dests[i+1-lo]] + neighbors[right][i+1] = [rhs_dests[i+1-lo], rhs_dests[i-lo]] + + if sz % 2 == 1: + # Odd special case: the last wire is not connected to + # any of the switches and just routed straight. + neighbors[left][hi] = [hi] + neighbors[right][hi] = [rhs_dests[hi-lo]] + new_rhs_dests[hi-lo] = hi + else: + # Even special case: fix the bottom-most LHS switch to + # a constant "straight" setting. + neighbors[left][hi-1] = [switch_output(lo, hi-1, sz, True)] + neighbors[left][hi] == [switch_output(lo, hi-1, sz, False)] + + d = top_height(sz) + construct_as_waksman_topology_inner(left + 1, right - 1, lo, lo + d - 1, new_rhs_dests[:d]) + construct_as_waksman_topology_inner(left + 1, right - 1, lo + d, hi, new_rhs_dests[d:]) + + construct_as_waksman_topology_inner(0, w-1, 0, n-1, range(n)) + return (neighbors, switches) + +def switch_position_from_wire_position(base, global_pos): + """Each switch occupies two wire positions (pos, pos+1); given a wire + position (plus, a base for offsetting the switch within subnetwork + that created it), this function returns the "canonical" position for + the switch, that is, the "upper" position global_pos. + + global_pos is assumed to be input position for the LHS switches + and output position for the RHS switches.""" + return ((global_pos - base) & ~1) + base + +def get_switch_value_from_top_bottom_decision(base, global_pos, top): + """Return a switch value that makes switch s = + switch_position_from_wire_position(base, global_pos) to route the + wire global_pos via the top (if top = True), resp., bottom (if top + = False) subnetwork. + + global_pos is assumed to be input position for the LHS switches + and output position for the RHS switches.""" + s = switch_position_from_wire_position(base, global_pos) + return (s == global_pos) ^ top + +def get_top_bottom_decision_from_switch_value(base, global_pos, val): + """Returns True if the switch s = + switch_position_from_wire_position(base, global_pos) when set to + "straight" (if val = True), resp., "cross" (if val = False), + routes the wire global_pos via the top subnetwork. + + global_pos is assumed to be input position for the LHS switches + and output position for the RHS switches.""" + s = switch_position_from_wire_position(base, global_pos) + return (s == global_pos) ^ val + +def other_output_position(base, global_pos): + """Given an output position of a RHS switch, calculate and return the + output position of the other wire also connected to this switch.""" + switch = switch_position_from_wire_position(base, global_pos) + return (1 - (global_pos - switch)) + switch + +def other_input_position(base, global_pos): + """Given an input position of a LHS switch, calculate and return the + output position of the other wire also connected to this switch.""" + # Exploiting symmetry here, this is the same as the output + # position for the corresponding RHS switch. + return other_output_position(base, global_pos) + +def route_as_waksman(n, network, pi): + """Return AS-Waksman switch settings that implement the given + permutation.""" + assert n > 1 + w = width(n) + neighbors, switches = network + + piinv = [None for i in xrange(n)] + for i in xrange(n): + piinv[pi[i]] = i + + def route_as_waksman_inner(left, right, lo, hi, pi, piinv): + """Get AS-Waksman switch settings for the subnetwork occupying switch + columns [left, left+1, ..., right] that will route left-hand + side inputs [lo, lo+1, ..., hi] to right-hand side + destinations pi[lo], pi[lo+1], ... pi[hi].""" + if left > right: + return + + sz = (hi - lo + 1) + assert (right - left + 1) >= width(sz) + + if right - left + 1 > width(sz): + # If there is more space for the routing network than + # required, then the topology for this subnetwork includes + # straight edges along its sides and no switches, so we + # just recurse. + route_as_waksman_inner(left + 1, right - 1, lo, hi, pi, piinv) + elif sz == 2: + # Non-trivial base case: switch settings for a 2-element permutation. + assert set([pi[lo], pi[lo+1]]) == set([lo, lo+1]) + switches[left][lo] = (pi[lo] != lo) + else: + newpi = defaultdict(lambda : None) + newpiinv = defaultdict(lambda : None) + # Our algorithm will first assign a setting for a LHS + # switch, route its target to RHS, which will enforce a + # RHS switch setting. Then, we back-route the RHS value + # back to LHS. If this enforces a LHS switch setting, then + # forward-route that, otherwise we will select the next + # value from LHS to route. + lhs_routed = defaultdict(lambda : False) + + if sz % 2 == 1: + # If size is odd we first deal with the bottom-most + # straight wire, which is not connected to any of the + # switches at this level of recursion and just passed + # into the lower subnetwork. + if pi[hi] == hi: + # Easy case: it is routed directly to the + # bottom-most wire on RHS, so no switches need to + # be touched. + newpi[hi] = hi + newpiinv[hi] = hi + to_route = hi - 1 + route_left = True + else: + # Other case: the straight wire is routed to a + # switch on RHS, so route the other value from + # that switch using the lower subnetwork. + rhs_switch = switch_position_from_wire_position(lo, pi[hi]) + rhs_switch_val = get_switch_value_from_top_bottom_decision(lo, pi[hi], False) + switches[right][rhs_switch] = rhs_switch_val + tprime = switch_input(lo, rhs_switch, sz, False) + newpi[hi] = tprime + newpiinv[tprime] = hi + + to_route = other_output_position(lo, pi[hi]) + route_left = False + + lhs_routed[hi] = True + max_unrouted = hi - 1 + else: + # If n is even, then the bottom-most switch (one + # freely set in Benes construction) is fixed to a + # constant straight setting. So we route wire hi + # accordingly. + switches[left][hi-1] = False + to_route = hi + route_left = True + max_unrouted = hi + + while True: + # We maintain invariant that wire `to_route' on LHS + # (if route_left = True), resp., rhs (if route_left = + # False) can be routed. + if route_left: + # If switch value hasn't been assigned, assign it arbitrarily + lhs_switch = switch_position_from_wire_position(lo, to_route) + if switches[left][lhs_switch] is None: + switches[left][lhs_switch] = False + lhs_switch_val = switches[left][lhs_switch] + use_top = get_top_bottom_decision_from_switch_value(lo, to_route, lhs_switch_val) + + t = switch_output(lo, lhs_switch, sz, use_top) + if pi[to_route] == hi: + # We have routed to the straight wire for the + # odd case, so back-route from it. + newpi[t] = hi + newpiinv[hi] = t + + lhs_routed[to_route] = True + to_route = max_unrouted + route_left = True + else: + rhs_switch = switch_position_from_wire_position(lo, pi[to_route]) + # We know that the corresponding switch on RHS + # cannot be set, so set it according to our + # incoming wire. + assert switches[right][rhs_switch] is None + + switches[right][rhs_switch] = get_switch_value_from_top_bottom_decision(lo, pi[to_route], use_top) + tprime = switch_input(lo, rhs_switch, sz, use_top) + newpi[t] = tprime + newpiinv[tprime] = t + + lhs_routed[to_route] = True + to_route = other_output_position(lo, pi[to_route]) + route_left = False + else: + # We have arrived on RHS side, so our switch + # setting is fixed. We will just back-route from + # that. + rhs_switch = switch_position_from_wire_position(lo, to_route) + lhs_switch = switch_position_from_wire_position(lo, piinv[to_route]) + + assert switches[right][rhs_switch] is not None + rhs_switch_val = switches[right][rhs_switch] + use_top = get_top_bottom_decision_from_switch_value(lo, to_route, rhs_switch_val) + lhs_switch_val = get_switch_value_from_top_bottom_decision(lo, piinv[to_route], use_top) + + # The value on LHS is either the same or unset + assert switches[left][lhs_switch] in [None, lhs_switch_val] + + switches[left][lhs_switch] = lhs_switch_val + t = switch_input(lo, rhs_switch, sz, use_top) + tprime = switch_output(lo, lhs_switch, sz, use_top) + newpi[tprime] = t + newpiinv[t] = tprime + + lhs_routed[piinv[to_route]] = True + to_route = other_input_position(lo, piinv[to_route]) + route_left = True + + # If the next item to be routed hasn't been routed + # before, then try routing it. + if not route_left or not lhs_routed[to_route]: + continue + + # Otherwise just find the next unrouted item. + while max_unrouted >= lo and lhs_routed[max_unrouted]: + max_unrouted -= 1 + + if max_unrouted < lo: + # All routed + break + else: + to_route = max_unrouted + route_left = True + + d = top_height(sz) + route_as_waksman_inner(left + 1, right - 1, lo, lo + d - 1, newpi, newpiinv) + route_as_waksman_inner(left + 1, right - 1, lo + d, hi, newpi, newpiinv) + + route_as_waksman_inner(0, w-1, 0, n-1, pi, piinv) + +def check_as_waksman_routing(network, pi): + assert n > 1 + w = width(n) + neighbors, switches = network + + piinv = [None for i in xrange(n)] + for i in xrange(n): + piinv[pi[i]] = i + curperm = range(n) + for i in xrange(w): + nextperm = [None] * n + for j in xrange(n): + assert len(neighbors[i][j]) in [1, 2] + + if len(neighbors[i][j]) == 1: + nextperm[neighbors[i][j][0]] = curperm[j] + else: + assert (j in switches[i]) ^ ((j - 1) in switches[i]) + switchval = switches[i][j] if j in switches[i] else switches[i][j-1] + nextperm[neighbors[i][j][1 if switchval else 0]] = curperm[j] + curperm = nextperm + + return curperm == piinv + +def test_routing_of_all_permutations(n): + for pi in itertools.permutations(range(n)): + print n, pi + network = construct_as_waksman_topology(n) + route_as_waksman(n, network, pi) + assert check_as_waksman_routing(network, pi) + +def profile_routing_algorithm_speed(k_min, k_max): + prev_t = None + for k in xrange(k_min, k_max+1): + n = 2**k + pi = range(n) + random.shuffle(pi) + network = construct_network(n) + t = time.time() + route(n, network, pi) + t = time.time() - t + assert check_as_waksman_routing(network, pi) + print n, t, (t/prev_t if prev_t else "-"), t/(n * k) + prev_t = t + + +if __name__ == '__main__': + for n in xrange(2, 9): + test_routing_of_all_permutations(n) + #profile_routing_algorithm_speed(2, 16) diff --git a/privacy/zsl/zsl/common/serialization.hpp b/privacy/zsl/zsl/common/serialization.hpp new file mode 100644 index 0000000..bea7feb --- /dev/null +++ b/privacy/zsl/zsl/common/serialization.hpp @@ -0,0 +1,106 @@ +/** @file + ***************************************************************************** + + Declaration of serialization routines and constants. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SERIALIZATION_HPP_ +#define SERIALIZATION_HPP_ + +#include +#include +#include +#include +#include + +namespace libsnark { + +/* + * @todo + * The serialization is fragile. Shoud be rewritten using a standard, portable-format + * library like boost::serialize. + * + * However, for now the following conventions are used within the code. + * + * All algebraic objects support either binary or decimal output using + * the standard C++ stream operators (operator<<, operator>>). + * + * The binary mode is activated by defining a BINARY_OUTPUT + * preprocessor macro (e.g. g++ -DBINARY_OUTPUT ...). + * + * Binary output assumes that the stream is to be binary read at its + * current position so any white space should be consumed beforehand. + * + * Consecutive algebraic objects are separated by OUTPUT_NEWLINE and + * within themselves (e.g. X and Y coordinates for field elements) with + * OUTPUT_SEPARATOR (as defined below). + * + * Therefore to dump two integers, two Fp elements and another integer + * one would: + * + * out << 3 << "\n"; + * out << 4 << "\n"; + * out << FieldT(56) << OUTPUT_NEWLINE; + * out << FieldT(78) << OUTPUT_NEWLINE; + * out << 9 << "\n"; + * + * Then reading back it its reader's responsibility (!) to consume "\n" + * after 4, but Fp::operator<< will correctly consume OUTPUT_NEWLINE. + * + * The reader should also consume "\n" after 9, so that another field + * element can be properly chained. This is especially important for + * binary output. + * + * The binary serialization of algebraic objects is currently *not* + * portable between machines of different word sizes. + */ + +#ifdef BINARY_OUTPUT +#define OUTPUT_NEWLINE "" +#define OUTPUT_SEPARATOR "" +#else +#define OUTPUT_NEWLINE "\n" +#define OUTPUT_SEPARATOR " " +#endif + +inline void consume_newline(std::istream &in); +inline void consume_OUTPUT_NEWLINE(std::istream &in); +inline void consume_OUTPUT_SEPARATOR(std::istream &in); + +inline void output_bool(std::ostream &out, const bool b); +inline void input_bool(std::istream &in, bool &b); + +inline void output_bool_vector(std::ostream &out, const std::vector &v); +inline void input_bool_vector(std::istream &in, std::vector &v); + +template +T reserialize(const T &obj); + +template +std::ostream& operator<<(std::ostream& out, const std::vector &v); + +template +std::istream& operator>>(std::ostream& out, std::vector &v); + +template +std::ostream& operator<<(std::ostream& out, const std::map &m); + +template +std::istream& operator>>(std::istream& in, std::map &m); + +template +std::ostream& operator<<(std::ostream& out, const std::set &s); + +template +std::istream& operator>>(std::istream& in, std::set &s); + +} // libsnark + +#include "common/serialization.tcc" + +#endif // SERIALIZATION_HPP_ diff --git a/privacy/zsl/zsl/common/serialization.tcc b/privacy/zsl/zsl/common/serialization.tcc new file mode 100644 index 0000000..c6f67bc --- /dev/null +++ b/privacy/zsl/zsl/common/serialization.tcc @@ -0,0 +1,204 @@ +/** @file + ***************************************************************************** + + Implementation of serialization routines. + + See serialization.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SERIALIZATION_TCC_ +#define SERIALIZATION_TCC_ + +#include +#include +#include "common/utils.hpp" + +namespace libsnark { + +inline void consume_newline(std::istream &in) +{ + char c; + in.read(&c, 1); +} + +inline void consume_OUTPUT_NEWLINE(std::istream &in) +{ +#ifdef BINARY_OUTPUT + // nothing to consume + UNUSED(in); +#else + char c; + in.read(&c, 1); +#endif +} + +inline void consume_OUTPUT_SEPARATOR(std::istream &in) +{ +#ifdef BINARY_OUTPUT + // nothing to consume + UNUSED(in); +#else + char c; + in.read(&c, 1); +#endif +} + +inline void output_bool(std::ostream &out, const bool b) +{ + out << (b ? 1 : 0) << "\n"; +} + +inline void input_bool(std::istream &in, bool &b) +{ + size_t tmp; + in >> tmp; + consume_newline(in); + assert(tmp == 0 || tmp == 1); + + b = (tmp == 1 ? true : false); +} + +inline void output_bool_vector(std::ostream &out, const std::vector &v) +{ + out << v.size() << "\n"; + for (const bool b : v) + { + output_bool(out, b); + } +} + +inline void input_bool_vector(std::istream &in, std::vector &v) +{ + size_t size; + in >> size; + consume_newline(in); + v.resize(size); + for (size_t i = 0; i < size; ++i) + { + bool b; + input_bool(in, b); + v[i] = b; + } +} + +template +T reserialize(const T &obj) +{ + std::stringstream ss; + ss << obj; + T tmp; + ss >> tmp; + assert(obj == tmp); + return tmp; +} + +template +std::ostream& operator<<(std::ostream& out, const std::vector &v) +{ + static_assert(!std::is_same::value, "this does not work for std::vector"); + out << v.size() << "\n"; + for (const T& t : v) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +template +std::istream& operator>>(std::istream& in, std::vector &v) +{ + static_assert(!std::is_same::value, "this does not work for std::vector"); + size_t size; + in >> size; + consume_newline(in); + + v.resize(0); + for (size_t i = 0; i < size; ++i) + { + T elt; + in >> elt; + consume_OUTPUT_NEWLINE(in); + v.push_back(elt); + } + + return in; +} + +template +std::ostream& operator<<(std::ostream& out, const std::map &m) +{ + out << m.size() << "\n"; + + for (auto &it : m) + { + out << it.first << "\n"; + out << it.second << "\n"; + } + + return out; +} + +template +std::istream& operator>>(std::istream& in, std::map &m) +{ + m.clear(); + size_t size; + in >> size; + consume_newline(in); + + for (size_t i = 0; i < size; ++i) + { + T1 k; + T2 v; + in >> k; + consume_newline(in); + in >> v; + consume_newline(in); + m[k] = v; + } + + return in; +} + +template +std::ostream& operator<<(std::ostream& out, const std::set &s) +{ + out << s.size() << "\n"; + + for (auto &el : s) + { + out << el << "\n"; + } + + return out; +} + + +template +std::istream& operator>>(std::istream& in, std::set &s) +{ + s.clear(); + size_t size; + in >> size; + consume_newline(in); + + for (size_t i = 0; i < size; ++i) + { + T el; + in >> el; + consume_newline(in); + s.insert(el); + } + + return in; +} + +} + +#endif // SERIALIZATION_TCC_ diff --git a/privacy/zsl/zsl/common/template_utils.hpp b/privacy/zsl/zsl/common/template_utils.hpp new file mode 100644 index 0000000..8dbfd26 --- /dev/null +++ b/privacy/zsl/zsl/common/template_utils.hpp @@ -0,0 +1,26 @@ +/** @file + ***************************************************************************** + + Declaration of functions for supporting the use of templates. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TEMPLATE_UTILS_HPP_ +#define TEMPLATE_UTILS_HPP_ + +namespace libsnark { + +/* A commonly used SFINAE helper type */ +template +struct void_type +{ + typedef void type; +}; + +} // libsnark + +#endif // TEMPLATE_UTILS_HPP_ diff --git a/privacy/zsl/zsl/common/utils.cpp b/privacy/zsl/zsl/common/utils.cpp new file mode 100644 index 0000000..5332769 --- /dev/null +++ b/privacy/zsl/zsl/common/utils.cpp @@ -0,0 +1,115 @@ +/** @file + ***************************************************************************** + Implementation of misc math and serialization utility functions + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include +#include +#include "common/utils.hpp" + +namespace libsnark { + +size_t log2(size_t n) +/* returns ceil(log2(n)), so 1ul< 1) + { + n >>= 1; + r++; + } + + return r; +} + +size_t to_twos_complement(int i, size_t w) +{ + assert(i >= -(1l<<(w-1))); + assert(i < (1l<<(w-1))); + return (i >= 0) ? i : i + (1l<>= 1; + } + return r; +} + +bit_vector int_list_to_bits(const std::initializer_list &l, const size_t wordsize) +{ + bit_vector res(wordsize*l.size()); + for (size_t i = 0; i < l.size(); ++i) + { + for (size_t j = 0; j < wordsize; ++j) + { + res[i*wordsize + j] = (*(l.begin()+i) & (1ul<<(wordsize-1-j))); + } + } + return res; +} + +long long div_ceil(long long x, long long y) +{ + return (x + (y-1)) / y; +} + +bool is_little_endian() +{ + uint64_t a = 0x12345678; + unsigned char *c = (unsigned char*)(&a); + return (*c = 0x78); +} + +std::string FORMAT(const std::string &prefix, const char* format, ...) +{ + const static size_t MAX_FMT = 256; + char buf[MAX_FMT]; + va_list args; + va_start(args, format); + vsnprintf(buf, MAX_FMT, format, args); + va_end(args); + + return prefix + std::string(buf); +} + +void serialize_bit_vector(std::ostream &out, const bit_vector &v) +{ + out << v.size() << "\n"; + for (size_t i = 0; i < v.size(); ++i) + { + out << v[i] << "\n"; + } +} + +void deserialize_bit_vector(std::istream &in, bit_vector &v) +{ + size_t size; + in >> size; + v.resize(size); + for (size_t i = 0; i < size; ++i) + { + bool b; + in >> b; + v[i] = b; + } +} +} // libsnark diff --git a/privacy/zsl/zsl/common/utils.d b/privacy/zsl/zsl/common/utils.d new file mode 100644 index 0000000..282be13 --- /dev/null +++ b/privacy/zsl/zsl/common/utils.d @@ -0,0 +1,2 @@ +src/common/utils.o: src/common/utils.cpp src/common/utils.hpp \ + src/common/utils.tcc diff --git a/privacy/zsl/zsl/common/utils.hpp b/privacy/zsl/zsl/common/utils.hpp new file mode 100644 index 0000000..8d7f06a --- /dev/null +++ b/privacy/zsl/zsl/common/utils.hpp @@ -0,0 +1,60 @@ +/** @file + ***************************************************************************** + Declaration of misc math and serialization utility functions + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef UTILS_HPP_ +#define UTILS_HPP_ + +#include +#include +#include +#include +#include + +namespace libsnark { + +typedef std::vector bit_vector; + +/// returns ceil(log2(n)), so 1ul< &l, const size_t wordsize); +long long div_ceil(long long x, long long y); + +bool is_little_endian(); + +std::string FORMAT(const std::string &prefix, const char* format, ...); + +/* A variadic template to suppress unused argument warnings */ +template +void UNUSED(Types&&...) {} + +#ifdef DEBUG +#define FMT FORMAT +#else +#define FMT(...) (UNUSED(__VA_ARGS__), "") +#endif + +void serialize_bit_vector(std::ostream &out, const bit_vector &v); +void deserialize_bit_vector(std::istream &in, bit_vector &v); + +template +size_t size_in_bits(const std::vector &v); + +#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0])) + +} // libsnark + +#include "common/utils.tcc" /* note that utils has a templatized part (utils.tcc) and non-templatized part (utils.cpp) */ +#endif // UTILS_HPP_ diff --git a/privacy/zsl/zsl/common/utils.tcc b/privacy/zsl/zsl/common/utils.tcc new file mode 100644 index 0000000..f97178f --- /dev/null +++ b/privacy/zsl/zsl/common/utils.tcc @@ -0,0 +1,23 @@ +/** @file + ***************************************************************************** + Implementation of templatized utility functions + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef UTILS_TCC_ +#define UTILS_TCC_ + +namespace libsnark { + +template +size_t size_in_bits(const std::vector &v) +{ + return v.size() * T::size_in_bits(); +} + +} // libsnark + +#endif // UTILS_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/constraint_profiling.cpp b/privacy/zsl/zsl/gadgetlib1/constraint_profiling.cpp new file mode 100644 index 0000000..bc17e63 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/constraint_profiling.cpp @@ -0,0 +1,48 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for profiling constraints. + + See constraint_profiling.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "gadgetlib1/constraint_profiling.hpp" +#include "common/profiling.hpp" + +namespace libsnark { + +size_t constraint_profiling_indent = 0; +std::vector constraint_profiling_table; + +size_t PRINT_CONSTRAINT_PROFILING() +{ + size_t accounted = 0; + print_indent(); + printf("Constraint profiling:\n"); + for (constraint_profiling_entry &ent : constraint_profiling_table) + { + if (ent.indent == 0) + { + accounted += ent.count; + } + + print_indent(); + for (size_t i = 0; i < ent.indent; ++i) + { + printf(" "); + } + printf("* Number of constraints in [%s]: %zu\n", ent.annotation.c_str(), ent.count); + } + + constraint_profiling_table.clear(); + constraint_profiling_indent = 0; + + return accounted; +} + +} diff --git a/privacy/zsl/zsl/gadgetlib1/constraint_profiling.d b/privacy/zsl/zsl/gadgetlib1/constraint_profiling.d new file mode 100644 index 0000000..c74565c --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/constraint_profiling.d @@ -0,0 +1,3 @@ +src/gadgetlib1/constraint_profiling.o: \ + src/gadgetlib1/constraint_profiling.cpp \ + src/gadgetlib1/constraint_profiling.hpp src/common/profiling.hpp diff --git a/privacy/zsl/zsl/gadgetlib1/constraint_profiling.hpp b/privacy/zsl/zsl/gadgetlib1/constraint_profiling.hpp new file mode 100644 index 0000000..df8a55d --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/constraint_profiling.hpp @@ -0,0 +1,42 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for profiling constraints. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef CONSTRAINT_PROFILING_HPP_ +#define CONSTRAINT_PROFILING_HPP_ + +#include +#include +#include +#include + +namespace libsnark { + +extern size_t constraint_profiling_indent; + +struct constraint_profiling_entry { + size_t indent; + std::string annotation; + size_t count; +}; + +extern std::vector constraint_profiling_table; + +#define PROFILE_CONSTRAINTS(pb, annotation) \ + for (size_t _num_constraints_before = pb.num_constraints(), _iter = (++constraint_profiling_indent, 0), _cp_pos = constraint_profiling_table.size(); \ + _iter == 0; \ + constraint_profiling_table.insert(constraint_profiling_table.begin() + _cp_pos, constraint_profiling_entry{--constraint_profiling_indent, annotation, pb.num_constraints() - _num_constraints_before}), \ + _iter = 1) + +size_t PRINT_CONSTRAINT_PROFILING(); // returns # of top level constraints + +} // libsnark + +#endif // CONSTRAINT_PROFILING_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/examples/simple_example.hpp b/privacy/zsl/zsl/gadgetlib1/examples/simple_example.hpp new file mode 100644 index 0000000..e2a4774 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/examples/simple_example.hpp @@ -0,0 +1,23 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SIMPLE_EXAMPLE_HPP_ +#define SIMPLE_EXAMPLE_HPP_ + +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" + +namespace libsnark { + +template +r1cs_example gen_r1cs_example_from_protoboard(const size_t num_constraints, + const size_t num_inputs); + +} // libsnark + +#include "gadgetlib1/examples/simple_example.tcc" + +#endif // SIMPLE_EXAMPLE_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/examples/simple_example.tcc b/privacy/zsl/zsl/gadgetlib1/examples/simple_example.tcc new file mode 100644 index 0000000..c7418f5 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/examples/simple_example.tcc @@ -0,0 +1,48 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SIMPLE_EXAMPLE_TCC_ +#define SIMPLE_EXAMPLE_TCC_ + +#include "gadgetlib1/gadgets/basic_gadgets.hpp" + +namespace libsnark { + +/* NOTE: all examples here actually generate one constraint less to account for soundness constraint in QAP */ + +template +r1cs_example gen_r1cs_example_from_protoboard(const size_t num_constraints) +{ + const size_t new_num_constraints = num_constraints - 1; + + /* construct dummy example: inner products of two vectors */ + protoboard pb; + pb_variable_array A; + pb_variable_array B; + pb_variable res; + + // the variables on the protoboard are (ONE (constant 1 term), res, A[0], ..., A[num_constraints-1], B[0], ..., B[num_constraints-1]) + res.allocate(pb, "res"); + A.allocate(pb, new_num_constraints, "A"); + B.allocate(pb, new_num_constraints, "B"); + + inner_product_gadget compute_inner_product(pb, A, B, res, "compute_inner_product"); + compute_inner_product.generate_r1cs_constraints(); + + /* fill in random example */ + for (size_t i = 0; i < new_num_constraints; ++i) + { + pb.val(A[i]) = FieldT::random_element(); + pb.val(B[i]) = FieldT::random_element(); + } + + compute_inner_product.generate_r1cs_witness(); + return r1cs_example(pb.get_constraint_system(), pb.primary_input(), pb.auxiliary_input()); +} + +} // libsnark +#endif // R1CS_EXAMPLES_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadget.hpp b/privacy/zsl/zsl/gadgetlib1/gadget.hpp new file mode 100644 index 0000000..dbeaa9d --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadget.hpp @@ -0,0 +1,27 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef GADGET_HPP_ +#define GADGET_HPP_ + +#include "gadgetlib1/protoboard.hpp" + +namespace libsnark { + +template +class gadget { +protected: + protoboard &pb; + const std::string annotation_prefix; +public: + gadget(protoboard &pb, const std::string &annotation_prefix=""); +}; + +} // libsnark +#include "gadgetlib1/gadget.tcc" + +#endif // GADGET_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadget.tcc b/privacy/zsl/zsl/gadgetlib1/gadget.tcc new file mode 100644 index 0000000..120229b --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadget.tcc @@ -0,0 +1,23 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef GADGET_TCC_ +#define GADGET_TCC_ + +namespace libsnark { + +template +gadget::gadget(protoboard &pb, const std::string &annotation_prefix) : + pb(pb), annotation_prefix(annotation_prefix) +{ +#ifdef DEBUG + assert(annotation_prefix != ""); +#endif +} + +} // libsnark +#endif // GADGET_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/basic_gadgets.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/basic_gadgets.hpp new file mode 100644 index 0000000..08e596b --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/basic_gadgets.hpp @@ -0,0 +1,351 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BASIC_GADGETS_HPP_ +#define BASIC_GADGETS_HPP_ + +#include +#include + +#include "gadgetlib1/gadget.hpp" + +namespace libsnark { + +/* forces lc to take value 0 or 1 by adding constraint lc * (1-lc) = 0 */ +template +void generate_boolean_r1cs_constraint(protoboard &pb, const pb_linear_combination &lc, const std::string &annotation_prefix=""); + +template +void generate_r1cs_equals_const_constraint(protoboard &pb, const pb_linear_combination &lc, const FieldT& c, const std::string &annotation_prefix=""); + +template +class packing_gadget : public gadget { +private: + /* no internal variables */ +public: + const pb_linear_combination_array bits; + const pb_linear_combination packed; + + packing_gadget(protoboard &pb, + const pb_linear_combination_array &bits, + const pb_linear_combination &packed, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix), bits(bits), packed(packed) {} + + void generate_r1cs_constraints(const bool enforce_bitness); + /* adds constraint result = \sum bits[i] * 2^i */ + + void generate_r1cs_witness_from_packed(); + void generate_r1cs_witness_from_bits(); +}; + +template +class multipacking_gadget : public gadget { +private: + std::vector > packers; +public: + const pb_linear_combination_array bits; + const pb_linear_combination_array packed_vars; + + const size_t chunk_size; + const size_t num_chunks; + // const size_t last_chunk_size; + + multipacking_gadget(protoboard &pb, + const pb_linear_combination_array &bits, + const pb_linear_combination_array &packed_vars, + const size_t chunk_size, + const std::string &annotation_prefix=""); + void generate_r1cs_constraints(const bool enforce_bitness); + void generate_r1cs_witness_from_packed(); + void generate_r1cs_witness_from_bits(); +}; + +template +class field_vector_copy_gadget : public gadget { +public: + const pb_variable_array source; + const pb_variable_array target; + const pb_linear_combination do_copy; + + field_vector_copy_gadget(protoboard &pb, + const pb_variable_array &source, + const pb_variable_array &target, + const pb_linear_combination &do_copy, + const std::string &annotation_prefix=""); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +class bit_vector_copy_gadget : public gadget { +public: + const pb_variable_array source_bits; + const pb_variable_array target_bits; + const pb_linear_combination do_copy; + + pb_variable_array packed_source; + pb_variable_array packed_target; + + std::shared_ptr > pack_source; + std::shared_ptr > pack_target; + std::shared_ptr > copier; + + const size_t chunk_size; + const size_t num_chunks; + + bit_vector_copy_gadget(protoboard &pb, + const pb_variable_array &source_bits, + const pb_variable_array &target_bits, + const pb_linear_combination &do_copy, + const size_t chunk_size, + const std::string &annotation_prefix=""); + void generate_r1cs_constraints(const bool enforce_source_bitness, const bool enforce_target_bitness); + void generate_r1cs_witness(); +}; + +template +class dual_variable_gadget : public gadget { +private: + std::shared_ptr > consistency_check; +public: + pb_variable packed; + pb_variable_array bits; + + dual_variable_gadget(protoboard &pb, + const size_t width, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix) + { + packed.allocate(pb, FMT(this->annotation_prefix, " packed")); + bits.allocate(pb, width, FMT(this->annotation_prefix, " bits")); + consistency_check.reset(new packing_gadget(pb, + bits, + packed, + FMT(this->annotation_prefix, " consistency_check"))); + } + + dual_variable_gadget(protoboard &pb, + const pb_variable_array &bits, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix), bits(bits) + { + packed.allocate(pb, FMT(this->annotation_prefix, " packed")); + consistency_check.reset(new packing_gadget(pb, + bits, + packed, + FMT(this->annotation_prefix, " consistency_check"))); + } + + dual_variable_gadget(protoboard &pb, + const pb_variable &packed, + const size_t width, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix), packed(packed) + { + bits.allocate(pb, width, FMT(this->annotation_prefix, " bits")); + consistency_check.reset(new packing_gadget(pb, + bits, + packed, + FMT(this->annotation_prefix, " consistency_check"))); + } + + void generate_r1cs_constraints(const bool enforce_bitness); + void generate_r1cs_witness_from_packed(); + void generate_r1cs_witness_from_bits(); +}; + +/* + the gadgets below are Fp specific: + I * X = R + (1-R) * X = 0 + + if X = 0 then R = 0 + if X != 0 then R = 1 and I = X^{-1} +*/ + +template +class disjunction_gadget : public gadget { +private: + pb_variable inv; +public: + const pb_variable_array inputs; + const pb_variable output; + + disjunction_gadget(protoboard& pb, + const pb_variable_array &inputs, + const pb_variable &output, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix), inputs(inputs), output(output) + { + assert(inputs.size() >= 1); + inv.allocate(pb, FMT(this->annotation_prefix, " inv")); + } + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_disjunction_gadget(const size_t n); + +template +class conjunction_gadget : public gadget { +private: + pb_variable inv; +public: + const pb_variable_array inputs; + const pb_variable output; + + conjunction_gadget(protoboard& pb, + const pb_variable_array &inputs, + const pb_variable &output, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix), inputs(inputs), output(output) + { + assert(inputs.size() >= 1); + inv.allocate(pb, FMT(this->annotation_prefix, " inv")); + } + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_conjunction_gadget(const size_t n); + +template +class comparison_gadget : public gadget { +private: + pb_variable_array alpha; + pb_variable alpha_packed; + std::shared_ptr > pack_alpha; + + std::shared_ptr > all_zeros_test; + pb_variable not_all_zeros; +public: + const size_t n; + const pb_linear_combination A; + const pb_linear_combination B; + const pb_variable less; + const pb_variable less_or_eq; + + comparison_gadget(protoboard& pb, + const size_t n, + const pb_linear_combination &A, + const pb_linear_combination &B, + const pb_variable &less, + const pb_variable &less_or_eq, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix), n(n), A(A), B(B), less(less), less_or_eq(less_or_eq) + { + alpha.allocate(pb, n, FMT(this->annotation_prefix, " alpha")); + alpha.emplace_back(less_or_eq); // alpha[n] is less_or_eq + + alpha_packed.allocate(pb, FMT(this->annotation_prefix, " alpha_packed")); + not_all_zeros.allocate(pb, FMT(this->annotation_prefix, " not_all_zeros")); + + pack_alpha.reset(new packing_gadget(pb, alpha, alpha_packed, + FMT(this->annotation_prefix, " pack_alpha"))); + + all_zeros_test.reset(new disjunction_gadget(pb, + pb_variable_array(alpha.begin(), alpha.begin() + n), + not_all_zeros, + FMT(this->annotation_prefix, " all_zeros_test"))); + }; + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_comparison_gadget(const size_t n); + +template +class inner_product_gadget : public gadget { +private: + /* S_i = \sum_{k=0}^{i+1} A[i] * B[i] */ + pb_variable_array S; +public: + const pb_linear_combination_array A; + const pb_linear_combination_array B; + const pb_variable result; + + inner_product_gadget(protoboard& pb, + const pb_linear_combination_array &A, + const pb_linear_combination_array &B, + const pb_variable &result, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix), A(A), B(B), result(result) + { + assert(A.size() >= 1); + assert(A.size() == B.size()); + + S.allocate(pb, A.size()-1, FMT(this->annotation_prefix, " S")); + } + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_inner_product_gadget(const size_t n); + +template +class loose_multiplexing_gadget : public gadget { +/* + this implements loose multiplexer: + index not in bounds -> success_flag = 0 + index in bounds && success_flag = 1 -> result is correct + however if index is in bounds we can also set success_flag to 0 (and then result will be forced to be 0) +*/ +public: + pb_variable_array alpha; +private: + std::shared_ptr > compute_result; +public: + const pb_linear_combination_array arr; + const pb_variable index; + const pb_variable result; + const pb_variable success_flag; + + loose_multiplexing_gadget(protoboard& pb, + const pb_linear_combination_array &arr, + const pb_variable &index, + const pb_variable &result, + const pb_variable &success_flag, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix), arr(arr), index(index), result(result), success_flag(success_flag) + { + alpha.allocate(pb, arr.size(), FMT(this->annotation_prefix, " alpha")); + compute_result.reset(new inner_product_gadget(pb, alpha, arr, result, FMT(this->annotation_prefix, " compute_result"))); + }; + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_loose_multiplexing_gadget(const size_t n); + +template +void create_linear_combination_constraints(protoboard &pb, + const std::vector &base, + const std::vector > &v, + const VarT &target, + const std::string &annotation_prefix); + +template +void create_linear_combination_witness(protoboard &pb, + const std::vector &base, + const std::vector > &v, + const VarT &target); + +} // libsnark +#include "gadgetlib1/gadgets/basic_gadgets.tcc" + +#endif // BASIC_GADGETS_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/basic_gadgets.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/basic_gadgets.tcc new file mode 100644 index 0000000..45fd7aa --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/basic_gadgets.tcc @@ -0,0 +1,705 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BASIC_GADGETS_TCC_ +#define BASIC_GADGETS_TCC_ + +#include "common/profiling.hpp" +#include "common/utils.hpp" + +namespace libsnark { + +template +void generate_boolean_r1cs_constraint(protoboard &pb, const pb_linear_combination &lc, const std::string &annotation_prefix) +/* forces lc to take value 0 or 1 by adding constraint lc * (1-lc) = 0 */ +{ + pb.add_r1cs_constraint(r1cs_constraint(lc, 1-lc, 0), + FMT(annotation_prefix, " boolean_r1cs_constraint")); +} + +template +void generate_r1cs_equals_const_constraint(protoboard &pb, const pb_linear_combination &lc, const FieldT& c, const std::string &annotation_prefix) +{ + pb.add_r1cs_constraint(r1cs_constraint(1, lc, c), + FMT(annotation_prefix, " constness_constraint")); +} + +template +void packing_gadget::generate_r1cs_constraints(const bool enforce_bitness) +/* adds constraint result = \sum bits[i] * 2^i */ +{ + this->pb.add_r1cs_constraint(r1cs_constraint(1, pb_packing_sum(bits), packed), FMT(this->annotation_prefix, " packing_constraint")); + + if (enforce_bitness) + { + for (size_t i = 0; i < bits.size(); ++i) + { + generate_boolean_r1cs_constraint(this->pb, bits[i], FMT(this->annotation_prefix, " bitness_%zu", i)); + } + } +} + +template +void packing_gadget::generate_r1cs_witness_from_packed() +{ + packed.evaluate(this->pb); + assert(this->pb.lc_val(packed).as_bigint().num_bits() <= bits.size()); // `bits` is large enough to represent this packed value + bits.fill_with_bits_of_field_element(this->pb, this->pb.lc_val(packed)); +} + +template +void packing_gadget::generate_r1cs_witness_from_bits() +{ + bits.evaluate(this->pb); + this->pb.lc_val(packed) = bits.get_field_element_from_bits(this->pb); +} + +template +multipacking_gadget::multipacking_gadget(protoboard &pb, + const pb_linear_combination_array &bits, + const pb_linear_combination_array &packed_vars, + const size_t chunk_size, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), bits(bits), packed_vars(packed_vars), + chunk_size(chunk_size), + num_chunks(div_ceil(bits.size(), chunk_size)) + // last_chunk_size(bits.size() - (num_chunks-1) * chunk_size) +{ + assert(packed_vars.size() == num_chunks); + for (size_t i = 0; i < num_chunks; ++i) + { + packers.emplace_back(packing_gadget(this->pb, pb_linear_combination_array(bits.begin() + i * chunk_size, + bits.begin() + std::min((i+1) * chunk_size, bits.size())), + packed_vars[i], FMT(this->annotation_prefix, " packers_%zu", i))); + } +} + +template +void multipacking_gadget::generate_r1cs_constraints(const bool enforce_bitness) +{ + for (size_t i = 0; i < num_chunks; ++i) + { + packers[i].generate_r1cs_constraints(enforce_bitness); + } +} + +template +void multipacking_gadget::generate_r1cs_witness_from_packed() +{ + for (size_t i = 0; i < num_chunks; ++i) + { + packers[i].generate_r1cs_witness_from_packed(); + } +} + +template +void multipacking_gadget::generate_r1cs_witness_from_bits() +{ + for (size_t i = 0; i < num_chunks; ++i) + { + packers[i].generate_r1cs_witness_from_bits(); + } +} + +template +size_t multipacking_num_chunks(const size_t num_bits) +{ + return div_ceil(num_bits, FieldT::capacity()); +} + +template +field_vector_copy_gadget::field_vector_copy_gadget(protoboard &pb, + const pb_variable_array &source, + const pb_variable_array &target, + const pb_linear_combination &do_copy, + const std::string &annotation_prefix) : +gadget(pb, annotation_prefix), source(source), target(target), do_copy(do_copy) +{ + assert(source.size() == target.size()); +} + +template +void field_vector_copy_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < source.size(); ++i) + { + this->pb.add_r1cs_constraint(r1cs_constraint(do_copy, source[i] - target[i], 0), + FMT(this->annotation_prefix, " copying_check_%zu", i)); + } +} + +template +void field_vector_copy_gadget::generate_r1cs_witness() +{ + do_copy.evaluate(this->pb); + assert(this->pb.lc_val(do_copy) == FieldT::one() || this->pb.lc_val(do_copy) == FieldT::zero()); + if (this->pb.lc_val(do_copy) != FieldT::zero()) + { + for (size_t i = 0; i < source.size(); ++i) + { + this->pb.val(target[i]) = this->pb.val(source[i]); + } + } +} + +template +bit_vector_copy_gadget::bit_vector_copy_gadget(protoboard &pb, + const pb_variable_array &source_bits, + const pb_variable_array &target_bits, + const pb_linear_combination &do_copy, + const size_t chunk_size, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), source_bits(source_bits), target_bits(target_bits), do_copy(do_copy), + chunk_size(chunk_size), num_chunks(div_ceil(source_bits.size(), chunk_size)) +{ + assert(source_bits.size() == target_bits.size()); + + packed_source.allocate(pb, num_chunks, FMT(annotation_prefix, " packed_source")); + pack_source.reset(new multipacking_gadget(pb, source_bits, packed_source, chunk_size, FMT(annotation_prefix, " pack_source"))); + + packed_target.allocate(pb, num_chunks, FMT(annotation_prefix, " packed_target")); + pack_target.reset(new multipacking_gadget(pb, target_bits, packed_target, chunk_size, FMT(annotation_prefix, " pack_target"))); + + copier.reset(new field_vector_copy_gadget(pb, packed_source, packed_target, do_copy, FMT(annotation_prefix, " copier"))); +} + +template +void bit_vector_copy_gadget::generate_r1cs_constraints(const bool enforce_source_bitness, const bool enforce_target_bitness) +{ + pack_source->generate_r1cs_constraints(enforce_source_bitness); + pack_target->generate_r1cs_constraints(enforce_target_bitness); + + copier->generate_r1cs_constraints(); +} + +template +void bit_vector_copy_gadget::generate_r1cs_witness() +{ + do_copy.evaluate(this->pb); + assert(this->pb.lc_val(do_copy) == FieldT::zero() || this->pb.lc_val(do_copy) == FieldT::one()); + if (this->pb.lc_val(do_copy) == FieldT::one()) + { + for (size_t i = 0; i < source_bits.size(); ++i) + { + this->pb.val(target_bits[i]) = this->pb.val(source_bits[i]); + } + } + + pack_source->generate_r1cs_witness_from_bits(); + pack_target->generate_r1cs_witness_from_bits(); +} + +template +void dual_variable_gadget::generate_r1cs_constraints(const bool enforce_bitness) +{ + consistency_check->generate_r1cs_constraints(enforce_bitness); +} + +template +void dual_variable_gadget::generate_r1cs_witness_from_packed() +{ + consistency_check->generate_r1cs_witness_from_packed(); +} + +template +void dual_variable_gadget::generate_r1cs_witness_from_bits() +{ + consistency_check->generate_r1cs_witness_from_bits(); +} + +template +void disjunction_gadget::generate_r1cs_constraints() +{ + /* inv * sum = output */ + linear_combination a1, b1, c1; + a1.add_term(inv); + for (size_t i = 0; i < inputs.size(); ++i) + { + b1.add_term(inputs[i]); + } + c1.add_term(output); + + this->pb.add_r1cs_constraint(r1cs_constraint(a1, b1, c1), FMT(this->annotation_prefix, " inv*sum=output")); + + /* (1-output) * sum = 0 */ + linear_combination a2, b2, c2; + a2.add_term(ONE); + a2.add_term(output, -1); + for (size_t i = 0; i < inputs.size(); ++i) + { + b2.add_term(inputs[i]); + } + c2.add_term(ONE, 0); + + this->pb.add_r1cs_constraint(r1cs_constraint(a2, b2, c2), FMT(this->annotation_prefix, " (1-output)*sum=0")); +} + +template +void disjunction_gadget::generate_r1cs_witness() +{ + FieldT sum = FieldT::zero(); + + for (size_t i = 0; i < inputs.size(); ++i) + { + sum += this->pb.val(inputs[i]); + } + + if (sum.is_zero()) + { + this->pb.val(inv) = FieldT::zero(); + this->pb.val(output) = FieldT::zero(); + } + else + { + this->pb.val(inv) = sum.inverse(); + this->pb.val(output) = FieldT::one(); + } +} + +template +void test_disjunction_gadget(const size_t n) +{ + printf("testing disjunction_gadget on all %zu bit strings\n", n); + + protoboard pb; + pb_variable_array inputs; + inputs.allocate(pb, n, "inputs"); + + pb_variable output; + output.allocate(pb, "output"); + + disjunction_gadget d(pb, inputs, output, "d"); + d.generate_r1cs_constraints(); + + for (size_t w = 0; w < 1ul< +void conjunction_gadget::generate_r1cs_constraints() +{ + /* inv * (n-sum) = 1-output */ + linear_combination a1, b1, c1; + a1.add_term(inv); + b1.add_term(ONE, inputs.size()); + for (size_t i = 0; i < inputs.size(); ++i) + { + b1.add_term(inputs[i], -1); + } + c1.add_term(ONE); + c1.add_term(output, -1); + + this->pb.add_r1cs_constraint(r1cs_constraint(a1, b1, c1), FMT(this->annotation_prefix, " inv*(n-sum)=(1-output)")); + + /* output * (n-sum) = 0 */ + linear_combination a2, b2, c2; + a2.add_term(output); + b2.add_term(ONE, inputs.size()); + for (size_t i = 0; i < inputs.size(); ++i) + { + b2.add_term(inputs[i], -1); + } + c2.add_term(ONE, 0); + + this->pb.add_r1cs_constraint(r1cs_constraint(a2, b2, c2), FMT(this->annotation_prefix, " output*(n-sum)=0")); +} + +template +void conjunction_gadget::generate_r1cs_witness() +{ + FieldT sum = FieldT(inputs.size()); + + for (size_t i = 0; i < inputs.size(); ++i) + { + sum -= this->pb.val(inputs[i]); + } + + if (sum.is_zero()) + { + this->pb.val(inv) = FieldT::zero(); + this->pb.val(output) = FieldT::one(); + } + else + { + this->pb.val(inv) = sum.inverse(); + this->pb.val(output) = FieldT::zero(); + } +} + +template +void test_conjunction_gadget(const size_t n) +{ + printf("testing conjunction_gadget on all %zu bit strings\n", n); + + protoboard pb; + pb_variable_array inputs; + inputs.allocate(pb, n, "inputs"); + + pb_variable output; + output.allocate(pb, "output"); + + conjunction_gadget c(pb, inputs, output, "c"); + c.generate_r1cs_constraints(); + + for (size_t w = 0; w < 1ul< +void comparison_gadget::generate_r1cs_constraints() +{ + /* + packed(alpha) = 2^n + B - A + + not_all_zeros = \bigvee_{i=0}^{n-1} alpha_i + + if B - A > 0, then 2^n + B - A > 2^n, + so alpha_n = 1 and not_all_zeros = 1 + if B - A = 0, then 2^n + B - A = 2^n, + so alpha_n = 1 and not_all_zeros = 0 + if B - A < 0, then 2^n + B - A \in {0, 1, \ldots, 2^n-1}, + so alpha_n = 0 + + therefore alpha_n = less_or_eq and alpha_n * not_all_zeros = less + */ + + /* not_all_zeros to be Boolean, alpha_i are Boolean by packing gadget */ + generate_boolean_r1cs_constraint(this->pb, not_all_zeros, + FMT(this->annotation_prefix, " not_all_zeros")); + + /* constraints for packed(alpha) = 2^n + B - A */ + pack_alpha->generate_r1cs_constraints(true); + this->pb.add_r1cs_constraint(r1cs_constraint(1, (FieldT(2)^n) + B - A, alpha_packed), FMT(this->annotation_prefix, " main_constraint")); + + /* compute result */ + all_zeros_test->generate_r1cs_constraints(); + this->pb.add_r1cs_constraint(r1cs_constraint(less_or_eq, not_all_zeros, less), + FMT(this->annotation_prefix, " less")); +} + +template +void comparison_gadget::generate_r1cs_witness() +{ + A.evaluate(this->pb); + B.evaluate(this->pb); + + /* unpack 2^n + B - A into alpha_packed */ + this->pb.val(alpha_packed) = (FieldT(2)^n) + this->pb.lc_val(B) - this->pb.lc_val(A); + pack_alpha->generate_r1cs_witness_from_packed(); + + /* compute result */ + all_zeros_test->generate_r1cs_witness(); + this->pb.val(less) = this->pb.val(less_or_eq) * this->pb.val(not_all_zeros); +} + +template +void test_comparison_gadget(const size_t n) +{ + printf("testing comparison_gadget on all %zu bit inputs\n", n); + + protoboard pb; + + pb_variable A, B, less, less_or_eq; + A.allocate(pb, "A"); + B.allocate(pb, "B"); + less.allocate(pb, "less"); + less_or_eq.allocate(pb, "less_or_eq"); + + comparison_gadget cmp(pb, n, A, B, less, less_or_eq, "cmp"); + cmp.generate_r1cs_constraints(); + + for (size_t a = 0; a < 1ul< +void inner_product_gadget::generate_r1cs_constraints() +{ + /* + S_i = \sum_{k=0}^{i+1} A[i] * B[i] + S[0] = A[0] * B[0] + S[i+1] - S[i] = A[i] * B[i] + */ + for (size_t i = 0; i < A.size(); ++i) + { + this->pb.add_r1cs_constraint( + r1cs_constraint(A[i], B[i], + (i == A.size()-1 ? result : S[i]) + (i == 0 ? 0 * ONE : -S[i-1])), + FMT(this->annotation_prefix, " S_%zu", i)); + } +} + +template +void inner_product_gadget::generate_r1cs_witness() +{ + FieldT total = FieldT::zero(); + for (size_t i = 0; i < A.size(); ++i) + { + A[i].evaluate(this->pb); + B[i].evaluate(this->pb); + + total += this->pb.lc_val(A[i]) * this->pb.lc_val(B[i]); + this->pb.val(i == A.size()-1 ? result : S[i]) = total; + } +} + +template +void test_inner_product_gadget(const size_t n) +{ + printf("testing inner_product_gadget on all %zu bit strings\n", n); + + protoboard pb; + pb_variable_array A; + A.allocate(pb, n, "A"); + pb_variable_array B; + B.allocate(pb, n, "B"); + + pb_variable result; + result.allocate(pb, "result"); + + inner_product_gadget g(pb, A, B, result, "g"); + g.generate_r1cs_constraints(); + + for (size_t i = 0; i < 1ul< +void loose_multiplexing_gadget::generate_r1cs_constraints() +{ + /* \alpha_i (index - i) = 0 */ + for (size_t i = 0; i < arr.size(); ++i) + { + this->pb.add_r1cs_constraint( + r1cs_constraint(alpha[i], index - i, 0), + FMT(this->annotation_prefix, " alpha_%zu", i)); + } + + /* 1 * (\sum \alpha_i) = success_flag */ + linear_combination a, b, c; + a.add_term(ONE); + for (size_t i = 0; i < arr.size(); ++i) + { + b.add_term(alpha[i]); + } + c.add_term(success_flag); + this->pb.add_r1cs_constraint(r1cs_constraint(a, b, c), FMT(this->annotation_prefix, " main_constraint")); + + /* now success_flag is constrained to either 0 (if index is out of + range) or \alpha_i. constrain it and \alpha_i to zero */ + generate_boolean_r1cs_constraint(this->pb, success_flag, FMT(this->annotation_prefix, " success_flag")); + + /* compute result */ + compute_result->generate_r1cs_constraints(); +} + +template +void loose_multiplexing_gadget::generate_r1cs_witness() +{ + /* assumes that idx can be fit in ulong; true for our purposes for now */ + const bigint valint = this->pb.val(index).as_bigint(); + unsigned long idx = valint.as_ulong(); + const bigint arrsize(arr.size()); + + if (idx >= arr.size() || mpn_cmp(valint.data, arrsize.data, FieldT::num_limbs) >= 0) + { + for (size_t i = 0; i < arr.size(); ++i) + { + this->pb.val(alpha[i]) = FieldT::zero(); + } + + this->pb.val(success_flag) = FieldT::zero(); + } + else + { + for (size_t i = 0; i < arr.size(); ++i) + { + this->pb.val(alpha[i]) = (i == idx ? FieldT::one() : FieldT::zero()); + } + + this->pb.val(success_flag) = FieldT::one(); + } + + compute_result->generate_r1cs_witness(); +} + +template +void test_loose_multiplexing_gadget(const size_t n) +{ + printf("testing loose_multiplexing_gadget on 2**%zu pb_variable array inputs\n", n); + protoboard pb; + + pb_variable_array arr; + arr.allocate(pb, 1ul< index, result, success_flag; + index.allocate(pb, "index"); + result.allocate(pb, "result"); + success_flag.allocate(pb, "success_flag"); + + loose_multiplexing_gadget g(pb, arr, index, result, success_flag, "g"); + g.generate_r1cs_constraints(); + + for (size_t i = 0; i < 1ul< +void create_linear_combination_constraints(protoboard &pb, + const std::vector &base, + const std::vector > &v, + const VarT &target, + const std::string &annotation_prefix) +{ + for (size_t i = 0; i < base.size(); ++i) + { + linear_combination a, b, c; + + a.add_term(ONE); + b.add_term(ONE, base[i]); + + for (auto &p : v) + { + b.add_term(p.first.all_vars[i], p.second); + } + + c.add_term(target.all_vars[i]); + + pb.add_r1cs_constraint(r1cs_constraint(a, b, c), FMT(annotation_prefix, " linear_combination_%zu", i)); + } +} + +template +void create_linear_combination_witness(protoboard &pb, + const std::vector &base, + const std::vector > &v, + const VarT &target) +{ + for (size_t i = 0; i < base.size(); ++i) + { + pb.val(target.all_vars[i]) = base[i]; + + for (auto &p : v) + { + pb.val(target.all_vars[i]) += p.second * pb.val(p.first.all_vars[i]); + } + } +} + +} // libsnark +#endif // BASIC_GADGETS_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/fooram/components/bar_gadget.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/fooram/components/bar_gadget.hpp new file mode 100644 index 0000000..0e28032 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/fooram/components/bar_gadget.hpp @@ -0,0 +1,64 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for an auxiliarry gadget for the FOORAM CPU. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BAR_GADGET_HPP_ +#define BAR_GADGET_HPP_ + +#include "gadgetlib1/gadget.hpp" +#include "gadgetlib1/gadgets/basic_gadgets.hpp" + +namespace libsnark { + +/** + * The bar gadget checks linear combination + * Z = aX + bY (mod 2^w) + * for a, b - const, X, Y - vectors of w bits, + * where w is implicitly inferred, Z - a packed variable. + * + * This gadget is used four times in fooram: + * - PC' = PC + 1 + * - load_addr = 2 * x + PC' + * - store_addr = x + PC + */ +template +class bar_gadget : public gadget { +public: + pb_linear_combination_array X; + FieldT a; + pb_linear_combination_array Y; + FieldT b; + pb_linear_combination Z_packed; + pb_variable_array Z_bits; + + pb_variable result; + pb_variable_array overflow; + pb_variable_array unpacked_result; + + std::shared_ptr > unpack_result; + std::shared_ptr > pack_Z; + + size_t width; + bar_gadget(protoboard &pb, + const pb_linear_combination_array &X, + const FieldT &a, + const pb_linear_combination_array &Y, + const FieldT &b, + const pb_linear_combination &Z_packed, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/cpu_checkers/fooram/components/bar_gadget.tcc" + +#endif // BAR_GADGET_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/fooram/components/bar_gadget.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/fooram/components/bar_gadget.tcc new file mode 100644 index 0000000..f25d1df --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/fooram/components/bar_gadget.tcc @@ -0,0 +1,68 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for an auxiliarry gadget for the FOORAM CPU. + + See bar_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BAR_GADGET_TCC_ +#define BAR_GADGET_TCC_ + +namespace libsnark { + +template +bar_gadget::bar_gadget(protoboard &pb, + const pb_linear_combination_array &X, + const FieldT &a, + const pb_linear_combination_array &Y, + const FieldT &b, + const pb_linear_combination &Z_packed, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + X(X), + a(a), + Y(Y), + b(b), + Z_packed(Z_packed) +{ + assert(X.size() == Y.size()); + width = X.size(); + + result.allocate(pb, FMT(annotation_prefix, " result")); + Z_bits.allocate(pb, width, FMT(annotation_prefix, " Z_bits")); + overflow.allocate(pb, 2*width, FMT(annotation_prefix, " overflow")); + + unpacked_result.insert(unpacked_result.end(), Z_bits.begin(), Z_bits.end()); + unpacked_result.insert(unpacked_result.end(), overflow.begin(), overflow.end()); + + unpack_result.reset(new packing_gadget(pb, unpacked_result, result, FMT(annotation_prefix, " unpack_result"))); + pack_Z.reset(new packing_gadget(pb, Z_bits, Z_packed, FMT(annotation_prefix, " pack_Z"))); +} + +template +void bar_gadget::generate_r1cs_constraints() +{ + unpack_result->generate_r1cs_constraints(true); + pack_Z->generate_r1cs_constraints(false); + + this->pb.add_r1cs_constraint(r1cs_constraint(1, a * pb_packing_sum(X) + b * pb_packing_sum(Y), result), FMT(this->annotation_prefix, " compute_result")); +} + +template +void bar_gadget::generate_r1cs_witness() +{ + this->pb.val(result) = X.get_field_element_from_bits(this->pb) * a + Y.get_field_element_from_bits(this->pb) * b; + unpack_result->generate_r1cs_witness_from_packed(); + + pack_Z->generate_r1cs_witness_from_bits(); +} + +} // libsnark + +#endif // BAR_GADGET_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/fooram/components/fooram_protoboard.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/fooram/components/fooram_protoboard.hpp new file mode 100644 index 0000000..d8c3ca8 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/fooram/components/fooram_protoboard.hpp @@ -0,0 +1,40 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a protoboard for the FOORAM CPU. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FOORAM_PROTOBOARD_HPP_ +#define FOORAM_PROTOBOARD_HPP_ + +#include "gadgetlib1/gadget.hpp" +#include "relations/ram_computations/rams/fooram/fooram_aux.hpp" + +namespace libsnark { + +template +class fooram_protoboard : public protoboard { +public: + const fooram_architecture_params ap; + + fooram_protoboard(const fooram_architecture_params &ap); +}; + +template +class fooram_gadget : public gadget { +protected: + fooram_protoboard &pb; +public: + fooram_gadget(fooram_protoboard &pb, const std::string &annotation_prefix=""); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/cpu_checkers/fooram/components/fooram_protoboard.tcc" + +#endif // FOORAM_PROTOBOARD_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/fooram/components/fooram_protoboard.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/fooram/components/fooram_protoboard.tcc new file mode 100644 index 0000000..035cfab --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/fooram/components/fooram_protoboard.tcc @@ -0,0 +1,33 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a protoboard for the FOORAM CPU. + + See fooram_protoboard.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FOORAM_PROTOBOARD_TCC_ +#define FOORAM_PROTOBOARD_TCC_ + +namespace libsnark { + +template +fooram_protoboard::fooram_protoboard(const fooram_architecture_params &ap) : + protoboard(), ap(ap) +{ +} + +template +fooram_gadget::fooram_gadget(fooram_protoboard &pb, const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), pb(pb) +{ +} + +} // libsnark + +#endif // FOORAM_PROTOBOARD_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/fooram/examples/test_fooram.cpp b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/fooram/examples/test_fooram.cpp new file mode 100644 index 0000000..347ba03 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/fooram/examples/test_fooram.cpp @@ -0,0 +1,82 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include "common/default_types/r1cs_ppzksnark_pp.hpp" +#include "common/default_types/r1cs_ppzkpcd_pp.hpp" +#include "common/utils.hpp" +#include "zk_proof_systems/zksnark/ram_zksnark/examples/run_ram_zksnark.hpp" +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/examples/run_ram_ppzksnark.hpp" + +#include "relations/ram_computations/rams/fooram/fooram_params.hpp" + +namespace libsnark { + +class default_fooram_zksnark_pp { +public: + typedef default_r1cs_ppzkpcd_pp PCD_pp; + typedef typename PCD_pp::scalar_field_A FieldT; + typedef ram_fooram machine_pp; + + static void init_public_params() { PCD_pp::init_public_params(); } +}; + +class default_fooram_ppzksnark_pp { +public: + typedef default_r1cs_ppzksnark_pp snark_pp; + typedef Fr FieldT; + typedef ram_fooram machine_pp; + + static void init_public_params() { snark_pp::init_public_params(); } +}; + +} // libsnark + +using namespace libsnark; + +template +void profile_ram_zksnark(const size_t w) +{ + typedef ram_zksnark_machine_pp ramT; + + ram_example example; + example.ap = ram_architecture_params(w); + example.boot_trace_size_bound = 0; + example.time_bound = 10; + const bool test_serialization = true; + const bool bit = run_ram_zksnark(example, test_serialization); + assert(bit); +} + +template +void profile_ram_ppzksnark(const size_t w) +{ + typedef ram_ppzksnark_machine_pp ramT; + + ram_example example; + example.ap = ram_architecture_params(w); + example.boot_trace_size_bound = 0; + example.time_bound = 100; + const bool test_serialization = true; + const bool bit = run_ram_ppzksnark(example, test_serialization); + assert(bit); +} + +int main(int argc, const char* argv[]) +{ + UNUSED(argv); + start_profiling(); + default_fooram_ppzksnark_pp::init_public_params(); + default_fooram_zksnark_pp::init_public_params(); + + if (argc == 1) + { + profile_ram_zksnark(32); + } + else + { + profile_ram_ppzksnark(8); + } +} diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/fooram/fooram_cpu_checker.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/fooram/fooram_cpu_checker.hpp new file mode 100644 index 0000000..d12198f --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/fooram/fooram_cpu_checker.hpp @@ -0,0 +1,107 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the FOORAM CPU checker gadget. + + The gadget checks the correct operation for the CPU of the FOORAM architecture. + + In FOORAM, the only instruction is FOO(x) and its encoding is x. + The instruction FOO(x) has the following semantics: + - if x is odd: reg <- [2*x+(pc+1)] + - if x is even: [pc+x] <- reg+pc + - increment pc by 1 + + Starting from empty memory, FOORAM performs non-trivial pseudo-random computation + that exercises both loads, stores, and instruction fetches. + + E.g. for the first 200 steps on 16 cell machine we get 93 different memory configurations. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FOORAM_CPU_CHECKER_HPP_ +#define FOORAM_CPU_CHECKER_HPP_ + +#include +#include + +#include "common/serialization.hpp" +#include "gadgetlib1/gadget.hpp" +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "gadgetlib1/gadgets/cpu_checkers/fooram/components/fooram_protoboard.hpp" +#include "gadgetlib1/gadgets/cpu_checkers/fooram/components/bar_gadget.hpp" +#include "relations/ram_computations/memory/memory_interface.hpp" + +namespace libsnark { + +template +class fooram_cpu_checker : public fooram_gadget { +public: + pb_variable_array prev_pc_addr; + pb_variable_array prev_pc_val; + pb_variable_array prev_state; + pb_variable_array guess; + pb_variable_array ls_addr; + pb_variable_array ls_prev_val; + pb_variable_array ls_next_val; + pb_variable_array next_state; + pb_variable_array next_pc_addr; + pb_variable next_has_accepted; + + pb_variable zero; + pb_variable packed_next_pc_addr; + pb_linear_combination_array one_as_addr; + std::shared_ptr > pack_next_pc_addr; + + pb_variable packed_load_addr; + pb_variable packed_store_addr; + pb_variable packed_store_val; + + std::shared_ptr > increment_pc; + std::shared_ptr > compute_packed_load_addr; + std::shared_ptr > compute_packed_store_addr; + std::shared_ptr > compute_packed_store_val; + + pb_variable packed_ls_addr; + pb_variable packed_ls_prev_val; + pb_variable packed_ls_next_val; + pb_variable packed_prev_state; + pb_variable packed_next_state; + std::shared_ptr > pack_ls_addr; + std::shared_ptr > pack_ls_prev_val; + std::shared_ptr > pack_ls_next_val; + std::shared_ptr > pack_prev_state; + std::shared_ptr > pack_next_state; + + fooram_cpu_checker(fooram_protoboard &pb, + pb_variable_array &prev_pc_addr, + pb_variable_array &prev_pc_val, + pb_variable_array &prev_state, + pb_variable_array &ls_addr, + pb_variable_array &ls_prev_val, + pb_variable_array &ls_next_val, + pb_variable_array &next_state, + pb_variable_array &next_pc_addr, + pb_variable &next_has_accepted, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + + void generate_r1cs_witness() { assert(0); } + + void generate_r1cs_witness_address(); + + void generate_r1cs_witness_other(fooram_input_tape_iterator &aux_it, + const fooram_input_tape_iterator &aux_end); + + void dump() const; +}; + +} // libsnark + +#include "gadgetlib1/gadgets/cpu_checkers/fooram/fooram_cpu_checker.tcc" + +#endif // FORAM_CPU_CHECKER_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/fooram/fooram_cpu_checker.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/fooram/fooram_cpu_checker.tcc new file mode 100644 index 0000000..0024714 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/fooram/fooram_cpu_checker.tcc @@ -0,0 +1,232 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the FOORAM CPU checker gadget. + + See fooram_cpu_checker.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FOORAM_CPU_CHECKER_TCC_ +#define FOORAM_CPU_CHECKER_TCC_ + +namespace libsnark { + +template +fooram_cpu_checker::fooram_cpu_checker(fooram_protoboard &pb, + pb_variable_array &prev_pc_addr, + pb_variable_array &prev_pc_val, + pb_variable_array &prev_state, + pb_variable_array &ls_addr, + pb_variable_array &ls_prev_val, + pb_variable_array &ls_next_val, + pb_variable_array &next_state, + pb_variable_array &next_pc_addr, + pb_variable &next_has_accepted, + const std::string &annotation_prefix) : + fooram_gadget(pb, annotation_prefix), + prev_pc_addr(prev_pc_addr), + prev_pc_val(prev_pc_val), + prev_state(prev_state), + ls_addr(ls_addr), + ls_prev_val(ls_prev_val), + ls_next_val(ls_next_val), + next_state(next_state), + next_pc_addr(next_pc_addr), + next_has_accepted(next_has_accepted) +{ + /* increment PC */ + packed_next_pc_addr.allocate(pb, FMT(annotation_prefix, " packed_next_pc_addr")); + pack_next_pc_addr.reset(new packing_gadget(pb, next_pc_addr, packed_next_pc_addr, FMT(annotation_prefix, " pack_next_pc_addr"))); + + one_as_addr.resize(next_pc_addr.size()); + one_as_addr[0].assign(this->pb, 1); + for (size_t i = 1; i < next_pc_addr.size(); ++i) + { + one_as_addr[i].assign(this->pb, 0); + } + + /* packed_next_pc_addr = prev_pc_addr + one_as_addr */ + increment_pc.reset(new bar_gadget(pb, prev_pc_addr, FieldT::one(), one_as_addr, FieldT::one(), packed_next_pc_addr, FMT(annotation_prefix, " increment_pc"))); + + /* packed_store_addr = prev_pc_addr + prev_pc_val */ + packed_store_addr.allocate(pb, FMT(annotation_prefix, " packed_store_addr")); + compute_packed_store_addr.reset(new bar_gadget(pb, prev_pc_addr, FieldT::one(), prev_pc_val, FieldT::one(), packed_store_addr, FMT(annotation_prefix, " compute_packed_store_addr"))); + + /* packed_load_addr = 2 * x + next_pc_addr */ + packed_load_addr.allocate(pb, FMT(annotation_prefix, " packed_load_addr")); + compute_packed_load_addr.reset(new bar_gadget(pb, prev_pc_val, FieldT(2), next_pc_addr, FieldT::one(), packed_load_addr, FMT(annotation_prefix, " compute_packed_load_addr"))); + + /* + packed_ls_addr = x0 * packed_load_addr + (1-x0) * packed_store_addr + packed_ls_addr ~ ls_addr + */ + packed_ls_addr.allocate(pb, FMT(annotation_prefix, " packed_ls_addr")); + pack_ls_addr.reset(new packing_gadget(pb, ls_addr, packed_ls_addr, " pack_ls_addr")); + + /* packed_store_val = prev_state_bits + prev_pc_addr */ + packed_store_val.allocate(pb, FMT(annotation_prefix, " packed_store_val")); + compute_packed_store_val.reset(new bar_gadget(pb, prev_state, FieldT::one(), prev_pc_addr, FieldT::one(), packed_store_val, FMT(annotation_prefix, " compute_packed_store_val"))); + + /* + packed_ls_next_val = x0 * packed_ls_prev_val + (1-x0) * packed_store_val + packed_ls_next_val ~ ls_next_val + */ + packed_ls_prev_val.allocate(pb, FMT(annotation_prefix, " packed_ls_prev_val")); + pack_ls_prev_val.reset(new packing_gadget(this->pb, ls_prev_val, packed_ls_prev_val, FMT(annotation_prefix, " pack_ls_prev_val"))); + packed_ls_next_val.allocate(pb, FMT(annotation_prefix, " packed_ls_next_val")); + pack_ls_next_val.reset(new packing_gadget(this->pb, ls_next_val, packed_ls_next_val, FMT(annotation_prefix, " pack_ls_next_val"))); + + /* + packed_next_state = x0 * packed_ls_prev_val + (1-x0) * packed_prev_state + packed_next_state ~ next_state + packed_prev_state ~ prev_state + */ + packed_prev_state.allocate(pb, FMT(annotation_prefix, " packed_prev_state")); + pack_prev_state.reset(new packing_gadget(pb, prev_state, packed_prev_state, " pack_prev_state")); + + packed_next_state.allocate(pb, FMT(annotation_prefix, " packed_next_state")); + pack_next_state.reset(new packing_gadget(pb, next_state, packed_next_state, " pack_next_state")); + + /* next_has_accepted = 1 */ +} + +template +void fooram_cpu_checker::generate_r1cs_constraints() +{ + /* packed_next_pc_addr = prev_pc_addr + one_as_addr */ + pack_next_pc_addr->generate_r1cs_constraints(false); + increment_pc->generate_r1cs_constraints(); + + /* packed_store_addr = prev_pc_addr + prev_pc_val */ + compute_packed_store_addr->generate_r1cs_constraints(); + + /* packed_load_addr = 2 * x + next_pc_addr */ + compute_packed_load_addr->generate_r1cs_constraints(); + + /* + packed_ls_addr = x0 * packed_load_addr + (1-x0) * packed_store_addr + packed_ls_addr - packed_store_addr = x0 * (packed_load_addr - packed_store_addr) + packed_ls_addr ~ ls_addr + */ + pack_ls_addr->generate_r1cs_constraints(false); + this->pb.add_r1cs_constraint(r1cs_constraint(prev_pc_val[0], + packed_load_addr - packed_store_addr, + packed_ls_addr - packed_store_addr), + FMT(this->annotation_prefix, " compute_ls_addr_packed")); + + /* packed_store_val = prev_state_bits + prev_pc_addr */ + compute_packed_store_val->generate_r1cs_constraints(); + + /* + packed_ls_next_val = x0 * packed_ls_prev_val + (1-x0) * packed_store_val + packed_ls_next_val - packed_store_val = x0 * (packed_ls_prev_val - packed_store_val) + packed_ls_next_val ~ ls_next_val + */ + pack_ls_prev_val->generate_r1cs_constraints(false); + pack_ls_next_val->generate_r1cs_constraints(false); + this->pb.add_r1cs_constraint(r1cs_constraint(prev_pc_val[0], + packed_ls_prev_val - packed_store_val, + packed_ls_next_val - packed_store_val), + FMT(this->annotation_prefix, " compute_packed_ls_next_val")); + + /* + packed_next_state = x0 * packed_ls_prev_val + (1-x0) * packed_prev_state + packed_next_state - packed_prev_state = x0 * (packed_ls_prev_val - packed_prev_state) + packed_next_state ~ next_state + packed_prev_state ~ prev_state + */ + pack_prev_state->generate_r1cs_constraints(false); + pack_next_state->generate_r1cs_constraints(false); + this->pb.add_r1cs_constraint(r1cs_constraint(prev_pc_val[0], + packed_ls_prev_val - packed_prev_state, + packed_next_state - packed_prev_state), + FMT(this->annotation_prefix, " compute_packed_next_state")); + + /* next_has_accepted = 1 */ + this->pb.add_r1cs_constraint(r1cs_constraint(1, next_has_accepted, 1), FMT(this->annotation_prefix, " always_accepted")); +} + +template +void fooram_cpu_checker::generate_r1cs_witness_address() +{ + one_as_addr.evaluate(this->pb); + + /* packed_next_pc_addr = prev_pc_addr + one_as_addr */ + increment_pc->generate_r1cs_witness(); + pack_next_pc_addr->generate_r1cs_witness_from_packed(); + + /* packed_store_addr = prev_pc_addr + prev_pc_val */ + compute_packed_store_addr->generate_r1cs_witness(); + + /* packed_load_addr = 2 * x + next_pc_addr */ + compute_packed_load_addr->generate_r1cs_witness(); + + /* + packed_ls_addr = x0 * packed_load_addr + (1-x0) * packed_store_addr + packed_ls_addr - packed_store_addr = x0 * (packed_load_addr - packed_store_addr) + packed_ls_addr ~ ls_addr + */ + this->pb.val(packed_ls_addr) = (this->pb.val(prev_pc_val[0]) * this->pb.val(packed_load_addr) + + (FieldT::one()-this->pb.val(prev_pc_val[0])) * this->pb.val(packed_store_addr)); + pack_ls_addr->generate_r1cs_witness_from_packed(); +} + +template +void fooram_cpu_checker::generate_r1cs_witness_other(fooram_input_tape_iterator &aux_it, + const fooram_input_tape_iterator &aux_end) +{ + /* fooram memory contents do not depend on program/input. */ + UNUSED(aux_it, aux_end); + /* packed_store_val = prev_state_bits + prev_pc_addr */ + compute_packed_store_val->generate_r1cs_witness(); + + /* + packed_ls_next_val = x0 * packed_ls_prev_val + (1-x0) * packed_store_val + packed_ls_next_val - packed_store_val = x0 * (packed_ls_prev_val - packed_store_val) + packed_ls_next_val ~ ls_next_val + */ + pack_ls_prev_val->generate_r1cs_witness_from_bits(); + this->pb.val(packed_ls_next_val) = (this->pb.val(prev_pc_val[0]) * this->pb.val(packed_ls_prev_val) + + (FieldT::one() - this->pb.val(prev_pc_val[0])) * this->pb.val(packed_store_val)); + pack_ls_next_val->generate_r1cs_witness_from_packed(); + + /* + packed_next_state = x0 * packed_ls_prev_val + (1-x0) * packed_prev_state + packed_next_state - packed_prev_state = x0 * (packed_ls_prev_val - packed_prev_state) + packed_next_state ~ next_state + packed_prev_state ~ prev_state + */ + pack_prev_state->generate_r1cs_witness_from_bits(); + this->pb.val(packed_next_state) = (this->pb.val(prev_pc_val[0]) * this->pb.val(packed_ls_prev_val) + + (FieldT::one() - this->pb.val(prev_pc_val[0])) * this->pb.val(packed_prev_state)); + pack_next_state->generate_r1cs_witness_from_packed(); + + /* next_has_accepted = 1 */ + this->pb.val(next_has_accepted) = FieldT::one(); +} + +template +void fooram_cpu_checker::dump() const +{ + printf("packed_store_addr: "); + this->pb.val(packed_store_addr).print(); + printf("packed_load_addr: "); + this->pb.val(packed_load_addr).print(); + printf("packed_ls_addr: "); + this->pb.val(packed_ls_addr).print(); + printf("packed_store_val: "); + this->pb.val(packed_store_val).print(); + printf("packed_ls_next_val: "); + this->pb.val(packed_ls_next_val).print(); + printf("packed_next_state: "); + this->pb.val(packed_next_state).print(); +} + +} // libsnark + +#endif // FOORAM_CPU_CHECKER_TCC diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_arithmetic.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_arithmetic.hpp new file mode 100644 index 0000000..f687a5a --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_arithmetic.hpp @@ -0,0 +1,684 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the TinyRAM ALU arithmetic gadgets. + + These gadget check the correct execution of arithmetic TinyRAM instructions. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALU_ARITHMETIC_HPP_ +#define ALU_ARITHMETIC_HPP_ +#include + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.hpp" +#include "gadgetlib1/gadgets/basic_gadgets.hpp" + +namespace libsnark { + +/* arithmetic gadgets */ +template +class ALU_arithmetic_gadget : public tinyram_standard_gadget { +public: + const pb_variable_array opcode_indicators; + const word_variable_gadget desval; + const word_variable_gadget arg1val; + const word_variable_gadget arg2val; + const pb_variable flag; + const pb_variable result; + const pb_variable result_flag; + + ALU_arithmetic_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &result, + const pb_variable &result_flag, + const std::string &annotation_prefix="") : + tinyram_standard_gadget(pb, annotation_prefix), + opcode_indicators(opcode_indicators), + desval(desval), + arg1val(arg1val), + arg2val(arg2val), + flag(flag), + result(result), + result_flag(result_flag) {} +}; + +template +class ALU_and_gadget : public ALU_arithmetic_gadget { +private: + pb_variable_array res_word; + std::shared_ptr > pack_result; + std::shared_ptr > not_all_zeros; + pb_variable not_all_zeros_result; +public: + ALU_and_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &result, + const pb_variable &result_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, annotation_prefix) + { + res_word.allocate(pb, pb.ap.w, FMT(this->annotation_prefix, " res_bit")); + not_all_zeros_result.allocate(pb, FMT(this->annotation_prefix, " not_all_zeros_result")); + + pack_result.reset( + new packing_gadget(pb, res_word, result, + FMT(this->annotation_prefix, " pack_result"))); + not_all_zeros.reset( + new disjunction_gadget(pb, res_word, not_all_zeros_result, + FMT(this->annotation_prefix, "not_all_zeros"))); + } + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_and_gadget(const size_t w); + +template +class ALU_or_gadget : public ALU_arithmetic_gadget { +private: + pb_variable_array res_word; + std::shared_ptr > pack_result; + std::shared_ptr > not_all_zeros; + pb_variable not_all_zeros_result; +public: + ALU_or_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &result, + const pb_variable &result_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, annotation_prefix) + { + res_word.allocate(pb, pb.ap.w, FMT(this->annotation_prefix, " res_bit")); + not_all_zeros_result.allocate(pb, FMT(this->annotation_prefix, " not_all_zeros_result")); + + pack_result.reset( + new packing_gadget(pb, res_word, result, + FMT(this->annotation_prefix, " pack_result"))); + not_all_zeros.reset( + new disjunction_gadget(pb, res_word, not_all_zeros_result, + FMT(this->annotation_prefix, "not_all_zeros"))); + } + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_or_gadget(const size_t w); + +template +class ALU_xor_gadget : public ALU_arithmetic_gadget { +private: + pb_variable_array res_word; + std::shared_ptr > pack_result; + std::shared_ptr > not_all_zeros; + pb_variable not_all_zeros_result; +public: + ALU_xor_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &result, + const pb_variable &result_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, annotation_prefix) + { + res_word.allocate(pb, pb.ap.w, FMT(this->annotation_prefix, " res_bit")); + not_all_zeros_result.allocate(pb, FMT(this->annotation_prefix, " not_all_zeros_result")); + + pack_result.reset( + new packing_gadget(pb, res_word, result, + FMT(this->annotation_prefix, " pack_result"))); + not_all_zeros.reset( + new disjunction_gadget(pb, res_word, not_all_zeros_result, + FMT(this->annotation_prefix, "not_all_zeros"))); + } + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_xor_gadget(const size_t w); + +template +class ALU_not_gadget : public ALU_arithmetic_gadget { +/* we do bitwise not, because we need to compute flag */ +private: + pb_variable_array res_word; + std::shared_ptr > pack_result; + std::shared_ptr > not_all_zeros; + pb_variable not_all_zeros_result; +public: + ALU_not_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &result, + const pb_variable &result_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, annotation_prefix) + { + res_word.allocate(pb, pb.ap.w, FMT(this->annotation_prefix, " res_bit")); + not_all_zeros_result.allocate(pb, FMT(this->annotation_prefix, " not_all_zeros_result")); + + pack_result.reset( + new packing_gadget(pb, res_word, result, + FMT(this->annotation_prefix, " pack_result"))); + not_all_zeros.reset( + new disjunction_gadget(pb, res_word, not_all_zeros_result, + FMT(this->annotation_prefix, "not_all_zeros"))); + } + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_not_gadget(const size_t w); + +template +class ALU_add_gadget : public ALU_arithmetic_gadget { +private: + pb_variable addition_result; + pb_variable_array res_word; + pb_variable_array res_word_and_flag; + std::shared_ptr > unpack_addition, pack_result; +public: + ALU_add_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &result, + const pb_variable &result_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, annotation_prefix) + { + addition_result.allocate(pb, FMT(this->annotation_prefix, " addition_result")); + res_word.allocate(pb, pb.ap.w, FMT(this->annotation_prefix, " res_word")); + + res_word_and_flag = res_word; + res_word_and_flag.emplace_back(result_flag); + + unpack_addition.reset( + new packing_gadget(pb, res_word_and_flag, addition_result, + FMT(this->annotation_prefix, " unpack_addition"))); + pack_result.reset( + new packing_gadget(pb, res_word, result, + FMT(this->annotation_prefix, " pack_result"))); + } + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +void test_ALU_add_gadget(const size_t w); + +template +class ALU_sub_gadget : public ALU_arithmetic_gadget { +private: + pb_variable intermediate_result; + pb_variable negated_flag; + pb_variable_array res_word; + pb_variable_array res_word_and_negated_flag; + + std::shared_ptr > unpack_intermediate, pack_result; +public: + ALU_sub_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &result, + const pb_variable &result_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, annotation_prefix) + { + intermediate_result.allocate(pb, FMT(this->annotation_prefix, " intermediate_result")); + negated_flag.allocate(pb, FMT(this->annotation_prefix, " negated_flag")); + res_word.allocate(pb, pb.ap.w, FMT(this->annotation_prefix, " res_word")); + + res_word_and_negated_flag = res_word; + res_word_and_negated_flag.emplace_back(negated_flag); + + unpack_intermediate.reset( + new packing_gadget(pb, res_word_and_negated_flag, intermediate_result, + FMT(this->annotation_prefix, " unpack_intermediate"))); + pack_result.reset( + new packing_gadget(pb, res_word, result, + FMT(this->annotation_prefix, " pack_result"))); + } + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +void test_ALU_sub_gadget(const size_t w); + +template +class ALU_mov_gadget : public ALU_arithmetic_gadget { +public: + ALU_mov_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &result, + const pb_variable &result_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, annotation_prefix) {} + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_mov_gadget(const size_t w); + +template +class ALU_cmov_gadget : public ALU_arithmetic_gadget { +public: + ALU_cmov_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &result, + const pb_variable &result_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, annotation_prefix) + { + } + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_cmov_gadget(const size_t w); + +template +class ALU_cmp_gadget : public ALU_arithmetic_gadget { +private: + comparison_gadget comparator; +public: + const pb_variable cmpe_result; + const pb_variable cmpe_result_flag; + const pb_variable cmpa_result; + const pb_variable cmpa_result_flag; + const pb_variable cmpae_result; + const pb_variable cmpae_result_flag; + + ALU_cmp_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &cmpe_result, + const pb_variable &cmpe_result_flag, + const pb_variable &cmpa_result, + const pb_variable &cmpa_result_flag, + const pb_variable &cmpae_result, + const pb_variable &cmpae_result_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, cmpa_result, cmpa_result_flag, annotation_prefix), + comparator(pb, pb.ap.w, arg2val.packed, arg1val.packed, cmpa_result_flag, cmpae_result_flag, + FMT(this->annotation_prefix, " comparator")), + cmpe_result(cmpe_result), cmpe_result_flag(cmpe_result_flag), + cmpa_result(cmpa_result), cmpa_result_flag(cmpa_result_flag), + cmpae_result(cmpae_result), cmpae_result_flag(cmpae_result_flag) {} + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_cmpe_gadget(const size_t w); + +template +void test_ALU_cmpa_gadget(const size_t w); + +template +void test_ALU_cmpae_gadget(const size_t w); + +template +class ALU_cmps_gadget : public ALU_arithmetic_gadget { +private: + pb_variable negated_arg1val_sign; + pb_variable negated_arg2val_sign; + pb_variable_array modified_arg1; + pb_variable_array modified_arg2; + pb_variable packed_modified_arg1; + pb_variable packed_modified_arg2; + std::shared_ptr > pack_modified_arg1; + std::shared_ptr > pack_modified_arg2; + std::shared_ptr > comparator; +public: + const pb_variable cmpg_result; + const pb_variable cmpg_result_flag; + const pb_variable cmpge_result; + const pb_variable cmpge_result_flag; + + ALU_cmps_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &cmpg_result, + const pb_variable &cmpg_result_flag, + const pb_variable &cmpge_result, + const pb_variable &cmpge_result_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, cmpg_result, cmpg_result_flag, annotation_prefix), + cmpg_result(cmpg_result), cmpg_result_flag(cmpg_result_flag), + cmpge_result(cmpge_result), cmpge_result_flag(cmpge_result_flag) + { + negated_arg1val_sign.allocate(pb, FMT(this->annotation_prefix, " negated_arg1val_sign")); + negated_arg2val_sign.allocate(pb, FMT(this->annotation_prefix, " negated_arg2val_sign")); + + modified_arg1 = pb_variable_array(arg1val.bits.begin(), --arg1val.bits.end()); + modified_arg1.emplace_back(negated_arg1val_sign); + + modified_arg2 = pb_variable_array(arg2val.bits.begin(), --arg2val.bits.end()); + modified_arg2.emplace_back(negated_arg2val_sign); + + packed_modified_arg1.allocate(pb, FMT(this->annotation_prefix, " packed_modified_arg1")); + packed_modified_arg2.allocate(pb, FMT(this->annotation_prefix, " packed_modified_arg2")); + + pack_modified_arg1.reset(new packing_gadget(pb, modified_arg1, packed_modified_arg1, + FMT(this->annotation_prefix, " pack_modified_arg1"))); + pack_modified_arg2.reset(new packing_gadget(pb, modified_arg2, packed_modified_arg2, + FMT(this->annotation_prefix, " pack_modified_arg2"))); + + comparator.reset(new comparison_gadget(pb, pb.ap.w, + packed_modified_arg2, packed_modified_arg1, + cmpg_result_flag, cmpge_result_flag, + FMT(this->annotation_prefix, " comparator"))); + } + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_cmpg_gadget(const size_t w); + +template +void test_ALU_cmpge_gadget(const size_t w); + +template +class ALU_umul_gadget : public ALU_arithmetic_gadget { +private: + dual_variable_gadget mul_result; + pb_variable_array mull_bits; + pb_variable_array umulh_bits; + pb_variable result_flag; + std::shared_ptr > pack_mull_result; + std::shared_ptr > pack_umulh_result; + std::shared_ptr > compute_flag; +public: + const pb_variable mull_result; + const pb_variable mull_flag; + const pb_variable umulh_result; + const pb_variable umulh_flag; + + ALU_umul_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &mull_result, + const pb_variable &mull_flag, + const pb_variable &umulh_result, + const pb_variable &umulh_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, mull_result, mull_flag, annotation_prefix), + mul_result(pb, 2*pb.ap.w, FMT(this->annotation_prefix, " mul_result")), + mull_result(mull_result), mull_flag(mull_flag), umulh_result(umulh_result), umulh_flag(umulh_flag) + { + mull_bits.insert(mull_bits.end(), mul_result.bits.begin(), mul_result.bits.begin()+pb.ap.w); + umulh_bits.insert(umulh_bits.end(), mul_result.bits.begin()+pb.ap.w, mul_result.bits.begin()+2*pb.ap.w); + + pack_mull_result.reset(new packing_gadget(pb, mull_bits, mull_result, FMT(this->annotation_prefix, " pack_mull_result"))); + pack_umulh_result.reset(new packing_gadget(pb, umulh_bits, umulh_result, FMT(this->annotation_prefix, " pack_umulh_result"))); + + result_flag.allocate(pb, FMT(this->annotation_prefix, " result_flag")); + compute_flag.reset(new disjunction_gadget(pb, umulh_bits, result_flag, FMT(this->annotation_prefix, " compute_flag"))); + } + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_mull_gadget(const size_t w); + +template +void test_ALU_umulh_gadget(const size_t w); + +template +class ALU_smul_gadget : public ALU_arithmetic_gadget { +private: + dual_variable_gadget mul_result; + pb_variable_array smulh_bits; + + pb_variable top; + std::shared_ptr > pack_top; + + pb_variable is_top_empty, is_top_empty_aux; + pb_variable is_top_full, is_top_full_aux; + + pb_variable result_flag; + std::shared_ptr > pack_smulh_result; +public: + const pb_variable smulh_result; + const pb_variable smulh_flag; + + ALU_smul_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &smulh_result, + const pb_variable &smulh_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, smulh_result, smulh_flag, annotation_prefix), + mul_result(pb, 2*pb.ap.w+1, FMT(this->annotation_prefix, " mul_result")), /* see witness map for explanation for 2w+1 */ + smulh_result(smulh_result), smulh_flag(smulh_flag) + { + smulh_bits.insert(smulh_bits.end(), mul_result.bits.begin()+pb.ap.w, mul_result.bits.begin()+2*pb.ap.w); + + pack_smulh_result.reset(new packing_gadget(pb, smulh_bits, smulh_result, FMT(this->annotation_prefix, " pack_smulh_result"))); + + top.allocate(pb, FMT(this->annotation_prefix, " top")); + pack_top.reset(new packing_gadget(pb, pb_variable_array(mul_result.bits.begin() + pb.ap.w-1, mul_result.bits.begin() + 2*pb.ap.w), top, + FMT(this->annotation_prefix, " pack_top"))); + + is_top_empty.allocate(pb, FMT(this->annotation_prefix, " is_top_empty")); + is_top_empty_aux.allocate(pb, FMT(this->annotation_prefix, " is_top_empty_aux")); + + is_top_full.allocate(pb, FMT(this->annotation_prefix, " is_top_full")); + is_top_full_aux.allocate(pb, FMT(this->annotation_prefix, " is_top_full_aux")); + + result_flag.allocate(pb, FMT(this->annotation_prefix, " result_flag")); + } + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_smulh_gadget(const size_t w); + +template +class ALU_divmod_gadget : public ALU_arithmetic_gadget { +/* + <<<<<<< Updated upstream + B * q + r = A_aux = A * B_nonzero + q * (1-B_nonzero) = 0 + A(r < B, less=B_nonzero, leq=ONE) + ======= + B * q + r = A + + r <= B + >>>>>>> Stashed changes +*/ +private: + pb_variable B_inv; + pb_variable B_nonzero; + pb_variable A_aux; + std::shared_ptr > r_less_B; +public: + const pb_variable udiv_result; + const pb_variable udiv_flag; + const pb_variable umod_result; + const pb_variable umod_flag; + + ALU_divmod_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &udiv_result, + const pb_variable &udiv_flag, + const pb_variable &umod_result, + const pb_variable &umod_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, udiv_result, udiv_flag, annotation_prefix), + udiv_result(udiv_result), udiv_flag(udiv_flag), umod_result(umod_result), umod_flag(umod_flag) + { + B_inv.allocate(pb, FMT(this->annotation_prefix, " B_inv")); + B_nonzero.allocate(pb, FMT(this->annotation_prefix, " B_nonzer")); + A_aux.allocate(pb, FMT(this->annotation_prefix, " A_aux")); + r_less_B.reset(new comparison_gadget(pb, pb.ap.w, umod_result, arg2val.packed, + B_nonzero, ONE, FMT(this->annotation_prefix, " r_less_B"))); + } + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_udiv_gadget(const size_t w); + +template +void test_ALU_umod_gadget(const size_t w); + +template +class ALU_shr_shl_gadget : public ALU_arithmetic_gadget { +private: + pb_variable reversed_input; + std::shared_ptr > pack_reversed_input; + + pb_variable_array barrel_right_internal; + std::vector > shifted_out_bits; + + pb_variable is_oversize_shift; + std::shared_ptr > check_oversize_shift; + pb_variable result; + + pb_variable_array result_bits; + std::shared_ptr > unpack_result; + pb_variable reversed_result; + std::shared_ptr > pack_reversed_result; +public: + pb_variable shr_result; + pb_variable shr_flag; + pb_variable shl_result; + pb_variable shl_flag; + + size_t logw; + + ALU_shr_shl_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &shr_result, + const pb_variable &shr_flag, + const pb_variable &shl_result, + const pb_variable &shl_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, shr_result, shr_flag, annotation_prefix), + shr_result(shr_result), shr_flag(shr_flag), shl_result(shl_result), shl_flag(shl_flag) + { + logw = log2(pb.ap.w); + + reversed_input.allocate(pb, FMT(this->annotation_prefix, " reversed_input")); + pack_reversed_input.reset( + new packing_gadget(pb, pb_variable_array(arg1val.bits.rbegin(), arg1val.bits.rend()), + reversed_input, + FMT(this->annotation_prefix, " pack_reversed_input"))); + + barrel_right_internal.allocate(pb, logw+1, FMT(this->annotation_prefix, " barrel_right_internal")); + + shifted_out_bits.resize(logw); + for (size_t i = 0; i < logw; ++i) + { + shifted_out_bits[i].allocate(pb, 1ul<annotation_prefix, " shifted_out_bits_%zu", i)); + } + + is_oversize_shift.allocate(pb, FMT(this->annotation_prefix, " is_oversize_shift")); + check_oversize_shift.reset( + new disjunction_gadget(pb, + pb_variable_array(arg2val.bits.begin()+logw, arg2val.bits.end()), + is_oversize_shift, + FMT(this->annotation_prefix, " check_oversize_shift"))); + result.allocate(pb, FMT(this->annotation_prefix, " result")); + + result_bits.allocate(pb, pb.ap.w, FMT(this->annotation_prefix, " result_bits")); + unpack_result.reset( + new packing_gadget(pb, result_bits, result, //barrel_right_internal[logw], + FMT(this->annotation_prefix, " unpack_result"))); + + reversed_result.allocate(pb, FMT(this->annotation_prefix, " reversed_result")); + pack_reversed_result.reset( + new packing_gadget(pb, pb_variable_array(result_bits.rbegin(), result_bits.rend()), + reversed_result, + FMT(this->annotation_prefix, " pack_reversed_result"))); + } + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_shr_gadget(const size_t w); + +template +void test_ALU_shl_gadget(const size_t w); + +} // libsnark + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_arithmetic.tcc" + +#endif // ALU_ARITHMETIC_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_arithmetic.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_arithmetic.tcc new file mode 100644 index 0000000..170af28 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_arithmetic.tcc @@ -0,0 +1,1500 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the TinyRAM ALU arithmetic gadgets. + + See alu_arithmetic.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALU_ARITHMETIC_TCC_ +#define ALU_ARITHMETIC_TCC_ + +#include "common/profiling.hpp" +#include "common/utils.hpp" + +namespace libsnark { + +/* the code here is full of template lambda magic, but it is better to + have limited presence of such code than to have code duplication in + testing functions, which basically do the same thing: brute force + the range of inputs which different success predicates */ + +template +using initializer_fn = + std::function&, // pb + pb_variable_array&, // opcode_indicators + word_variable_gadget&, // desval + word_variable_gadget&, // arg1val + word_variable_gadget&, // arg2val + pb_variable&, // flag + pb_variable&, // result + pb_variable& // result_flag + )>; + +template +void brute_force_arithmetic_gadget(const size_t w, + const size_t opcode, + initializer_fn initializer, + std::function res_function, + std::function flag_function) +/* parameters for res_function and flag_function are both desval, flag, arg1val, arg2val */ +{ + printf("testing on all %zu bit inputs\n", w); + + tinyram_architecture_params ap(w, 16); + tinyram_program P; P.instructions = generate_tinyram_prelude(ap); + tinyram_protoboard pb(ap, P.size(), 0, 10); + + pb_variable_array opcode_indicators; + opcode_indicators.allocate(pb, 1ul< desval(pb, "desval"); + desval.generate_r1cs_constraints(true); + word_variable_gadget arg1val(pb, "arg1val"); + arg1val.generate_r1cs_constraints(true); + word_variable_gadget arg2val(pb, "arg2val"); + arg2val.generate_r1cs_constraints(true); + pb_variable flag; flag.allocate(pb, "flag"); + pb_variable result; result.allocate(pb, "result"); + pb_variable result_flag; result_flag.allocate(pb, "result_flag"); + + std::unique_ptr g; + g.reset(initializer(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag)); + g->generate_r1cs_constraints(); + + for (size_t des = 0; des < (1u << w); ++des) + { + pb.val(desval.packed) = FieldT(des); + desval.generate_r1cs_witness_from_packed(); + + for (char f = 0; f <= 1; ++f) + { + pb.val(flag) = (f ? FieldT::one() : FieldT::zero()); + + for (size_t arg1 = 0; arg1 < (1u << w); ++arg1) + { + pb.val(arg1val.packed) = FieldT(arg1); + arg1val.generate_r1cs_witness_from_packed(); + + for (size_t arg2 = 0; arg2 < (1u << w); ++arg2) + { + pb.val(arg2val.packed) = FieldT(arg2); + arg2val.generate_r1cs_witness_from_packed(); + + size_t res = res_function(des, f, arg1, arg2); + bool res_f = flag_function(des, f, arg1, arg2); +#ifdef DEBUG + printf("with the following parameters: flag = %d" + ", desval = %zu (%d)" + ", arg1val = %zu (%d)" + ", arg2val = %zu (%d)" + ". expected result: %zu (%d), expected flag: %d\n", + f, + des, from_twos_complement(des, w), + arg1, from_twos_complement(arg1, w), + arg2, from_twos_complement(arg2, w), + res, from_twos_complement(res, w), res_f); +#endif + g->generate_r1cs_witness(); +#ifdef DEBUG + printf("result: "); + pb.val(result).print(); + printf("flag: "); + pb.val(result_flag).print(); +#endif + assert(pb.is_satisfied()); + assert(pb.val(result) == FieldT(res)); + assert(pb.val(result_flag) == (res_f ? FieldT::one() : FieldT::zero())); + } + } + } + } +} + +/* and */ +template +void ALU_and_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < this->pb.ap.w; ++i) + { + this->pb.add_r1cs_constraint( + r1cs_constraint( + { this->arg1val.bits[i] }, + { this->arg2val.bits[i] }, + { this->res_word[i] }), + FMT(this->annotation_prefix, " res_word_%zu", i)); + } + + /* generate result */ + pack_result->generate_r1cs_constraints(false); + not_all_zeros->generate_r1cs_constraints(); + + /* result_flag = 1 - not_all_zeros = result is 0^w */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { ONE, this->not_all_zeros_result * (-1) }, + { this->result_flag }), + FMT(this->annotation_prefix, " result_flag")); +} + +template +void ALU_and_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < this->pb.ap.w; ++i) + { + bool b1 = this->pb.val(this->arg1val.bits[i]) == FieldT::one(); + bool b2 = this->pb.val(this->arg2val.bits[i]) == FieldT::one(); + + this->pb.val(this->res_word[i]) = (b1 && b2 ? FieldT::one() : FieldT::zero()); + } + + pack_result->generate_r1cs_witness_from_bits(); + not_all_zeros->generate_r1cs_witness(); + this->pb.val(this->result_flag) = FieldT::one() - this->pb.val(not_all_zeros_result); +} + +template +void test_ALU_and_gadget(const size_t w) +{ + print_time("starting and test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_AND, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_and_gadget* { + return new ALU_and_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, "ALU_and_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return x & y; }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { return (x & y) == 0; }); + print_time("and tests successful"); +} + +/* or */ +template +void ALU_or_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < this->pb.ap.w; ++i) + { + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE, this->arg1val.bits[i] * (-1) }, + { ONE, this->arg2val.bits[i] * (-1) }, + { ONE, this->res_word[i] * (-1) }), + FMT(this->annotation_prefix, " res_word_%zu", i)); + } + + /* generate result */ + pack_result->generate_r1cs_constraints(false); + not_all_zeros->generate_r1cs_constraints(); + + /* result_flag = 1 - not_all_zeros = result is 0^w */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { ONE, this->not_all_zeros_result * (-1) }, + { this->result_flag }), + FMT(this->annotation_prefix, " result_flag")); +} + +template +void ALU_or_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < this->pb.ap.w; ++i) + { + bool b1 = this->pb.val(this->arg1val.bits[i]) == FieldT::one(); + bool b2 = this->pb.val(this->arg2val.bits[i]) == FieldT::one(); + + this->pb.val(this->res_word[i]) = (b1 || b2 ? FieldT::one() : FieldT::zero()); + } + + pack_result->generate_r1cs_witness_from_bits(); + not_all_zeros->generate_r1cs_witness(); + this->pb.val(this->result_flag) = FieldT::one() - this->pb.val(this->not_all_zeros_result); +} + +template +void test_ALU_or_gadget(const size_t w) +{ + print_time("starting or test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_OR, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_or_gadget* { + return new ALU_or_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, "ALU_or_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return x | y; }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { return (x | y) == 0; }); + print_time("or tests successful"); +} + +/* xor */ +template +void ALU_xor_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < this->pb.ap.w; ++i) + { + /* a = b ^ c <=> a = b + c - 2*b*c, (2*b)*c = b+c - a */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { this->arg1val.bits[i] * 2}, + { this->arg2val.bits[i] }, + { this->arg1val.bits[i], this->arg2val.bits[i], this->res_word[i] * (-1) }), + FMT(this->annotation_prefix, " res_word_%zu", i)); + } + + /* generate result */ + pack_result->generate_r1cs_constraints(false); + not_all_zeros->generate_r1cs_constraints(); + + /* result_flag = 1 - not_all_zeros = result is 0^w */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { ONE, this->not_all_zeros_result * (-1) }, + { this->result_flag }), + FMT(this->annotation_prefix, " result_flag")); +} + +template +void ALU_xor_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < this->pb.ap.w; ++i) + { + bool b1 = this->pb.val(this->arg1val.bits[i]) == FieldT::one(); + bool b2 = this->pb.val(this->arg2val.bits[i]) == FieldT::one(); + + this->pb.val(this->res_word[i]) = (b1 ^ b2 ? FieldT::one() : FieldT::zero()); + } + + pack_result->generate_r1cs_witness_from_bits(); + not_all_zeros->generate_r1cs_witness(); + this->pb.val(this->result_flag) = FieldT::one() - this->pb.val(this->not_all_zeros_result); +} + +template +void test_ALU_xor_gadget(const size_t w) +{ + print_time("starting xor test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_XOR, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_xor_gadget* { + return new ALU_xor_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, "ALU_xor_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return x ^ y; }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { return (x ^ y) == 0; }); + print_time("xor tests successful"); +} + +/* not */ +template +void ALU_not_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < this->pb.ap.w; ++i) + { + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { ONE, this->arg2val.bits[i] * (-1) }, + { this->res_word[i] }), + FMT(this->annotation_prefix, " res_word_%zu", i)); + } + + /* generate result */ + pack_result->generate_r1cs_constraints(false); + not_all_zeros->generate_r1cs_constraints(); + + /* result_flag = 1 - not_all_zeros = result is 0^w */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { ONE, this->not_all_zeros_result * (-1) }, + { this->result_flag }), + FMT(this->annotation_prefix, " result_flag")); +} + +template +void ALU_not_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < this->pb.ap.w; ++i) + { + bool b2 = this->pb.val(this->arg2val.bits[i]) == FieldT::one(); + + this->pb.val(this->res_word[i]) = (!b2 ? FieldT::one() : FieldT::zero()); + } + + pack_result->generate_r1cs_witness_from_bits(); + not_all_zeros->generate_r1cs_witness(); + this->pb.val(this->result_flag) = FieldT::one() - this->pb.val(this->not_all_zeros_result); +} + +template +void test_ALU_not_gadget(const size_t w) +{ + print_time("starting not test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_NOT, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_not_gadget* { + return new ALU_not_gadget(pb, opcode_indicators,desval, arg1val, arg2val, flag, result, result_flag, "ALU_not_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return (1ul< bool { return ((1ul< +void ALU_add_gadget::generate_r1cs_constraints() +{ + /* addition_result = 1 * (arg1val + arg2val) */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->arg1val.packed, this->arg2val.packed }, + { this->addition_result }), + FMT(this->annotation_prefix, " addition_result")); + + /* unpack into bits */ + unpack_addition->generate_r1cs_constraints(true); + + /* generate result */ + pack_result->generate_r1cs_constraints(false); +} + +template +void ALU_add_gadget::generate_r1cs_witness() +{ + this->pb.val(addition_result) = this->pb.val(this->arg1val.packed) + this->pb.val(this->arg2val.packed); + unpack_addition->generate_r1cs_witness_from_packed(); + pack_result->generate_r1cs_witness_from_bits(); +} + +template +void test_ALU_add_gadget(const size_t w) +{ + print_time("starting add test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_ADD, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_add_gadget* { + return new ALU_add_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, "ALU_add_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return (x+y) % (1ul< bool { return (x+y) >= (1ul< +void ALU_sub_gadget::generate_r1cs_constraints() +{ + /* intermediate_result = 2^w + (arg1val - arg2val) */ + FieldT twoi = FieldT::one(); + + linear_combination a, b, c; + + a.add_term(0, 1); + for (size_t i = 0; i < this->pb.ap.w; ++i) + { + twoi = twoi + twoi; + } + b.add_term(0, twoi); + b.add_term(this->arg1val.packed, 1); + b.add_term(this->arg2val.packed, -1); + c.add_term(intermediate_result, 1); + + this->pb.add_r1cs_constraint(r1cs_constraint(a, b, c), FMT(this->annotation_prefix, " main_constraint")); + + /* unpack into bits */ + unpack_intermediate->generate_r1cs_constraints(true); + + /* generate result */ + pack_result->generate_r1cs_constraints(false); + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { ONE, this->negated_flag * (-1) }, + { this->result_flag }), + FMT(this->annotation_prefix, " result_flag")); +} + +template +void ALU_sub_gadget::generate_r1cs_witness() +{ + FieldT twoi = FieldT::one(); + for (size_t i = 0; i < this->pb.ap.w; ++i) + { + twoi = twoi + twoi; + } + + this->pb.val(intermediate_result) = twoi + this->pb.val(this->arg1val.packed) - this->pb.val(this->arg2val.packed); + unpack_intermediate->generate_r1cs_witness_from_packed(); + pack_result->generate_r1cs_witness_from_bits(); + this->pb.val(this->result_flag) = FieldT::one() - this->pb.val(this->negated_flag); +} + +template +void test_ALU_sub_gadget(const size_t w) +{ + print_time("starting sub test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_SUB, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_sub_gadget* { + return new ALU_sub_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, "ALU_sub_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { + const size_t unsigned_result = ((1ul< bool { + const size_t msb = ((1ul<> w; + return (msb == 0); + }); + print_time("sub tests successful"); +} + +/* mov */ +template +void ALU_mov_gadget::generate_r1cs_constraints() +{ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->arg2val.packed }, + { this->result }), + FMT(this->annotation_prefix, " mov_result")); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->flag }, + { this->result_flag }), + FMT(this->annotation_prefix, " mov_result_flag")); +} + +template +void ALU_mov_gadget::generate_r1cs_witness() +{ + this->pb.val(this->result) = this->pb.val(this->arg2val.packed); + this->pb.val(this->result_flag) = this->pb.val(this->flag); +} + +template +void test_ALU_mov_gadget(const size_t w) +{ + print_time("starting mov test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_MOV, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_mov_gadget* { + return new ALU_mov_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, "ALU_mov_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return y; }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { return f; }); + print_time("mov tests successful"); +} + +/* cmov */ +template +void ALU_cmov_gadget::generate_r1cs_constraints() +{ + /* + flag1 * arg2val + (1-flag1) * desval = result + flag1 * (arg2val - desval) = result - desval + */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { this->flag }, + { this->arg2val.packed, this->desval.packed * (-1) }, + { this->result, this->desval.packed * (-1) }), + FMT(this->annotation_prefix, " cmov_result")); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->flag }, + { this->result_flag }), + FMT(this->annotation_prefix, " cmov_result_flag")); +} + +template +void ALU_cmov_gadget::generate_r1cs_witness() +{ + this->pb.val(this->result) = ((this->pb.val(this->flag) == FieldT::one()) ? + this->pb.val(this->arg2val.packed) : + this->pb.val(this->desval.packed)); + this->pb.val(this->result_flag) = this->pb.val(this->flag); +} + +template +void test_ALU_cmov_gadget(const size_t w) +{ + print_time("starting cmov test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_CMOV, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_cmov_gadget* { + return new ALU_cmov_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, "ALU_cmov_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return f ? y : des; }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { return f; }); + print_time("cmov tests successful"); +} + +/* unsigned comparison */ +template +void ALU_cmp_gadget::generate_r1cs_constraints() +{ + comparator.generate_r1cs_constraints(); + /* + cmpe = cmpae * (1-cmpa) + */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { cmpae_result_flag }, + { ONE, cmpa_result_flag * (-1) }, + { cmpe_result_flag }), + FMT(this->annotation_prefix, " cmpa_result_flag")); + + /* copy over results */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->desval.packed }, + { cmpe_result }), + FMT(this->annotation_prefix, " cmpe_result")); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->desval.packed }, + { cmpa_result }), + FMT(this->annotation_prefix, " cmpa_result")); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->desval.packed }, + { cmpae_result }), + FMT(this->annotation_prefix, " cmpae_result")); +} + +template +void ALU_cmp_gadget::generate_r1cs_witness() +{ + comparator.generate_r1cs_witness(); + + this->pb.val(cmpe_result) = this->pb.val(this->desval.packed); + this->pb.val(cmpa_result) = this->pb.val(this->desval.packed); + this->pb.val(cmpae_result) = this->pb.val(this->desval.packed); + + this->pb.val(cmpe_result_flag) = ((this->pb.val(cmpae_result_flag) == FieldT::one()) && + (this->pb.val(cmpa_result_flag) == FieldT::zero()) ? + FieldT::one() : + FieldT::zero()); +} + +template +void test_ALU_cmpe_gadget(const size_t w) +{ + print_time("starting cmpe test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_CMPE, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_cmp_gadget* { + pb_variable cmpa_result; cmpa_result.allocate(pb, "cmpa_result"); + pb_variable cmpa_result_flag; cmpa_result_flag.allocate(pb, "cmpa_result_flag"); + pb_variable cmpae_result; cmpae_result.allocate(pb, "cmpae_result"); + pb_variable cmpae_result_flag; cmpae_result_flag.allocate(pb, "cmpae_result_flag"); + return new ALU_cmp_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + result, result_flag, + cmpa_result, cmpa_result_flag, + cmpae_result, cmpae_result_flag, "ALU_cmp_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return des; }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { return x == y; }); + print_time("cmpe tests successful"); +} + +template +void test_ALU_cmpa_gadget(const size_t w) +{ + print_time("starting cmpa test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_CMPA, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_cmp_gadget* { + pb_variable cmpe_result; cmpe_result.allocate(pb, "cmpe_result"); + pb_variable cmpe_result_flag; cmpe_result_flag.allocate(pb, "cmpe_result_flag"); + pb_variable cmpae_result; cmpae_result.allocate(pb, "cmpae_result"); + pb_variable cmpae_result_flag; cmpae_result_flag.allocate(pb, "cmpae_result_flag"); + return new ALU_cmp_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + cmpe_result, cmpe_result_flag, + result, result_flag, + cmpae_result, cmpae_result_flag, "ALU_cmp_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return des; }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { return x > y; }); + print_time("cmpa tests successful"); +} + +template +void test_ALU_cmpae_gadget(const size_t w) +{ + print_time("starting cmpae test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_CMPAE, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_cmp_gadget* { + pb_variable cmpe_result; cmpe_result.allocate(pb, "cmpe_result"); + pb_variable cmpe_result_flag; cmpe_result_flag.allocate(pb, "cmpe_result_flag"); + pb_variable cmpa_result; cmpa_result.allocate(pb, "cmpa_result"); + pb_variable cmpa_result_flag; cmpa_result_flag.allocate(pb, "cmpa_result_flag"); + return new ALU_cmp_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + cmpe_result, cmpe_result_flag, + cmpa_result, cmpa_result_flag, + result, result_flag, "ALU_cmp_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return des; }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { return x >= y; }); + print_time("cmpae tests successful"); +} + +/* signed comparison */ +template +void ALU_cmps_gadget::generate_r1cs_constraints() +{ + /* negate sign bits */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { ONE, this->arg1val.bits[this->pb.ap.w-1] * (-1) }, + { negated_arg1val_sign }), + FMT(this->annotation_prefix, " negated_arg1val_sign")); + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { ONE, this->arg2val.bits[this->pb.ap.w-1] * (-1) }, + { negated_arg2val_sign }), + FMT(this->annotation_prefix, " negated_arg2val_sign")); + + /* pack */ + pack_modified_arg1->generate_r1cs_constraints(false); + pack_modified_arg2->generate_r1cs_constraints(false); + + /* compare */ + comparator->generate_r1cs_constraints(); + + /* copy over results */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->desval.packed }, + { cmpg_result }), + FMT(this->annotation_prefix, " cmpg_result")); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->desval.packed }, + { cmpge_result }), + FMT(this->annotation_prefix, " cmpge_result")); +} + +template +void ALU_cmps_gadget::generate_r1cs_witness() +{ + /* negate sign bits */ + this->pb.val(negated_arg1val_sign) = FieldT::one() - this->pb.val(this->arg1val.bits[this->pb.ap.w-1]); + this->pb.val(negated_arg2val_sign) = FieldT::one() - this->pb.val(this->arg2val.bits[this->pb.ap.w-1]); + + /* pack */ + pack_modified_arg1->generate_r1cs_witness_from_bits(); + pack_modified_arg2->generate_r1cs_witness_from_bits(); + + /* produce result */ + comparator->generate_r1cs_witness(); + + this->pb.val(cmpg_result) = this->pb.val(this->desval.packed); + this->pb.val(cmpge_result) = this->pb.val(this->desval.packed); +} + +template +void test_ALU_cmpg_gadget(const size_t w) +{ + print_time("starting cmpg test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_CMPG, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_cmps_gadget* { + pb_variable cmpge_result; cmpge_result.allocate(pb, "cmpge_result"); + pb_variable cmpge_result_flag; cmpge_result_flag.allocate(pb, "cmpge_result_flag"); + return new ALU_cmps_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + result, result_flag, + cmpge_result, cmpge_result_flag, "ALU_cmps_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return des; }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { + return (from_twos_complement(x, w) > + from_twos_complement(y, w)); + }); + print_time("cmpg tests successful"); +} + +template +void test_ALU_cmpge_gadget(const size_t w) +{ + print_time("starting cmpge test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_CMPGE, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_cmps_gadget* { + pb_variable cmpg_result; cmpg_result.allocate(pb, "cmpg_result"); + pb_variable cmpg_result_flag; cmpg_result_flag.allocate(pb, "cmpg_result_flag"); + return new ALU_cmps_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + cmpg_result, cmpg_result_flag, + result, result_flag, "ALU_cmps_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return des; }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { + return (from_twos_complement(x, w) >= + from_twos_complement(y, w)); + }); + print_time("cmpge tests successful"); +} + +template +void ALU_umul_gadget::generate_r1cs_constraints() +{ + /* do multiplication */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { this->arg1val.packed }, + { this->arg2val.packed }, + { mul_result.packed }), + FMT(this->annotation_prefix, " main_constraint")); + mul_result.generate_r1cs_constraints(true); + + /* pack result */ + pack_mull_result->generate_r1cs_constraints(false); + pack_umulh_result->generate_r1cs_constraints(false); + + /* compute flag */ + compute_flag->generate_r1cs_constraints(); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->result_flag }, + { mull_flag }), + FMT(this->annotation_prefix, " mull_flag")); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->result_flag }, + { umulh_flag }), + FMT(this->annotation_prefix, " umulh_flag")); +} + +template +void ALU_umul_gadget::generate_r1cs_witness() +{ + /* do multiplication */ + this->pb.val(mul_result.packed) = this->pb.val(this->arg1val.packed) * this->pb.val(this->arg2val.packed); + mul_result.generate_r1cs_witness_from_packed(); + + /* pack result */ + pack_mull_result->generate_r1cs_witness_from_bits(); + pack_umulh_result->generate_r1cs_witness_from_bits(); + + /* compute flag */ + compute_flag->generate_r1cs_witness(); + + this->pb.val(mull_flag) = this->pb.val(this->result_flag); + this->pb.val(umulh_flag) = this->pb.val(this->result_flag); +} + +template +void test_ALU_mull_gadget(const size_t w) +{ + print_time("starting mull test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_MULL, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_umul_gadget* { + pb_variable umulh_result; umulh_result.allocate(pb, "umulh_result"); + pb_variable umulh_flag; umulh_flag.allocate(pb, "umulh_flag"); + return new ALU_umul_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + result, result_flag, + umulh_result, umulh_flag, + "ALU_umul_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return (x*y) % (1ul< bool { + return ((x*y) >> w) != 0; + }); + print_time("mull tests successful"); +} + +template +void test_ALU_umulh_gadget(const size_t w) +{ + print_time("starting umulh test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_UMULH, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_umul_gadget* { + pb_variable mull_result; mull_result.allocate(pb, "mull_result"); + pb_variable mull_flag; mull_flag.allocate(pb, "mull_flag"); + return new ALU_umul_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + mull_result, mull_flag, + result, result_flag, + "ALU_umul_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return (x*y) >> w; }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { + return ((x*y) >> w) != 0; + }); + print_time("umulh tests successful"); +} + +template +void ALU_smul_gadget::generate_r1cs_constraints() +{ + /* do multiplication */ + /* + from two's complement: (packed - 2^w * bits[w-1]) + to two's complement: lower order bits of 2^{2w} + result_of_* + */ + + linear_combination a, b, c; + a.add_term(this->arg1val.packed, 1); + a.add_term(this->arg1val.bits[this->pb.ap.w-1], -(FieldT(2)^this->pb.ap.w)); + b.add_term(this->arg2val.packed, 1); + b.add_term(this->arg2val.bits[this->pb.ap.w-1], -(FieldT(2)^this->pb.ap.w)); + c.add_term(mul_result.packed, 1); + c.add_term(ONE, -(FieldT(2)^(2*this->pb.ap.w))); + this->pb.add_r1cs_constraint(r1cs_constraint(a, b, c), FMT(this->annotation_prefix, " main_constraint")); + + mul_result.generate_r1cs_constraints(true); + + /* pack result */ + pack_smulh_result->generate_r1cs_constraints(false); + + /* compute flag */ + pack_top->generate_r1cs_constraints(false); + + /* + the gadgets below are FieldT specific: + I * X = (1-R) + R * X = 0 + + if X = 0 then R = 1 + if X != 0 then R = 0 and I = X^{-1} + */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { is_top_empty_aux }, + { top }, + { ONE, is_top_empty * (-1) }), + FMT(this->annotation_prefix, " I*X=1-R (is_top_empty)")); + this->pb.add_r1cs_constraint( + r1cs_constraint( + { is_top_empty }, + { top }, + { ONE * 0 }), + FMT(this->annotation_prefix, " R*X=0 (is_top_full)")); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + { is_top_full_aux }, + { top, ONE * (1l-(1ul<<(this->pb.ap.w+1))) }, + { ONE, is_top_full * (-1) }), + FMT(this->annotation_prefix, " I*X=1-R (is_top_full)")); + this->pb.add_r1cs_constraint( + r1cs_constraint( + { is_top_full }, + { top, ONE * (1l-(1ul<<(this->pb.ap.w+1))) }, + { ONE * 0 }), + FMT(this->annotation_prefix, " R*X=0 (is_top_full)")); + + /* smulh_flag = 1 - (is_top_full + is_top_empty) */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { ONE, is_top_full * (-1), is_top_empty * (-1) }, + { smulh_flag }), + FMT(this->annotation_prefix, " smulh_flag")); +} + +template +void ALU_smul_gadget::generate_r1cs_witness() +{ + /* do multiplication */ + /* + from two's complement: (packed - 2^w * bits[w-1]) + to two's complement: lower order bits of (2^{2w} + result_of_mul) + */ + this->pb.val(mul_result.packed) = + (this->pb.val(this->arg1val.packed) - (this->pb.val(this->arg1val.bits[this->pb.ap.w-1])*(FieldT(2)^this->pb.ap.w))) * + (this->pb.val(this->arg2val.packed) - (this->pb.val(this->arg2val.bits[this->pb.ap.w-1])*(FieldT(2)^this->pb.ap.w))) + + (FieldT(2)^(2*this->pb.ap.w)); + + mul_result.generate_r1cs_witness_from_packed(); + + /* pack result */ + pack_smulh_result->generate_r1cs_witness_from_bits(); + + /* compute flag */ + pack_top->generate_r1cs_witness_from_bits(); + size_t topval = this->pb.val(top).as_ulong(); + + if (topval == 0) + { + this->pb.val(is_top_empty) = FieldT::one(); + this->pb.val(is_top_empty_aux) = FieldT::zero(); + } + else + { + this->pb.val(is_top_empty) = FieldT::zero(); + this->pb.val(is_top_empty_aux) = this->pb.val(top).inverse(); + } + + if (topval == ((1ul<<(this->pb.ap.w+1))-1)) + { + this->pb.val(is_top_full) = FieldT::one(); + this->pb.val(is_top_full_aux) = FieldT::zero(); + } + else + { + this->pb.val(is_top_full) = FieldT::zero(); + this->pb.val(is_top_full_aux) = (this->pb.val(top)-FieldT((1ul<<(this->pb.ap.w+1))-1)).inverse(); + } + + /* smulh_flag = 1 - (is_top_full + is_top_empty) */ + this->pb.val(smulh_flag) = FieldT::one() - (this->pb.val(is_top_full) + this->pb.val(is_top_empty)); +} + +template +void test_ALU_smulh_gadget(const size_t w) +{ + print_time("starting smulh test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_SMULH, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_smul_gadget* { + return new ALU_smul_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + result, result_flag, + "ALU_smul_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { + const size_t res = to_twos_complement((from_twos_complement(x, w) * from_twos_complement(y, w)), 2*w); + return res >> w; + }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { + const int res = from_twos_complement(x, w) * from_twos_complement(y, w); + const int truncated_res = from_twos_complement(to_twos_complement(res, 2*w) & ((1ul< +void ALU_divmod_gadget::generate_r1cs_constraints() +{ + /* B_inv * B = B_nonzero */ + linear_combination a1, b1, c1; + a1.add_term(B_inv, 1); + b1.add_term(this->arg2val.packed, 1); + c1.add_term(B_nonzero, 1); + + this->pb.add_r1cs_constraint(r1cs_constraint(a1, b1, c1), FMT(this->annotation_prefix, " B_inv*B=B_nonzero")); + + /* (1-B_nonzero) * B = 0 */ + linear_combination a2, b2, c2; + a2.add_term(ONE, 1); + a2.add_term(B_nonzero, -1); + b2.add_term(this->arg2val.packed, 1); + c2.add_term(ONE, 0); + + this->pb.add_r1cs_constraint(r1cs_constraint(a2, b2, c2), FMT(this->annotation_prefix, " (1-B_nonzero)*B=0")); + + /* B * q + r = A_aux = A * B_nonzero */ + linear_combination a3, b3, c3; + a3.add_term(this->arg2val.packed, 1); + b3.add_term(udiv_result, 1); + c3.add_term(A_aux, 1); + c3.add_term(umod_result, -1); + + this->pb.add_r1cs_constraint(r1cs_constraint(a3, b3, c3), FMT(this->annotation_prefix, " B*q+r=A_aux")); + + linear_combination a4, b4, c4; + a4.add_term(this->arg1val.packed, 1); + b4.add_term(B_nonzero, 1); + c4.add_term(A_aux, 1); + + this->pb.add_r1cs_constraint(r1cs_constraint(a4, b4, c4), FMT(this->annotation_prefix, " A_aux=A*B_nonzero")); + + /* q * (1-B_nonzero) = 0 */ + linear_combination a5, b5, c5; + a5.add_term(udiv_result, 1); + b5.add_term(ONE, 1); + b5.add_term(B_nonzero, -1); + c5.add_term(ONE, 0); + + this->pb.add_r1cs_constraint(r1cs_constraint(a5, b5, c5), FMT(this->annotation_prefix, " q*B_nonzero=0")); + + /* A(B, r, less=B_nonzero, leq=ONE) */ + r_less_B->generate_r1cs_constraints(); +} + +template +void ALU_divmod_gadget::generate_r1cs_witness() +{ + if (this->pb.val(this->arg2val.packed) == FieldT::zero()) + { + this->pb.val(B_inv) = FieldT::zero(); + this->pb.val(B_nonzero) = FieldT::zero(); + + this->pb.val(A_aux) = FieldT::zero(); + + this->pb.val(udiv_result) = FieldT::zero(); + this->pb.val(umod_result) = FieldT::zero(); + + this->pb.val(udiv_flag) = FieldT::one(); + this->pb.val(umod_flag) = FieldT::one(); + } + else + { + this->pb.val(B_inv) = this->pb.val(this->arg2val.packed).inverse(); + this->pb.val(B_nonzero) = FieldT::one(); + + const size_t A = this->pb.val(this->arg1val.packed).as_ulong(); + const size_t B = this->pb.val(this->arg2val.packed).as_ulong(); + + this->pb.val(A_aux) = this->pb.val(this->arg1val.packed); + + this->pb.val(udiv_result) = FieldT(A / B); + this->pb.val(umod_result) = FieldT(A % B); + + this->pb.val(udiv_flag) = FieldT::zero(); + this->pb.val(umod_flag) = FieldT::zero(); + } + + r_less_B->generate_r1cs_witness(); +} + +template +void test_ALU_udiv_gadget(const size_t w) +{ + print_time("starting udiv test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_UDIV, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_divmod_gadget* { + pb_variable umod_result; umod_result.allocate(pb, "umod_result"); + pb_variable umod_flag; umod_flag.allocate(pb, "umod_flag"); + return new ALU_divmod_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + result, result_flag, + umod_result, umod_flag, + "ALU_divmod_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { + return (y == 0 ? 0 : x / y); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { + return (y == 0); + }); + print_time("udiv tests successful"); +} + +template +void test_ALU_umod_gadget(const size_t w) +{ + print_time("starting umod test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_UMOD, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_divmod_gadget* { + pb_variable udiv_result; udiv_result.allocate(pb, "udiv_result"); + pb_variable udiv_flag; udiv_flag.allocate(pb, "udiv_flag"); + return new ALU_divmod_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + udiv_result, udiv_flag, + result, result_flag, + "ALU_divmod_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { + return (y == 0 ? 0 : x % y); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { + return (y == 0); + }); + print_time("umod tests successful"); +} + +template +void ALU_shr_shl_gadget::generate_r1cs_constraints() +{ + /* + select the input for barrel shifter: + + r = arg1val * opcode_indicators[SHR] + reverse(arg1val) * (1-opcode_indicators[SHR]) + r - reverse(arg1val) = (arg1val - reverse(arg1val)) * opcode_indicators[SHR] + */ + pack_reversed_input->generate_r1cs_constraints(false); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + { this->arg1val.packed, reversed_input * (-1) }, + { this->opcode_indicators[tinyram_opcode_SHR] }, + { barrel_right_internal[0], reversed_input * (-1) }), + FMT(this->annotation_prefix, " select_arg1val_or_reversed")); + + /* + do logw iterations of barrel shifts + */ + for (size_t i = 0; i < logw; ++i) + { + /* assert that shifted out part is bits */ + for (size_t j = 0; j < 1ul<(this->pb, shifted_out_bits[i][j], FMT(this->annotation_prefix, " shifted_out_bits_%zu_%zu", i, j)); + } + + /* + add main shifting constraint + + + old_result = + (shifted_result * 2^(i+1) + shifted_out_part) * need_to_shift + + (shfited_result) * (1-need_to_shift) + + old_result - shifted_result = (shifted_result * (2^(i+1) - 1) + shifted_out_part) * need_to_shift + */ + linear_combination a, b, c; + + a.add_term(barrel_right_internal[i+1], (FieldT(2)^(i+1)) - FieldT::one()); + for (size_t j = 0; j < 1ul<arg2val.bits[i], 1); + + c.add_term(barrel_right_internal[i], 1); + c.add_term(barrel_right_internal[i+1], -1); + + this->pb.add_r1cs_constraint(r1cs_constraint(a, b, c), FMT(this->annotation_prefix, " barrel_shift_%zu", i)); + } + + /* + get result as the logw iterations or zero if shift was oversized + + result = (1-is_oversize_shift) * barrel_right_internal[logw] + */ + check_oversize_shift->generate_r1cs_constraints(); + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE, is_oversize_shift * (-1) }, + { barrel_right_internal[logw] }, + { this->result }), + FMT(this->annotation_prefix, " result")); + + /* + get reversed result for SHL + */ + unpack_result->generate_r1cs_constraints(true); + pack_reversed_result->generate_r1cs_constraints(false); + + /* + select the correct output: + r = result * opcode_indicators[SHR] + reverse(result) * (1-opcode_indicators[SHR]) + r - reverse(result) = (result - reverse(result)) * opcode_indicators[SHR] + */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { this->result, reversed_result * (-1) }, + { this->opcode_indicators[tinyram_opcode_SHR] }, + { shr_result, reversed_result * (-1) }), + FMT(this->annotation_prefix, " shr_result")); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + { this->result, reversed_result * (-1) }, + { this->opcode_indicators[tinyram_opcode_SHR] }, + { shr_result, reversed_result * (-1) }), + FMT(this->annotation_prefix, " shl_result")); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->arg1val.bits[0] }, + { shr_flag }), + FMT(this->annotation_prefix, " shr_flag")); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->arg1val.bits[this->pb.ap.w-1] }, + { shl_flag }), + FMT(this->annotation_prefix, " shl_flag")); +} + +template +void ALU_shr_shl_gadget::generate_r1cs_witness() +{ + /* select the input for barrel shifter */ + pack_reversed_input->generate_r1cs_witness_from_bits(); + + this->pb.val(barrel_right_internal[0]) = + (this->pb.val(this->opcode_indicators[tinyram_opcode_SHR]) == FieldT::one() ? + this->pb.val(this->arg1val.packed) : this->pb.val(reversed_input)); + + /* + do logw iterations of barrel shifts. + + old_result = + (shifted_result * 2^i + shifted_out_part) * need_to_shift + + (shfited_result) * (1-need_to_shift) + */ + + for (size_t i = 0; i < logw; ++i) + { + this->pb.val(barrel_right_internal[i+1]) = + (this->pb.val(this->arg2val.bits[i]) == FieldT::zero()) ? this->pb.val(barrel_right_internal[i]) : + FieldT(this->pb.val(barrel_right_internal[i]).as_ulong() >> (i+1)); + + shifted_out_bits[i].fill_with_bits_of_ulong(this->pb, this->pb.val(barrel_right_internal[i]).as_ulong() % (2u<generate_r1cs_witness(); + this->pb.val(this->result) = (FieldT::one() - this->pb.val(is_oversize_shift)) * this->pb.val(barrel_right_internal[logw]); + + /* + get reversed result for SHL + */ + unpack_result->generate_r1cs_witness_from_packed(); + pack_reversed_result->generate_r1cs_witness_from_bits(); + + /* + select the correct output: + r = result * opcode_indicators[SHR] + reverse(result) * (1-opcode_indicators[SHR]) + r - reverse(result) = (result - reverse(result)) * opcode_indicators[SHR] + */ + this->pb.val(shr_result) = (this->pb.val(this->opcode_indicators[tinyram_opcode_SHR]) == FieldT::one()) ? + this->pb.val(this->result) : this->pb.val(reversed_result); + + this->pb.val(shl_result) = this->pb.val(shr_result); + this->pb.val(shr_flag) = this->pb.val(this->arg1val.bits[0]); + this->pb.val(shl_flag) = this->pb.val(this->arg1val.bits[this->pb.ap.w-1]); +} + +template +void test_ALU_shr_gadget(const size_t w) +{ + print_time("starting shr test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_SHR, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_shr_shl_gadget* { + pb_variable shl_result; shl_result.allocate(pb, "shl_result"); + pb_variable shl_flag; shl_flag.allocate(pb, "shl_flag"); + return new ALU_shr_shl_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + result, result_flag, + shl_result, shl_flag, + "ALU_shr_shl_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { + return (x >> y); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { + return (x & 1); + }); + print_time("shr tests successful"); +} + +template +void test_ALU_shl_gadget(const size_t w) +{ + print_time("starting shl test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_SHL, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_shr_shl_gadget* { + pb_variable shr_result; shr_result.allocate(pb, "shr_result"); + pb_variable shr_flag; shr_flag.allocate(pb, "shr_flag"); + return new ALU_shr_shl_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + shr_result, shr_flag, + result, result_flag, + "ALU_shr_shl_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { + return (x << y) & ((1ul< bool { + return (x >> (w-1)); + }); + print_time("shl tests successful"); +} + +} // libsnark + +#endif diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_control_flow.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_control_flow.hpp new file mode 100644 index 0000000..9287825 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_control_flow.hpp @@ -0,0 +1,102 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the TinyRAM ALU control-flow gadgets. + + These gadget check the correct execution of control-flow TinyRAM instructions. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALU_CONTROL_FLOW_HPP_ +#define ALU_CONTROL_FLOW_HPP_ + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.hpp" +#include "gadgetlib1/gadgets/basic_gadgets.hpp" + +namespace libsnark { + +/* control flow gadgets */ +template +class ALU_control_flow_gadget : public tinyram_standard_gadget { +public: + const word_variable_gadget pc; + const word_variable_gadget argval2; + const pb_variable flag; + const pb_variable result; + + ALU_control_flow_gadget(tinyram_protoboard &pb, + const word_variable_gadget &pc, + const word_variable_gadget &argval2, + const pb_variable &flag, + const pb_variable &result, + const std::string &annotation_prefix="") : + tinyram_standard_gadget(pb, annotation_prefix), + pc(pc), + argval2(argval2), + flag(flag), + result(result) {}; +}; + +template +class ALU_jmp_gadget : public ALU_control_flow_gadget { +public: + ALU_jmp_gadget(tinyram_protoboard &pb, + const word_variable_gadget &pc, + const word_variable_gadget &argval2, + const pb_variable &flag, + const pb_variable &result, + const std::string &annotation_prefix="") : + ALU_control_flow_gadget(pb, pc, argval2, flag, result, annotation_prefix) {} + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_jmp_gadget(); + +template +class ALU_cjmp_gadget : public ALU_control_flow_gadget { +public: + ALU_cjmp_gadget(tinyram_protoboard &pb, + const word_variable_gadget &pc, + const word_variable_gadget &argval2, + const pb_variable &flag, + const pb_variable &result, + const std::string &annotation_prefix="") : + ALU_control_flow_gadget(pb, pc, argval2, flag, result, annotation_prefix) {} + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_cjmp_gadget(); + +template +class ALU_cnjmp_gadget : public ALU_control_flow_gadget { +public: + ALU_cnjmp_gadget(tinyram_protoboard &pb, + const word_variable_gadget &pc, + const word_variable_gadget &argval2, + const pb_variable &flag, + const pb_variable &result, + const std::string &annotation_prefix="") : + ALU_control_flow_gadget(pb, pc, argval2, flag, result, annotation_prefix) {} + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_cnjmp_gadget(); + +} // libsnark + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_control_flow.tcc" + +#endif // ALU_CONTROL_FLOW_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_control_flow.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_control_flow.tcc new file mode 100644 index 0000000..606d0b2 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_control_flow.tcc @@ -0,0 +1,233 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the TinyRAM ALU control-flow gadgets. + + See alu_control_flow.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALU_CONTROL_FLOW_TCC_ +#define ALU_CONTROL_FLOW_TCC_ + +#include "common/profiling.hpp" + +namespace libsnark { + +/* jmp */ +template +void ALU_jmp_gadget::generate_r1cs_constraints() +{ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->argval2.packed }, + { this->result }), + FMT(this->annotation_prefix, " jmp_result")); +} + +template +void ALU_jmp_gadget::generate_r1cs_witness() +{ + this->pb.val(this->result) = this->pb.val(this->argval2.packed); +} + +template +void test_ALU_jmp_gadget() +{ + print_time("starting jmp test"); + + tinyram_architecture_params ap(16, 16); + tinyram_program P; P.instructions = generate_tinyram_prelude(ap); + tinyram_protoboard pb(ap, P.size(), 0, 10); + + word_variable_gadget pc(pb, "pc"), argval2(pb, "argval2"); + pb_variable flag, result; + + pc.generate_r1cs_constraints(true); + argval2.generate_r1cs_constraints(true); + flag.allocate(pb, "flag"); + result.allocate(pb, "result"); + + ALU_jmp_gadget jmp(pb, pc, argval2, flag, result, "jmp"); + jmp.generate_r1cs_constraints(); + + pb.val(argval2.packed) = FieldT(123); + argval2.generate_r1cs_witness_from_packed(); + + jmp.generate_r1cs_witness(); + + assert(pb.val(result) == FieldT(123)); + assert(pb.is_satisfied()); + print_time("positive jmp test successful"); + + pb.val(result) = FieldT(1); + assert(!pb.is_satisfied()); + print_time("negative jmp test successful"); +} + +/* cjmp */ +template +void ALU_cjmp_gadget::generate_r1cs_constraints() +{ + /* + flag1 * argval2 + (1-flag1) * (pc1 + 1) = cjmp_result + flag1 * (argval2 - pc1 - 1) = cjmp_result - pc1 - 1 + + Note that instruction fetch semantics require program counter to + be aligned to the double word by rounding down, and pc_addr in + the outer reduction is expressed as a double word address. To + achieve this we just discard the first ap.subaddr_len() bits of + the byte address of the PC. + */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + this->flag, + pb_packing_sum(pb_variable_array(this->argval2.bits.begin() + this->pb.ap.subaddr_len(), this->argval2.bits.end())) - this->pc.packed - 1, + this->result - this->pc.packed - 1), + FMT(this->annotation_prefix, " cjmp_result")); +} + +template +void ALU_cjmp_gadget::generate_r1cs_witness() +{ + this->pb.val(this->result) = ((this->pb.val(this->flag) == FieldT::one()) ? + FieldT(this->pb.val(this->argval2.packed).as_ulong() >> this->pb.ap.subaddr_len()) : + this->pb.val(this->pc.packed) + FieldT::one()); +} + +template +void test_ALU_cjmp_gadget() +{ + // TODO: update + print_time("starting cjmp test"); + + tinyram_architecture_params ap(16, 16); + tinyram_program P; P.instructions = generate_tinyram_prelude(ap); + tinyram_protoboard pb(ap, P.size(), 0, 10); + + word_variable_gadget pc(pb, "pc"), argval2(pb, "argval2"); + pb_variable flag, result; + + pc.generate_r1cs_constraints(true); + argval2.generate_r1cs_constraints(true); + flag.allocate(pb, "flag"); + result.allocate(pb, "result"); + + ALU_cjmp_gadget cjmp(pb, pc, argval2, flag, result, "cjmp"); + cjmp.generate_r1cs_constraints(); + + pb.val(argval2.packed) = FieldT(123); + argval2.generate_r1cs_witness_from_packed(); + pb.val(pc.packed) = FieldT(456); + pc.generate_r1cs_witness_from_packed(); + + pb.val(flag) = FieldT(1); + cjmp.generate_r1cs_witness(); + + assert(pb.val(result) == FieldT(123)); + assert(pb.is_satisfied()); + print_time("positive cjmp test successful"); + + pb.val(flag) = FieldT(0); + assert(!pb.is_satisfied()); + print_time("negative cjmp test successful"); + + pb.val(flag) = FieldT(0); + cjmp.generate_r1cs_witness(); + + assert(pb.val(result) == FieldT(456+2*ap.w/8)); + assert(pb.is_satisfied()); + print_time("positive cjmp test successful"); + + pb.val(flag) = FieldT(1); + assert(!pb.is_satisfied()); + print_time("negative cjmp test successful"); +} + +/* cnjmp */ +template +void ALU_cnjmp_gadget::generate_r1cs_constraints() +{ + /* + flag1 * (pc1 + inc) + (1-flag1) * argval2 = cnjmp_result + flag1 * (pc1 + inc - argval2) = cnjmp_result - argval2 + + Note that instruction fetch semantics require program counter to + be aligned to the double word by rounding down, and pc_addr in + the outer reduction is expressed as a double word address. To + achieve this we just discard the first ap.subaddr_len() bits of + the byte address of the PC. + */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + this->flag, + this->pc.packed + 1 - pb_packing_sum(pb_variable_array(this->argval2.bits.begin() + this->pb.ap.subaddr_len(), this->argval2.bits.end())), + this->result - pb_packing_sum(pb_variable_array(this->argval2.bits.begin() + this->pb.ap.subaddr_len(), this->argval2.bits.end()))), + FMT(this->annotation_prefix, " cnjmp_result")); +} + +template +void ALU_cnjmp_gadget::generate_r1cs_witness() +{ + this->pb.val(this->result) = ((this->pb.val(this->flag) == FieldT::one()) ? + this->pb.val(this->pc.packed) + FieldT::one() : + FieldT(this->pb.val(this->argval2.packed).as_ulong() >> this->pb.ap.subaddr_len())); +} + +template +void test_ALU_cnjmp_gadget() +{ + // TODO: update + print_time("starting cnjmp test"); + + tinyram_architecture_params ap(16, 16); + tinyram_program P; P.instructions = generate_tinyram_prelude(ap); + tinyram_protoboard pb(ap, P.size(), 0, 10); + + word_variable_gadget pc(pb, "pc"), argval2(pb, "argval2"); + pb_variable flag, result; + + pc.generate_r1cs_constraints(true); + argval2.generate_r1cs_constraints(true); + flag.allocate(pb, "flag"); + result.allocate(pb, "result"); + + ALU_cnjmp_gadget cnjmp(pb, pc, argval2, flag, result, "cjmp"); + cnjmp.generate_r1cs_constraints(); + + pb.val(argval2.packed) = FieldT(123); + argval2.generate_r1cs_witness_from_packed(); + pb.val(pc.packed) = FieldT(456); + pc.generate_r1cs_witness_from_packed(); + + pb.val(flag) = FieldT(0); + cnjmp.generate_r1cs_witness(); + + assert(pb.val(result) == FieldT(123)); + assert(pb.is_satisfied()); + print_time("positive cnjmp test successful"); + + pb.val(flag) = FieldT(1); + assert(!pb.is_satisfied()); + print_time("negative cnjmp test successful"); + + pb.val(flag) = FieldT(1); + cnjmp.generate_r1cs_witness(); + + assert(pb.val(result) == FieldT(456 + (2*pb.ap.w/8))); + assert(pb.is_satisfied()); + print_time("positive cnjmp test successful"); + + pb.val(flag) = FieldT(0); + assert(!pb.is_satisfied()); + print_time("negative cnjmp test successful"); +} + +} // libsnark + +#endif // ALU_CONTROL_FLOW_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_gadget.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_gadget.hpp new file mode 100644 index 0000000..8466fe0 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_gadget.hpp @@ -0,0 +1,183 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the TinyRAM ALU gadget. + + The gadget checks the correct execution of a given TinyRAM instruction. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALU_GADGET_HPP_ +#define ALU_GADGET_HPP_ + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_arithmetic.hpp" +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_control_flow.hpp" + +namespace libsnark { + +template +class ALU_gadget : public tinyram_standard_gadget { +private: + std::vector > > components; +public: + pb_variable_array opcode_indicators; + word_variable_gadget pc; + word_variable_gadget desval; + word_variable_gadget arg1val; + word_variable_gadget arg2val; + pb_variable flag; + pb_variable_array instruction_results; + pb_variable_array instruction_flags; + + ALU_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &pc, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable_array &instruction_results, + const pb_variable_array &instruction_flags, + const std::string &annotation_prefix="") : + tinyram_standard_gadget(pb, annotation_prefix), + opcode_indicators(opcode_indicators), + pc(pc), + desval(desval), + arg1val(arg1val), + arg2val(arg2val), + flag(flag), + instruction_results(instruction_results), + instruction_flags(instruction_flags) + { + components.resize(1ul<(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_AND], + instruction_flags[tinyram_opcode_AND], + FMT(this->annotation_prefix, " AND"))); + + components[tinyram_opcode_OR].reset( + new ALU_or_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_OR], + instruction_flags[tinyram_opcode_OR], + FMT(this->annotation_prefix, " OR"))); + + components[tinyram_opcode_XOR].reset( + new ALU_xor_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_XOR], + instruction_flags[tinyram_opcode_XOR], + FMT(this->annotation_prefix, " XOR"))); + + components[tinyram_opcode_NOT].reset( + new ALU_not_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_NOT], + instruction_flags[tinyram_opcode_NOT], + FMT(this->annotation_prefix, " NOT"))); + + components[tinyram_opcode_ADD].reset( + new ALU_add_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_ADD], + instruction_flags[tinyram_opcode_ADD], + FMT(this->annotation_prefix, " ADD"))); + + components[tinyram_opcode_SUB].reset( + new ALU_sub_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_SUB], + instruction_flags[tinyram_opcode_SUB], + FMT(this->annotation_prefix, " SUB"))); + + components[tinyram_opcode_MOV].reset( + new ALU_mov_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_MOV], + instruction_flags[tinyram_opcode_MOV], + FMT(this->annotation_prefix, " MOV"))); + + components[tinyram_opcode_CMOV].reset( + new ALU_cmov_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_CMOV], + instruction_flags[tinyram_opcode_CMOV], + FMT(this->annotation_prefix, " CMOV"))); + + components[tinyram_opcode_CMPA].reset( + new ALU_cmp_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_CMPE], + instruction_flags[tinyram_opcode_CMPE], + instruction_results[tinyram_opcode_CMPA], + instruction_flags[tinyram_opcode_CMPA], + instruction_results[tinyram_opcode_CMPAE], + instruction_flags[tinyram_opcode_CMPAE], + FMT(this->annotation_prefix, " CMP_unsigned"))); + + components[tinyram_opcode_CMPG].reset( + new ALU_cmps_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_CMPG], + instruction_flags[tinyram_opcode_CMPG], + instruction_results[tinyram_opcode_CMPGE], + instruction_flags[tinyram_opcode_CMPGE], + FMT(this->annotation_prefix, " CMP_signed"))); + + components[tinyram_opcode_UMULH].reset( + new ALU_umul_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_MULL], + instruction_flags[tinyram_opcode_MULL], + instruction_results[tinyram_opcode_UMULH], + instruction_flags[tinyram_opcode_UMULH], + FMT(this->annotation_prefix, " MUL_unsigned"))); + + components[tinyram_opcode_SMULH].reset( + new ALU_smul_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_SMULH], + instruction_flags[tinyram_opcode_SMULH], + FMT(this->annotation_prefix, " MUL_signed"))); + + + components[tinyram_opcode_UDIV].reset( + new ALU_divmod_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_UDIV], + instruction_flags[tinyram_opcode_UDIV], + instruction_results[tinyram_opcode_UMOD], + instruction_flags[tinyram_opcode_UMOD], + FMT(this->annotation_prefix, " DIV"))); + + components[tinyram_opcode_SHR].reset( + new ALU_shr_shl_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_SHR], + instruction_flags[tinyram_opcode_SHR], + instruction_results[tinyram_opcode_SHL], + instruction_flags[tinyram_opcode_SHL], + FMT(this->annotation_prefix, " SHR_SHL"))); + + /* control flow */ + components[tinyram_opcode_JMP].reset( + new ALU_jmp_gadget(pb, pc, arg2val, flag, + instruction_results[tinyram_opcode_JMP], + FMT(this->annotation_prefix, " JMP"))); + + components[tinyram_opcode_CJMP].reset( + new ALU_cjmp_gadget(pb, pc, arg2val, flag, + instruction_results[tinyram_opcode_CJMP], + FMT(this->annotation_prefix, " CJMP"))); + + components[tinyram_opcode_CNJMP].reset( + new ALU_cnjmp_gadget(pb, pc, arg2val, flag, + instruction_results[tinyram_opcode_CNJMP], + FMT(this->annotation_prefix, " CNJMP"))); + } + + void generate_r1cs_constraints(); + + void generate_r1cs_witness(); + +}; + +} // libsnark + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_gadget.tcc" + +#endif // ALU_GADGET_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_gadget.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_gadget.tcc new file mode 100644 index 0000000..b5826a6 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_gadget.tcc @@ -0,0 +1,45 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the TinyRAM ALU gadget. + + See alu.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALU_GADGET_TCC_ +#define ALU_GADGET_TCC_ + +namespace libsnark { + +template +void ALU_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < 1ul<pb.ap.opcode_width(); ++i) + { + if (components[i]) + { + components[i]->generate_r1cs_constraints(); + } + } +} + +template +void ALU_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < 1ul<pb.ap.opcode_width(); ++i) + { + if (components[i]) + { + components[i]->generate_r1cs_witness(); + } + } +} + +} // libsnark + +#endif // ALU_GADGET_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/argument_decoder_gadget.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/argument_decoder_gadget.hpp new file mode 100644 index 0000000..5f6f0e8 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/argument_decoder_gadget.hpp @@ -0,0 +1,66 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the TinyRAM argument decoder gadget. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ARGUMENT_DECODER_GADGET_HPP_ +#define ARGUMENT_DECODER_GADGET_HPP_ + +namespace libsnark { + +template +class argument_decoder_gadget : public tinyram_standard_gadget { +private: + pb_variable packed_desidx; + pb_variable packed_arg1idx; + pb_variable packed_arg2idx; + + std::shared_ptr > pack_desidx; + std::shared_ptr > pack_arg1idx; + std::shared_ptr > pack_arg2idx; + + pb_variable arg2_demux_result; + pb_variable arg2_demux_success; + + std::shared_ptr > demux_des; + std::shared_ptr > demux_arg1; + std::shared_ptr > demux_arg2; +public: + pb_variable arg2_is_imm; + pb_variable_array desidx; + pb_variable_array arg1idx; + pb_variable_array arg2idx; + pb_variable_array packed_registers; + pb_variable packed_desval; + pb_variable packed_arg1val; + pb_variable packed_arg2val; + + argument_decoder_gadget(tinyram_protoboard &pb, + const pb_variable &arg2_is_imm, + const pb_variable_array &desidx, + const pb_variable_array &arg1idx, + const pb_variable_array &arg2idx, + const pb_variable_array &packed_registers, + const pb_variable &packed_desval, + const pb_variable &packed_arg1val, + const pb_variable &packed_arg2val, + const std::string &annotation_prefix=""); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_argument_decoder_gadget(); + +} // libsnark + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/argument_decoder_gadget.tcc" + +#endif // ARGUMENT_DECODER_GADGET_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/argument_decoder_gadget.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/argument_decoder_gadget.tcc new file mode 100644 index 0000000..ecaa8e5 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/argument_decoder_gadget.tcc @@ -0,0 +1,187 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the TinyRAM argument decoder gadget. + + See argument_decoder_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ARGUMENT_DECODER_GADGET_TCC_ +#define ARGUMENT_DECODER_GADGET_TCC_ + +namespace libsnark { + +template +argument_decoder_gadget::argument_decoder_gadget(tinyram_protoboard &pb, + const pb_variable &arg2_is_imm, + const pb_variable_array &desidx, + const pb_variable_array &arg1idx, + const pb_variable_array &arg2idx, + const pb_variable_array &packed_registers, + const pb_variable &packed_desval, + const pb_variable &packed_arg1val, + const pb_variable &packed_arg2val, + const std::string &annotation_prefix) : + tinyram_standard_gadget(pb, annotation_prefix), + arg2_is_imm(arg2_is_imm), + desidx(desidx), + arg1idx(arg1idx), + arg2idx(arg2idx), + packed_registers(packed_registers), + packed_desval(packed_desval), + packed_arg1val(packed_arg1val), + packed_arg2val(packed_arg2val) +{ + assert(desidx.size() == pb.ap.reg_arg_width()); + assert(arg1idx.size() == pb.ap.reg_arg_width()); + assert(arg2idx.size() == pb.ap.reg_arg_or_imm_width()); + + /* decode accordingly */ + packed_desidx.allocate(pb, FMT(this->annotation_prefix, " packed_desidx")); + packed_arg1idx.allocate(pb, FMT(this->annotation_prefix, " packed_arg1idx")); + packed_arg2idx.allocate(pb, FMT(this->annotation_prefix, " packed_arg2idx")); + + pack_desidx.reset(new packing_gadget(pb, desidx, packed_desidx, FMT(this->annotation_prefix, "pack_desidx"))); + pack_arg1idx.reset(new packing_gadget(pb, arg1idx, packed_arg1idx, FMT(this->annotation_prefix, "pack_arg1idx"))); + pack_arg2idx.reset(new packing_gadget(pb, arg2idx, packed_arg2idx, FMT(this->annotation_prefix, "pack_arg2idx"))); + + arg2_demux_result.allocate(pb, FMT(this->annotation_prefix, " arg2_demux_result")); + arg2_demux_success.allocate(pb, FMT(this->annotation_prefix, " arg2_demux_success")); + + demux_des.reset( + new loose_multiplexing_gadget(pb, packed_registers, packed_desidx, packed_desval, ONE, + FMT(this->annotation_prefix, " demux_des"))); + demux_arg1.reset( + new loose_multiplexing_gadget(pb, packed_registers, packed_arg1idx, packed_arg1val, ONE, + FMT(this->annotation_prefix, " demux_arg1"))); + demux_arg2.reset( + new loose_multiplexing_gadget(pb, packed_registers, packed_arg2idx, arg2_demux_result, arg2_demux_success, + FMT(this->annotation_prefix, " demux_arg2"))); +} + +template +void argument_decoder_gadget::generate_r1cs_constraints() +{ + /* pack */ + pack_desidx->generate_r1cs_constraints(true); + pack_arg1idx->generate_r1cs_constraints(true); + pack_arg2idx->generate_r1cs_constraints(true); + + /* demux */ + demux_des->generate_r1cs_constraints(); + demux_arg1->generate_r1cs_constraints(); + demux_arg2->generate_r1cs_constraints(); + + /* enforce correct handling of arg2val */ + + /* it is false that arg2 is reg and demux failed: + (1 - arg2_is_imm) * (1 - arg2_demux_success) = 0 */ + this->pb.add_r1cs_constraint( + r1cs_constraint({ ONE, arg2_is_imm * (-1) }, + { ONE, arg2_demux_success * (-1) }, + { ONE * 0 }), + FMT(this->annotation_prefix, " ensure_correc_demux")); + + /* + arg2val = arg2_is_imm * packed_arg2idx + + (1 - arg2_is_imm) * arg2_demux_result + + arg2val - arg2_demux_result = arg2_is_imm * (packed_arg2idx - arg2_demux_result) + */ + this->pb.add_r1cs_constraint( + r1cs_constraint({ arg2_is_imm }, + { packed_arg2idx, arg2_demux_result * (-1) }, + { packed_arg2val, arg2_demux_result * (-1) }), + FMT(this->annotation_prefix, " compute_arg2val")); +} + +template +void argument_decoder_gadget::generate_r1cs_witness() +{ + /* pack */ + pack_desidx->generate_r1cs_witness_from_bits(); + pack_arg1idx->generate_r1cs_witness_from_bits(); + pack_arg2idx->generate_r1cs_witness_from_bits(); + + /* demux */ + demux_des->generate_r1cs_witness(); + demux_arg1->generate_r1cs_witness(); + demux_arg2->generate_r1cs_witness(); + + /* handle arg2val */ + this->pb.val(packed_arg2val) = + (this->pb.val(arg2_is_imm) == FieldT::one() ? + this->pb.val(packed_arg2idx) : this->pb.val(arg2_demux_result)); +} + +template +void test_argument_decoder_gadget() +{ + print_time("starting argument_decoder_gadget test"); + + tinyram_architecture_params ap(16, 16); + tinyram_program P; P.instructions = generate_tinyram_prelude(ap); + tinyram_protoboard pb(ap, P.size(), 0, 10); + + pb_variable_array packed_registers; + packed_registers.allocate(pb, ap.k, "packed_registers"); + + pb_variable arg2_is_imm; + arg2_is_imm.allocate(pb, "arg_is_imm"); + + dual_variable_gadget desidx(pb, ap.reg_arg_width(), "desidx"); + dual_variable_gadget arg1idx(pb, ap.reg_arg_width(), "arg1idx"); + dual_variable_gadget arg2idx(pb, ap.reg_arg_or_imm_width(), "arg2idx"); + + pb_variable packed_desval, packed_arg1val, packed_arg2val; + packed_desval.allocate(pb, "packed_desval"); + packed_arg1val.allocate(pb, "packed_arg1val"); + packed_arg2val.allocate(pb, "packed_arg2val"); + + argument_decoder_gadget g(pb, packed_registers, arg2_is_imm, + desidx.bits, arg1idx.bits, arg2idx.bits, + packed_desval, packed_arg1val, packed_arg2val, "g"); + + g.generate_r1cs_constraints(); + for (size_t i = 0; i < ap.k; ++i) + { + pb.val(packed_registers[i]) = FieldT(1000+i); + } + + pb.val(desidx.packed) = FieldT(2); + pb.val(arg1idx.packed) = FieldT(5); + pb.val(arg2idx.packed) = FieldT(7); + pb.val(arg2_is_imm) = FieldT::zero(); + + desidx.generate_r1cs_witness_from_packed(); + arg1idx.generate_r1cs_witness_from_packed(); + arg2idx.generate_r1cs_witness_from_packed(); + + g.generate_r1cs_witness(); + + assert(pb.val(packed_desval) == FieldT(1002)); + assert(pb.val(packed_arg1val) == FieldT(1005)); + assert(pb.val(packed_arg2val) == FieldT(1007)); + assert(pb.is_satisfied()); + printf("positive test (get reg) successful\n"); + + pb.val(arg2_is_imm) = FieldT::one(); + g.generate_r1cs_witness(); + + assert(pb.val(packed_desval) == FieldT(1002)); + assert(pb.val(packed_arg1val) == FieldT(1005)); + assert(pb.val(packed_arg2val) == FieldT(7)); + assert(pb.is_satisfied()); + printf("positive test (get imm) successful\n"); + + print_time("argument_decoder_gadget tests successful"); +} + +} // libsnark + +#endif // ARGUMENT_DECODER_GADGET_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/consistency_enforcer_gadget.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/consistency_enforcer_gadget.hpp new file mode 100644 index 0000000..fdf6c0a --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/consistency_enforcer_gadget.hpp @@ -0,0 +1,71 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the TinyRAM consistency enforcer gadget. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef CONSISTENCY_ENFORCER_GADGET_HPP_ +#define CONSISTENCY_ENFORCER_GADGET_HPP_ + +namespace libsnark { + +template +class consistency_enforcer_gadget : public tinyram_standard_gadget { +private: + pb_variable is_register_instruction; + pb_variable is_control_flow_instruction; + pb_variable is_stall_instruction; + + pb_variable packed_desidx; + std::shared_ptr > pack_desidx; + + pb_variable computed_result; + pb_variable computed_flag; + std::shared_ptr > compute_computed_result; + std::shared_ptr > compute_computed_flag; + + pb_variable pc_from_cf_or_zero; + + std::shared_ptr > demux_packed_outgoing_desval; +public: + pb_variable_array opcode_indicators; + pb_variable_array instruction_results; + pb_variable_array instruction_flags; + pb_variable_array desidx; + pb_variable packed_incoming_pc; + pb_variable_array packed_incoming_registers; + pb_variable packed_incoming_desval; + pb_variable incoming_flag; + pb_variable packed_outgoing_pc; + pb_variable_array packed_outgoing_registers; + pb_variable outgoing_flag; + pb_variable packed_outgoing_desval; + + consistency_enforcer_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const pb_variable_array &instruction_results, + const pb_variable_array &instruction_flags, + const pb_variable_array &desidx, + const pb_variable &packed_incoming_pc, + const pb_variable_array &packed_incoming_registers, + const pb_variable &packed_incoming_desval, + const pb_variable &incoming_flag, + const pb_variable &packed_outgoing_pc, + const pb_variable_array &packed_outgoing_registers, + const pb_variable &outgoing_flag, + const std::string &annotation_prefix=""); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/consistency_enforcer_gadget.tcc" + +#endif // CONSISTENCY_ENFORCER_GADGET_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/consistency_enforcer_gadget.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/consistency_enforcer_gadget.tcc new file mode 100644 index 0000000..9da062e --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/consistency_enforcer_gadget.tcc @@ -0,0 +1,604 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the TinyRAM consistency enforcer gadget. + + See consistency_enforcer_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef CONSISTENCY_ENFORCER_GADGET_TCC_ +#define CONSISTENCY_ENFORCER_GADGET_TCC_ + +namespace libsnark { + +template +consistency_enforcer_gadget::consistency_enforcer_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const pb_variable_array &instruction_results, + const pb_variable_array &instruction_flags, + const pb_variable_array &desidx, + const pb_variable &packed_incoming_pc, + const pb_variable_array &packed_incoming_registers, + const pb_variable &packed_incoming_desval, + const pb_variable &incoming_flag, + const pb_variable &packed_outgoing_pc, + const pb_variable_array &packed_outgoing_registers, + const pb_variable &outgoing_flag, + const std::string &annotation_prefix) : + tinyram_standard_gadget(pb, annotation_prefix), + opcode_indicators(opcode_indicators), + instruction_results(instruction_results), + instruction_flags(instruction_flags), + desidx(desidx), + packed_incoming_pc(packed_incoming_pc), + packed_incoming_registers(packed_incoming_registers), + packed_incoming_desval(packed_incoming_desval), + incoming_flag(incoming_flag), + packed_outgoing_pc(packed_outgoing_pc), + packed_outgoing_registers(packed_outgoing_registers), + outgoing_flag(outgoing_flag) +{ + assert(desidx.size() == pb.ap.reg_arg_width()); + + packed_outgoing_desval.allocate(pb, FMT(this->annotation_prefix, " packed_outgoing_desval")); + is_register_instruction.allocate(pb, FMT(this->annotation_prefix, " is_register_instruction")); + is_control_flow_instruction.allocate(pb, FMT(this->annotation_prefix, " is_control_flow_instruction")); + is_stall_instruction.allocate(pb, FMT(this->annotation_prefix, " is_stall_instruction")); + + packed_desidx.allocate(pb, FMT(this->annotation_prefix, " packed_desidx")); + pack_desidx.reset(new packing_gadget(pb, desidx, packed_desidx, FMT(this->annotation_prefix, "pack_desidx"))); + + computed_result.allocate(pb, FMT(this->annotation_prefix, " computed_result")); + computed_flag.allocate(pb, FMT(this->annotation_prefix, " computed_flag")); + + compute_computed_result.reset( + new inner_product_gadget(pb, opcode_indicators, instruction_results, computed_result, + FMT(this->annotation_prefix, " compute_computed_result"))); + compute_computed_flag.reset( + new inner_product_gadget(pb, opcode_indicators, instruction_flags, computed_flag, + FMT(this->annotation_prefix, " compute_computed_flag"))); + + pc_from_cf_or_zero.allocate(pb, FMT(this->annotation_prefix, " pc_from_cf_or_zero")); + + demux_packed_outgoing_desval.reset( + new loose_multiplexing_gadget(pb, packed_outgoing_registers, packed_desidx, packed_outgoing_desval, ONE, + FMT(this->annotation_prefix, " demux_packed_outgoing_desval"))); + +} + +template +void consistency_enforcer_gadget::generate_r1cs_constraints() +{ + /* pack destination index */ + pack_desidx->generate_r1cs_constraints(false); + + /* demux result register */ + demux_packed_outgoing_desval->generate_r1cs_constraints(); + + /* is_register_instruction */ + linear_combination reg_a, reg_b, reg_c; + reg_a.add_term(ONE, 1); + for (size_t i = 0; i < ARRAY_SIZE(tinyram_opcodes_register); ++i) + { + reg_b.add_term(opcode_indicators[tinyram_opcodes_register[i]], 1); + } + reg_c.add_term(is_register_instruction, 1); + this->pb.add_r1cs_constraint(r1cs_constraint(reg_a, reg_b, reg_c), FMT(this->annotation_prefix, " is_register_instruction")); + + /* is_control_flow_instruction */ + linear_combination cf_a, cf_b, cf_c; + cf_a.add_term(ONE, 1); + for (size_t i = 0; i < ARRAY_SIZE(tinyram_opcodes_control_flow); ++i) + { + cf_b.add_term(opcode_indicators[tinyram_opcodes_control_flow[i]], 1); + } + cf_c.add_term(is_control_flow_instruction, 1); + this->pb.add_r1cs_constraint(r1cs_constraint(cf_a, cf_b, cf_c), FMT(this->annotation_prefix, " is_control_flow_instruction")); + + /* is_stall_instruction */ + linear_combination stall_a, stall_b, stall_c; + stall_a.add_term(ONE, 1); + for (size_t i = 0; i < ARRAY_SIZE(tinyram_opcodes_stall); ++i) + { + stall_b.add_term(opcode_indicators[tinyram_opcodes_stall[i]], 1); + } + stall_c.add_term(is_stall_instruction, 1); + this->pb.add_r1cs_constraint(r1cs_constraint(stall_a, stall_b, stall_c), FMT(this->annotation_prefix, " is_stall_instruction")); + + /* compute actual result/actual flag */ + compute_computed_result->generate_r1cs_constraints(); + compute_computed_flag->generate_r1cs_constraints(); + + /* + compute new PC address (in double words, not bytes!): + + PC' = computed_result * is_control_flow_instruction + PC * is_stall_instruction + (PC+1) * (1-is_control_flow_instruction - is_stall_instruction) + PC' - pc_from_cf_or_zero - (1-is_control_flow_instruction - is_stall_instruction) = PC * (1 - is_control_flow_instruction) + */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + computed_result, + is_control_flow_instruction, + pc_from_cf_or_zero), + FMT(this->annotation_prefix, " pc_from_cf_or_zero")); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + packed_incoming_pc, + 1 - is_control_flow_instruction, + packed_outgoing_pc - pc_from_cf_or_zero - (1 - is_control_flow_instruction - is_stall_instruction)), + FMT(this->annotation_prefix, " packed_outgoing_pc")); + + /* + enforce new flag: + + flag' = computed_flag * is_register_instruction + flag * (1-is_register_instruction) + flag' - flag = (computed_flag - flag) * is_register_instruction + */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { computed_flag, incoming_flag * (-1) }, + { is_register_instruction }, + { outgoing_flag, incoming_flag * (-1) }), + FMT(this->annotation_prefix, " outgoing_flag")); + + /* + force carryover of unchanged registers + + (1-indicator) * (new-old) = 0 + + In order to save constraints we "borrow" indicator variables + from loose multiplexing gadget. + */ + for (size_t i = 0; i < this->pb.ap.k; ++i) + { + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE, demux_packed_outgoing_desval->alpha[i] * (-1) }, + { packed_outgoing_registers[i], packed_incoming_registers[i] * (-1) }, + { ONE * 0 }), + FMT(this->annotation_prefix, " register_carryover_%zu", i)); + } + + /* + enforce correct destination register value: + + next_desval = computed_result * is_register_instruction + packed_incoming_desval * (1-is_register_instruction) + next_desval - packed_incoming_desval = (computed_result - packed_incoming_desval) * is_register_instruction + */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { computed_result, packed_incoming_desval * (-1) }, + { is_register_instruction }, + { packed_outgoing_desval, packed_incoming_desval * (-1) }), + FMT(this->annotation_prefix, " packed_outgoing_desval")); +} + +template +void consistency_enforcer_gadget::generate_r1cs_witness() +{ + /* pack destination index */ + pack_desidx->generate_r1cs_witness_from_bits(); + + /* is_register_instruction */ + this->pb.val(is_register_instruction) = FieldT::zero(); + + for (size_t i = 0; i < ARRAY_SIZE(tinyram_opcodes_register); ++i) + { + this->pb.val(is_register_instruction) += this->pb.val(opcode_indicators[tinyram_opcodes_register[i]]); + } + + /* is_control_flow_instruction */ + this->pb.val(is_control_flow_instruction) = FieldT::zero(); + + for (size_t i = 0; i < ARRAY_SIZE(tinyram_opcodes_control_flow); ++i) + { + this->pb.val(is_control_flow_instruction) += this->pb.val(opcode_indicators[tinyram_opcodes_control_flow[i]]); + } + + /* is_stall_instruction */ + this->pb.val(is_stall_instruction) = FieldT::zero(); + + for (size_t i = 0; i < ARRAY_SIZE(tinyram_opcodes_stall); ++i) + { + this->pb.val(is_stall_instruction) += this->pb.val(opcode_indicators[tinyram_opcodes_stall[i]]); + } + + /* compute actual result/actual flag */ + compute_computed_result->generate_r1cs_witness(); + compute_computed_flag->generate_r1cs_witness(); + + /* + compute new PC address (in double words, not bytes!): + + PC' = computed_result * is_control_flow_instruction + PC * is_stall_instruction + (PC+1) * (1-is_control_flow_instruction - is_stall_instruction) + PC' - pc_from_cf_or_zero - (1-is_control_flow_instruction - is_stall_instruction) = PC * (1 - is_control_flow_instruction) + */ + this->pb.val(pc_from_cf_or_zero) = this->pb.val(computed_result) * this->pb.val(is_control_flow_instruction); + this->pb.val(packed_outgoing_pc) = + this->pb.val(pc_from_cf_or_zero) + + this->pb.val(packed_incoming_pc) * this->pb.val(is_stall_instruction) + + (this->pb.val(packed_incoming_pc) + FieldT::one()) * (FieldT::one() - this->pb.val(is_control_flow_instruction) - this->pb.val(is_stall_instruction)); + + /* + enforce new flag: + + flag' = computed_flag * is_register_instruction + flag * (1-is_register_instruction) + flag' - flag = (computed_flag - flag) * is_register_instruction + */ + this->pb.val(outgoing_flag) = + this->pb.val(computed_flag) * this->pb.val(is_register_instruction) + + this->pb.val(incoming_flag) * (FieldT::one() - this->pb.val(is_register_instruction)); + + /* + update registers (changed and unchanged) + + next_desval = computed_result * is_register_instruction + packed_incoming_desval * (1-is_register_instruction) + */ + FieldT changed_register_contents = + this->pb.val(computed_result) * this->pb.val(is_register_instruction) + + this->pb.val(packed_incoming_desval) * (FieldT::one() - this->pb.val(is_register_instruction)); + + for (size_t i = 0; i < this->pb.ap.k; ++i) + { + this->pb.val(packed_outgoing_registers[i]) = + (this->pb.val(packed_desidx).as_ulong() == i) ? + changed_register_contents : + this->pb.val(packed_incoming_registers[i]); + } + + /* demux result register (it is important to do witness generation + here after all registers have been set to the correct + values!) */ + demux_packed_outgoing_desval->generate_r1cs_witness(); +} + +#if 0 +template +void test_arithmetic_consistency_enforcer_gadget() +{ + print_time("starting arithmetic_consistency_enforcer test"); + + tinyram_architecture_params ap(16, 16); + tinyram_protoboard pb(ap); + + pb_variable_array opcode_indicators, instruction_results, instruction_flags; + opcode_indicators.allocate(pb, 1ul< desidx(pb, ap.reg_arg_width(), "desidx"); + + pb_variable incoming_pc; + incoming_pc.allocate(pb, "incoming_pc"); + + pb_variable_array packed_incoming_registers; + packed_incoming_registers.allocate(pb, ap.k, "packed_incoming_registers"); + + pb_variable incoming_load_flag; + incoming_load_flag.allocate(pb, "incoming_load_flag"); + + pb_variable outgoing_pc, outgoing_flag; + outgoing_pc.allocate(pb, "outgoing_pc"); + outgoing_flag.allocate(pb, "outgoing_flag"); + + pb_variable_array packed_outgoing_registers; + packed_outgoing_registers.allocate(pb, ap.k, "packed_outgoing_registers"); + + arithmetic_consistency_enforcer_gadget g(pb, opcode_indicators, instruction_results, instruction_flags, + desidx.bits, incoming_pc, packed_incoming_registers, + incoming_load_flag, outgoing_pc, packed_outgoing_registers, outgoing_flag, "g"); + g.generate_r1cs_constraints(); + + for (size_t i = 0; i < 1ul<pb.val(instruction_results[i]) = FieldT(std::rand()); + this->pb.val(instruction_flags[i]) = FieldT(std::rand() % 2); + } + + this->pb.val(incoming_pc) = FieldT(12345); + this->pb.val(incoming_load_flag) = FieldT::zero(); + + for (size_t i = 0; i < ap.k; ++i) + { + this->pb.val(packed_incoming_registers[i]) = FieldT(1000+i); + } + + for (size_t t = 0; t < 1ul<pb.val(opcode_indicators[t]) = FieldT::zero(); + } + + this->pb.val(opcode_indicators[tinyram_opcode_AND]) = FieldT::one(); + + for (size_t i = 0; i < ap.k; ++i) + { + this->pb.val(desidx.packed) = FieldT(i); + desidx.generate_r1cs_witness_from_packed(); + + g.generate_r1cs_witness(); + + assert(this->pb.val(outgoing_pc) == FieldT(12346)); + + for (size_t j = 0; j < ap.k; ++j) + { + assert(this->pb.val(packed_outgoing_registers[j]) == + this->pb.val(i == j ? + instruction_results[tinyram_opcode_AND] : + packed_incoming_registers[j])); + } + + assert(this->pb.val(outgoing_flag) == this->pb.val(instruction_flags[tinyram_opcode_AND])); + assert(pb.is_satisfied()); + } + + printf("arithmetic test successful\n"); + for (size_t t = 0; t < 1ul<pb.val(opcode_indicators[t]) = FieldT::zero(); + } + this->pb.val(opcode_indicators[tinyram_opcode_LOAD]) = FieldT::one(); + this->pb.val(incoming_load_flag) = FieldT::one(); + + g.generate_r1cs_witness(); + + this->pb.val(outgoing_pc) == FieldT(12345); + assert(pb.is_satisfied()); + + this->pb.val(incoming_load_flag) = FieldT::zero(); + printf("test that firstload doesn't increment PC successful\n"); + + for (size_t t = 0; t < 1ul<pb.val(opcode_indicators[t]) = FieldT::zero(); + } + + this->pb.val(opcode_indicators[tinyram_opcode_JMP]) = FieldT::one(); + + for (size_t i = 0; i < ap.k; ++i) + { + this->pb.val(desidx.packed) = FieldT(i); + desidx.generate_r1cs_witness_from_packed(); + + g.generate_r1cs_witness(); + + for (size_t j = 0; j < ap.k; ++j) + { + assert(this->pb.val(packed_outgoing_registers[j]) == this->pb.val(packed_incoming_registers[j])); + } + + assert(pb.is_satisfied()); + } + + printf("non-arithmetic test successful\n"); + + print_time("arithmetic_consistency_enforcer tests successful"); +} + +template +void test_control_flow_consistency_enforcer_gadget() +{ + print_time("starting control_flow_consistency_enforcer test"); + + tinyram_architecture_params ap(16, 16); + tinyram_protoboard pb(ap); + + pb_variable_array opcode_indicators, instruction_results; + opcode_indicators.allocate(pb, 1ul< incoming_pc, incoming_flag; + incoming_pc.allocate(pb, "incoming_pc"); + incoming_flag.allocate(pb, "incoming_flag"); + + pb_variable_array packed_incoming_registers; + packed_incoming_registers.allocate(pb, ap.k, "packed_incoming_registers"); + + pb_variable outgoing_pc, outgoing_flag; + outgoing_pc.allocate(pb, "outgoing_pc"); + outgoing_flag.allocate(pb, "outgoing_flag"); + + pb_variable_array packed_outgoing_registers; + packed_outgoing_registers.allocate(pb, ap.k, "packed_outgoing_registers"); + + control_flow_consistency_enforcer_gadget g(pb, opcode_indicators, instruction_results, + incoming_pc, packed_incoming_registers, incoming_flag, + outgoing_pc, packed_outgoing_registers, outgoing_flag, "g"); + g.generate_r1cs_constraints(); + + for (size_t i = 0; i < 1ul<pb.val(instruction_results[i]) = FieldT(std::rand()); + } + + this->pb.val(incoming_pc) = FieldT(12345); + + for (size_t i = 0; i < ap.k; ++i) + { + this->pb.val(packed_incoming_registers[i]) = FieldT(1000+i); + } + + for (size_t t = 0; t < 1ul<pb.val(opcode_indicators[t]) = FieldT::zero(); + } + this->pb.val(opcode_indicators[tinyram_opcode_JMP]) = FieldT::one(); + + for (int flag = 0; flag <= 1; ++flag) + { + this->pb.val(incoming_flag) = FieldT(flag); + + g.generate_r1cs_witness(); + + assert(this->pb.val(outgoing_pc) == this->pb.val(instruction_results[tinyram_opcode_JMP])); + assert(this->pb.val(outgoing_flag) == this->pb.val(incoming_flag)); + + for (size_t j = 0; j < ap.k; ++j) + { + assert(this->pb.val(packed_outgoing_registers[j]) == this->pb.val(packed_incoming_registers[j])); + } + assert(pb.is_satisfied()); + } + + print_time("control_flow_consistency_enforcer tests successful"); +} + +template +void test_special_consistency_enforcer_gadget() +{ + print_time("starting special_consistency_enforcer_gadget test"); + + tinyram_architecture_params ap(16, 16); + tinyram_protoboard pb(ap); + + pb_variable_array opcode_indicators; + opcode_indicators.allocate(pb, 1ul< incoming_pc, incoming_flag, incoming_load_flag; + incoming_pc.allocate(pb, "incoming_pc"); + incoming_flag.allocate(pb, "incoming_flag"); + incoming_load_flag.allocate(pb, "incoming_load_flag"); + + pb_variable_array packed_incoming_registers; + packed_incoming_registers.allocate(pb, ap.k, "packed_incoming_registers"); + + pb_variable outgoing_pc, outgoing_flag, outgoing_load_flag; + outgoing_pc.allocate(pb, "outgoing_pc"); + outgoing_flag.allocate(pb, "outgoing_flag"); + outgoing_load_flag.allocate(pb, "outgoing_load_flag"); + + pb_variable_array packed_outgoing_registers; + packed_outgoing_registers.allocate(pb, ap.k, "packed_outgoing_registers"); + + special_consistency_enforcer_gadget g(pb, opcode_indicators, + incoming_pc, packed_incoming_registers, incoming_flag, incoming_load_flag, + outgoing_pc, packed_outgoing_registers, outgoing_flag, outgoing_load_flag, "g"); + g.generate_r1cs_constraints(); + + this->pb.val(incoming_pc) = FieldT(12345); + for (size_t i = 0; i < ap.k; ++i) + { + this->pb.val(packed_incoming_registers[i]) = FieldT(1000+i); + } + this->pb.val(incoming_flag) = FieldT::zero(); + this->pb.val(incoming_load_flag) = FieldT::zero(); + + /* test that accept stalls */ + printf("test that ACCEPT stalls\n"); + + for (size_t t = 0; t < 1ul<pb.val(opcode_indicators[t]) = FieldT::zero(); + } + this->pb.val(opcode_indicators[tinyram_opcode_ACCEPT]) = FieldT::one(); + + g.generate_r1cs_witness(); + + assert(this->pb.val(outgoing_flag) == this->pb.val(incoming_flag)); + for (size_t j = 0; j < ap.k; ++j) + { + assert(this->pb.val(packed_outgoing_registers[j]) == this->pb.val(packed_incoming_registers[j])); + } + + assert(this->pb.val(outgoing_pc) == this->pb.val(incoming_pc)); + assert(pb.is_satisfied()); + + printf("test that ACCEPT preserves registers\n"); + this->pb.val(packed_outgoing_registers[0]) = FieldT::zero(); + assert(!pb.is_satisfied()); + + /* test that other special instructions (e.g. STORE) don't and also preserve registers */ + printf("test that others (e.g. STORE) don't stall\n"); + + for (size_t t = 0; t < 1ul<pb.val(opcode_indicators[t]) = FieldT::zero(); + } + this->pb.val(opcode_indicators[tinyram_opcode_STORE]) = FieldT::one(); + + g.generate_r1cs_witness(); + + assert(this->pb.val(outgoing_flag) == this->pb.val(incoming_flag)); + for (size_t j = 0; j < ap.k; ++j) + { + assert(this->pb.val(packed_outgoing_registers[j]) == this->pb.val(packed_incoming_registers[j])); + } + + assert(this->pb.val(outgoing_pc) == this->pb.val(incoming_pc) + FieldT::one()); + assert(pb.is_satisfied()); + + printf("test that STORE preserves registers\n"); + this->pb.val(packed_outgoing_registers[0]) = FieldT::zero(); + assert(!pb.is_satisfied()); + + printf("test that STORE can't have load_flag\n"); + g.generate_r1cs_witness(); + this->pb.val(incoming_load_flag) = FieldT::one(); + + assert(!pb.is_satisfied()); + + /* test that load can modify outgoing register and sets load_flag */ + printf("test that LOAD sets load_flag\n"); + + for (size_t t = 0; t < 1ul<pb.val(opcode_indicators[t]) = FieldT::zero(); + } + this->pb.val(opcode_indicators[tinyram_opcode_LOAD]) = FieldT::one(); + this->pb.val(incoming_load_flag) = FieldT::zero(); + + g.generate_r1cs_witness(); + + assert(this->pb.val(outgoing_load_flag) == FieldT::one()); + assert(pb.is_satisfied()); + + printf("test that LOAD can modify registers\n"); + this->pb.val(packed_outgoing_registers[0]) = FieldT::zero(); + assert(pb.is_satisfied()); + + /* test that postload clears load_flag */ + printf("test that postload clears load_flag\n"); + + for (size_t t = 0; t < 1ul<pb.val(opcode_indicators[t]) = FieldT::zero(); + } + this->pb.val(opcode_indicators[tinyram_opcode_LOAD]) = FieldT::one(); + this->pb.val(incoming_load_flag) = FieldT::one(); + + g.generate_r1cs_witness(); + + assert(this->pb.val(outgoing_load_flag) == FieldT::zero()); + assert(pb.is_satisfied()); + + /* test non-special instructions */ + printf("test non-special instructions\n"); + + for (size_t t = 0; t < 1ul<pb.val(opcode_indicators[t]) = FieldT::zero(); + } + this->pb.val(opcode_indicators[tinyram_opcode_JMP]) = FieldT::one(); + this->pb.val(incoming_load_flag) = FieldT::zero(); + g.generate_r1cs_witness(); + + assert(pb.is_satisfied()); + + printf("test that non-special can't have load_flag\n"); + g.generate_r1cs_witness(); + this->pb.val(incoming_load_flag) = FieldT::one(); + + assert(!pb.is_satisfied()); + + print_time("special_consistency_enforcer_gadget tests successful"); +} +#endif + +} // libsnark + +#endif // CONSISTENCY_ENFORCER_GADGET_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/instruction_packing_gadget.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/instruction_packing_gadget.hpp new file mode 100644 index 0000000..8f247d1 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/instruction_packing_gadget.hpp @@ -0,0 +1,58 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the TinyRAM instruction packing gadget. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef INSTRUCTION_PACKING_GADGET_HPP_ +#define INSTRUCTION_PACKING_GADGET_HPP_ + +namespace libsnark { + +template +class tinyram_instruction_packing_gadget : public tinyram_gadget { +private: + pb_variable_array all_bits; + + std::shared_ptr > pack_instruction; +public: + pb_variable_array opcode; + pb_variable arg2_is_imm; + pb_variable_array desidx; + pb_variable_array arg1idx; + pb_variable_array arg2idx; + pb_variable packed_instruction; + + pb_variable_array dummy; + + tinyram_instruction_packing_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode, + const pb_variable &arg2_is_imm, + const pb_variable_array &desidx, + const pb_variable_array &arg1idx, + const pb_variable_array &arg2idx, + const pb_variable &packed_instruction, + const std::string &annotation_prefix=""); + + void generate_r1cs_constraints(const bool enforce_bitness); + void generate_r1cs_witness_from_packed(); + void generate_r1cs_witness_from_bits(); +}; + +template +FieldT pack_instruction(const tinyram_architecture_params &ap, + const tinyram_instruction &instr); + +template +void test_instruction_packing(); + +} // libsnark + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/instruction_packing_gadget.tcc" + +#endif // INSTRUCTION_PACKING_GADGET_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/instruction_packing_gadget.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/instruction_packing_gadget.tcc new file mode 100644 index 0000000..5691dd8 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/instruction_packing_gadget.tcc @@ -0,0 +1,195 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the TinyRAM instruction packing gadget. + + See instruction_packing_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef INSTRUCTION_PACKING_GADGET_TCC_ +#define INSTRUCTION_PACKING_GADGET_TCC_ + +namespace libsnark { + +template +tinyram_instruction_packing_gadget::tinyram_instruction_packing_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode, + const pb_variable &arg2_is_imm, + const pb_variable_array &desidx, + const pb_variable_array &arg1idx, + const pb_variable_array &arg2idx, + const pb_variable &packed_instruction, + const std::string &annotation_prefix) : + tinyram_gadget(pb, annotation_prefix), + opcode(opcode), + arg2_is_imm(arg2_is_imm), + desidx(desidx), + arg1idx(arg1idx), + arg2idx(arg2idx), + packed_instruction(packed_instruction) +{ + all_bits.reserve(2*pb.ap.w); + + all_bits.insert(all_bits.begin(), opcode.begin(), opcode.end()); + all_bits.insert(all_bits.begin(), arg2_is_imm); + all_bits.insert(all_bits.begin(), desidx.begin(), desidx.end()); + all_bits.insert(all_bits.begin(), arg1idx.begin(), arg1idx.end()); + dummy.allocate(pb, pb.ap.w-all_bits.size(), FMT(this->annotation_prefix, " dummy")); + all_bits.insert(all_bits.begin(), dummy.begin(), dummy.end()); + all_bits.insert(all_bits.begin(), arg2idx.begin(), arg2idx.end()); + + assert(all_bits.size() == 2*pb.ap.w); + + pack_instruction.reset( + new packing_gadget(pb, all_bits, packed_instruction, FMT(this->annotation_prefix, " pack_instruction"))); +} + + +template +void tinyram_instruction_packing_gadget::generate_r1cs_constraints(const bool enforce_bitness) +{ + pack_instruction->generate_r1cs_constraints(enforce_bitness); +} + +template +void tinyram_instruction_packing_gadget::generate_r1cs_witness_from_packed() +{ + pack_instruction->generate_r1cs_witness_from_packed(); +} + +template +void tinyram_instruction_packing_gadget::generate_r1cs_witness_from_bits() +{ + pack_instruction->generate_r1cs_witness_from_bits(); +} + +template +FieldT pack_instruction(const tinyram_architecture_params &ap, + const tinyram_instruction &instr) +{ + tinyram_program P; P.instructions = generate_tinyram_prelude(ap); + tinyram_protoboard pb(ap, P.size(), 0, 10); + + pb_variable_array v_opcode; + pb_variable v_arg2_is_imm; + pb_variable_array v_desidx; + pb_variable_array v_arg1idx; + pb_variable_array v_arg2idx; + + v_opcode.allocate(pb, ap.s, "opcode"); + v_arg2_is_imm.allocate(pb, "arg2_is_imm"); + v_desidx.allocate(pb, ap.reg_arg_width(), "desidx"); + v_arg1idx.allocate(pb, ap.reg_arg_width(), "arg1idx"); + v_arg2idx.allocate(pb, ap.reg_arg_or_imm_width(), "arg2idx"); + + v_opcode.fill_with_bits_of_ulong(pb, instr.opcode); + pb.val(v_arg2_is_imm) = instr.arg2_is_imm ? FieldT::one() : FieldT::zero(); + v_desidx.fill_with_bits_of_ulong(pb, instr.desidx); + v_arg1idx.fill_with_bits_of_ulong(pb, instr.arg1idx); + v_arg2idx.fill_with_bits_of_ulong(pb, instr.arg2idx_or_imm); + + pb_variable packed; + packed.allocate(pb, "packed"); + + tinyram_instruction_packing_gadget g(pb, v_opcode, v_arg2_is_imm, v_desidx, v_arg1idx, v_arg2idx, packed, "g"); + g.generate_r1cs_constraints(true); + g.generate_r1cs_witness_from_bits(); + + return pb.val(packed); +} + +template +void test_instruction_packing() +{ + print_time("starting instruction packing test"); + + tinyram_architecture_params ap(16, 16); + tinyram_program P; P.instructions = generate_tinyram_prelude(ap); + tinyram_protoboard pb(ap, P.size(), 0, 10); + + pb_variable_array opcode[2]; + pb_variable arg2_is_imm[2]; + pb_variable_array desidx[2]; + pb_variable_array arg1idx[2]; + pb_variable_array arg2idx[2]; + + for (size_t i = 0; i < 2; ++i) + { + opcode[i].allocate(pb, ap.s, FMT("", "opcode_%zu", i)); + arg2_is_imm[i].allocate(pb, FMT("", "arg2_is_imm_%zu", i)); + desidx[i].allocate(pb, ap.reg_arg_width(), FMT("", "desidx_%zu", i)); + arg1idx[i].allocate(pb, ap.reg_arg_width(), FMT("", "arg1idx_%zu", i)); + arg2idx[i].allocate(pb, ap.reg_arg_or_imm_width(), FMT("", "arg2idx_%zu", i)); + } + + pb_variable packed_instr; + packed_instr.allocate(pb, "packed_instr"); + + instruction_packing_gadget pack(pb, opcode[0], arg2_is_imm[0], desidx[0], arg1idx[0], arg2idx[0], packed_instr, "pack"); + instruction_packing_gadget unpack(pb, opcode[1], arg2_is_imm[1], desidx[1], arg1idx[1], arg2idx[1], packed_instr, "unpack"); + + pack.generate_r1cs_constraints(true); + unpack.generate_r1cs_constraints(true); + + for (size_t k = 0; k < 100; ++k) + { + tinyram_opcode oc = static_cast(std::rand() % (1u << ap.s)); + bool imm = std::rand() % 2; + size_t des = rand() % (1u << ap.reg_arg_width()); + size_t arg1 = rand() % (1u << ap.reg_arg_width()); + size_t arg2 = rand() % (1u << ap.reg_arg_or_imm_width()); + + for (size_t i = 0; i < ap.s; ++i) + { + pb.val(opcode[0][i]) = (oc & (1ul<(ap, tinyram_instruction(oc, imm, des, arg1, arg2))); + assert(pb.is_satisfied()); + } + + print_time("instruction packing tests successful"); +} + +} // libsnark + +#endif // INSTRUCTION_PACKING_GADGET_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/memory_masking_gadget.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/memory_masking_gadget.hpp new file mode 100644 index 0000000..5096aa3 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/memory_masking_gadget.hpp @@ -0,0 +1,94 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the TinyRAM memory masking gadget. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MEMORY_MASKING_GADGET_HPP_ +#define MEMORY_MASKING_GADGET_HPP_ + +namespace libsnark { + +/** + * The memory masking gadget checks if a specified part of a double + * word is correctly modified. In TinyRAM CPU checker we use this to + * implement byte addressing and word addressing for the memory that + * consists of double words. + * + * More precisely, memory masking gadgets takes the following + * arguments: + * + * dw_contents_prev, dw_contents_next -- the contents of the memory + * + * double word before and after the access + * + * access_is_word -- a boolean indicating if access is word + * + * access_is_byte -- a boolean indicating if access is byte + * + * subaddress -- an integer specifying which byte (if access_is_byte=1) + * or word (if access_is_byte=1) this access is operating on + * + * subcontents -- contents of the byte, resp., word to be operated on + * + * Memory masking gadget enforces that dw_contents_prev is equal to + * dw_contents_next everywhere, except subaddres-th byte (if + * access_is_byte = 1), or MSB(subaddress)-th word (if access_is_word = + * 1). The corresponding byte, resp., word in dw_contents_next is + * required to equal subcontents. + * + * Note that indexing MSB(subaddress)-th word is the same as indexing + * the word specified by subaddress expressed in bytes and aligned to + * the word boundary by rounding the subaddress down. + * + * Requirements: The caller is required to perform bounds checks on + * subcontents. The caller is also required to ensure that exactly one + * of access_is_word and access_is_byte is set to 1. + */ +template +class memory_masking_gadget : public tinyram_standard_gadget { +private: + pb_linear_combination shift; + pb_variable is_word0; + pb_variable is_word1; + pb_variable_array is_subaddress; + pb_variable_array is_byte; + + pb_linear_combination masked_out_word0; + pb_linear_combination masked_out_word1; + pb_linear_combination_array masked_out_bytes; + + std::shared_ptr > get_masked_out_dw_contents_prev; + + pb_variable masked_out_dw_contents_prev; + pb_variable expected_dw_contents_next; +public: + doubleword_variable_gadget dw_contents_prev; + dual_variable_gadget subaddress; + pb_linear_combination subcontents; + pb_linear_combination access_is_word; + pb_linear_combination access_is_byte; + doubleword_variable_gadget dw_contents_next; + + memory_masking_gadget(tinyram_protoboard &pb, + const doubleword_variable_gadget &dw_contents_prev, + const dual_variable_gadget &subaddress, + const pb_linear_combination &subcontents, + const pb_linear_combination &access_is_word, + const pb_linear_combination &access_is_byte, + const doubleword_variable_gadget &dw_contents_next, + const std::string& annotation_prefix=""); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/memory_masking_gadget.tcc" + +#endif // MEMORY_MASKING_GADGET_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/memory_masking_gadget.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/memory_masking_gadget.tcc new file mode 100644 index 0000000..99e2538 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/memory_masking_gadget.tcc @@ -0,0 +1,171 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the TinyRAM memory masking gadget. + + See memory_masking_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MEMORY_MASKING_GADGET_TCC_ +#define MEMORY_MASKING_GADGET_TCC_ + +namespace libsnark { + +template +memory_masking_gadget::memory_masking_gadget(tinyram_protoboard &pb, + const doubleword_variable_gadget &dw_contents_prev, + const dual_variable_gadget &subaddress, + const pb_linear_combination &subcontents, + const pb_linear_combination &access_is_word, + const pb_linear_combination &access_is_byte, + const doubleword_variable_gadget &dw_contents_next, + const std::string& annotation_prefix) : + tinyram_standard_gadget(pb, annotation_prefix), + dw_contents_prev(dw_contents_prev), + subaddress(subaddress), + subcontents(subcontents), + access_is_word(access_is_word), + access_is_byte(access_is_byte), + dw_contents_next(dw_contents_next) +{ + /* + Indicator variables for access being to word_0, word_1, and + byte_0, byte_1, ... + + We use little-endian indexing here (least significant + bit/byte/word has the smallest address). + */ + is_word0.allocate(pb, FMT(this->annotation_prefix, " is_word0")); + is_word1.allocate(pb, FMT(this->annotation_prefix, " is_word1")); + is_subaddress.allocate(pb, 2 * pb.ap.bytes_in_word(), FMT(this->annotation_prefix, " is_sub_address")); + is_byte.allocate(pb, 2 * pb.ap.bytes_in_word(), FMT(this->annotation_prefix, " is_byte")); + + /* + Get value of the dw_contents_prev for which the specified entity + is masked out to be zero. E.g. the value of masked_out_bytes[3] + will be the same as the value of dw_contents_prev, when 3rd + (0-indexed) byte is set to all zeros. + */ + masked_out_word0.assign(pb, (FieldT(2)^pb.ap.w) * pb_packing_sum( + pb_variable_array(dw_contents_prev.bits.begin() + pb.ap.w, + dw_contents_prev.bits.begin() + 2 * pb.ap.w))); + masked_out_word1.assign(pb, pb_packing_sum( + pb_variable_array(dw_contents_prev.bits.begin(), + dw_contents_prev.bits.begin() + pb.ap.w))); + masked_out_bytes.resize(2 * pb.ap.bytes_in_word()); + + for (size_t i = 0; i < 2 * pb.ap.bytes_in_word(); ++i) + { + /* just subtract out the byte to be masked */ + masked_out_bytes[i].assign(pb, (dw_contents_prev.packed - + (FieldT(2)^(8*i)) * pb_packing_sum( + pb_variable_array(dw_contents_prev.bits.begin() + 8*i, + dw_contents_prev.bits.begin() + 8*(i+1))))); + } + + /* + Define masked_out_dw_contents_prev to be the correct masked out + contents for the current access type. + */ + + pb_linear_combination_array masked_out_indicators; + masked_out_indicators.emplace_back(is_word0); + masked_out_indicators.emplace_back(is_word1); + masked_out_indicators.insert(masked_out_indicators.end(), is_byte.begin(), is_byte.end()); + + pb_linear_combination_array masked_out_results; + masked_out_results.emplace_back(masked_out_word0); + masked_out_results.emplace_back(masked_out_word1); + masked_out_results.insert(masked_out_results.end(), masked_out_bytes.begin(), masked_out_bytes.end()); + + masked_out_dw_contents_prev.allocate(pb, FMT(this->annotation_prefix, " masked_out_dw_contents_prev")); + get_masked_out_dw_contents_prev.reset(new inner_product_gadget(pb, masked_out_indicators, masked_out_results, masked_out_dw_contents_prev, + FMT(this->annotation_prefix, " get_masked_out_dw_contents_prev"))); + + /* + Define shift so that masked_out_dw_contents_prev + shift * subcontents = dw_contents_next + */ + linear_combination shift_lc = is_word0 * 1 + is_word1 * (FieldT(2)^this->pb.ap.w); + for (size_t i = 0; i < 2 * this->pb.ap.bytes_in_word(); ++i) + { + shift_lc = shift_lc + is_byte[i] * (FieldT(2)^(8*i)); + } + shift.assign(pb, shift_lc); +} + +template +void memory_masking_gadget::generate_r1cs_constraints() +{ + /* get indicator variables for is_subaddress[i] by adding constraints + is_subaddress[i] * (subaddress - i) = 0 and \sum_i is_subaddress[i] = 1 */ + for (size_t i = 0; i < 2 * this->pb.ap.bytes_in_word(); ++i) + { + this->pb.add_r1cs_constraint(r1cs_constraint(is_subaddress[i], subaddress.packed - i, 0), + FMT(this->annotation_prefix, " is_subaddress_%zu", i)); + } + this->pb.add_r1cs_constraint(r1cs_constraint(1, pb_sum(is_subaddress), 1), FMT(this->annotation_prefix, " is_subaddress")); + + /* get indicator variables is_byte_X */ + for (size_t i = 0; i < 2 * this->pb.ap.bytes_in_word(); ++i) + { + this->pb.add_r1cs_constraint(r1cs_constraint(access_is_byte, is_subaddress[i], is_byte[i]), + FMT(this->annotation_prefix, " is_byte_%zu", i)); + } + + /* get indicator variables is_word_0/is_word_1 */ + this->pb.add_r1cs_constraint(r1cs_constraint(access_is_word, 1 - subaddress.bits[this->pb.ap.subaddr_len()-1], is_word0), + FMT(this->annotation_prefix, " is_word_0")); + this->pb.add_r1cs_constraint(r1cs_constraint(access_is_word, subaddress.bits[this->pb.ap.subaddr_len()-1], is_word1), + FMT(this->annotation_prefix, " is_word_1")); + + /* compute masked_out_dw_contents_prev */ + get_masked_out_dw_contents_prev->generate_r1cs_constraints(); + + /* + masked_out_dw_contents_prev + shift * subcontents = dw_contents_next + */ + this->pb.add_r1cs_constraint(r1cs_constraint(shift, subcontents, dw_contents_next.packed - masked_out_dw_contents_prev), + FMT(this->annotation_prefix, " mask_difference")); +} + +template +void memory_masking_gadget::generate_r1cs_witness() +{ + /* get indicator variables is_subaddress */ + for (size_t i = 0; i < 2 * this->pb.ap.bytes_in_word(); ++i) + { + this->pb.val(is_subaddress[i]) = (this->pb.val(subaddress.packed) == FieldT(i)) ? FieldT::one() : FieldT::zero(); + } + + /* get indicator variables is_byte_X */ + for (size_t i = 0; i < 2 * this->pb.ap.bytes_in_word(); ++i) + { + this->pb.val(is_byte[i]) = this->pb.val(is_subaddress[i]) * this->pb.lc_val(access_is_byte); + } + + /* get indicator variables is_word_0/is_word_1 */ + this->pb.val(is_word0) = (FieldT::one() - this->pb.val(subaddress.bits[this->pb.ap.subaddr_len()-1])) * this->pb.lc_val(access_is_word); + this->pb.val(is_word1) = this->pb.val(subaddress.bits[this->pb.ap.subaddr_len()-1]) * this->pb.lc_val(access_is_word); + + /* calculate shift and masked out words/bytes */ + shift.evaluate(this->pb); + masked_out_word0.evaluate(this->pb); + masked_out_word1.evaluate(this->pb); + masked_out_bytes.evaluate(this->pb); + + /* get masked_out dw/word0/word1/bytes */ + get_masked_out_dw_contents_prev->generate_r1cs_witness(); + + /* compute dw_contents_next */ + this->pb.val(dw_contents_next.packed) = this->pb.val(masked_out_dw_contents_prev) + this->pb.lc_val(shift) * this->pb.lc_val(subcontents); + dw_contents_next.generate_r1cs_witness_from_packed(); +} + +} // libsnark + +#endif // MEMORY_MASKING_GADGET_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.hpp new file mode 100644 index 0000000..c84ea7c --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.hpp @@ -0,0 +1,52 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a protoboard for TinyRAM. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TINYRAM_PROTOBOARD_HPP_ +#define TINYRAM_PROTOBOARD_HPP_ + +#include "relations/ram_computations/rams/ram_params.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_aux.hpp" +#include "gadgetlib1/protoboard.hpp" +#include "gadgetlib1/gadgets/basic_gadgets.hpp" + +namespace libsnark { + +template +class tinyram_protoboard : public protoboard { +public: + const tinyram_architecture_params ap; + + tinyram_protoboard(const tinyram_architecture_params &ap); +}; + +template +class tinyram_gadget : public gadget { +protected: + tinyram_protoboard &pb; +public: + tinyram_gadget(tinyram_protoboard &pb, const std::string &annotation_prefix=""); +}; + +// standard gadgets provide two methods: generate_r1cs_constraints and generate_r1cs_witness +template +class tinyram_standard_gadget : public tinyram_gadget { +public: + tinyram_standard_gadget(tinyram_protoboard &pb, const std::string &annotation_prefix=""); + + virtual void generate_r1cs_constraints() = 0; + virtual void generate_r1cs_witness() = 0; +}; + +} // libsnark + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.tcc" + +#endif // TINYRAM_PROTOBOARD_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.tcc new file mode 100644 index 0000000..c70b9db --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.tcc @@ -0,0 +1,39 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a protoboard for TinyRAM. + + See tinyram_protoboard.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TINYRAM_PROTOBOARD_TCC_ +#define TINYRAM_PROTOBOARD_TCC_ + +namespace libsnark { + +template +tinyram_protoboard::tinyram_protoboard(const tinyram_architecture_params &ap) : + ap(ap) +{ +} + +template +tinyram_gadget::tinyram_gadget(tinyram_protoboard &pb, const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), pb(pb) +{ +} + +template +tinyram_standard_gadget::tinyram_standard_gadget(tinyram_protoboard &pb, const std::string &annotation_prefix) : + tinyram_gadget(pb, annotation_prefix) +{ +} + +} // libsnark + +#endif // TINYRAM_PROTOBOARD_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/word_variable_gadget.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/word_variable_gadget.hpp new file mode 100644 index 0000000..24c462b --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/components/word_variable_gadget.hpp @@ -0,0 +1,49 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for (single and double) word gadgets. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WORD_VARIABLE_GADGET_HPP_ +#define WORD_VARIABLE_GADGET_HPP_ + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.hpp" + +namespace libsnark { + +/** + * Holds both binary and field representaton of a word. + */ +template +class word_variable_gadget : public dual_variable_gadget { +public: + word_variable_gadget(tinyram_protoboard &pb, const std::string &annotation_prefix="") : + dual_variable_gadget(pb, pb.ap.w, annotation_prefix) {} + word_variable_gadget(tinyram_protoboard &pb, const pb_variable_array &bits, const std::string &annotation_prefix="") : + dual_variable_gadget(pb, bits, annotation_prefix) {} + word_variable_gadget(tinyram_protoboard &pb, const pb_variable &packed, const std::string &annotation_prefix="") : + dual_variable_gadget(pb, packed, pb.ap.w, annotation_prefix) {} +}; + +/** + * Holds both binary and field representaton of a double word. + */ +template +class doubleword_variable_gadget : public dual_variable_gadget { +public: + doubleword_variable_gadget(tinyram_protoboard &pb, const std::string &annotation_prefix="") : + dual_variable_gadget(pb, 2*pb.ap.w, annotation_prefix) {} + doubleword_variable_gadget(tinyram_protoboard &pb, const pb_variable_array &bits, const std::string &annotation_prefix="") : + dual_variable_gadget(pb, bits, annotation_prefix) {} + doubleword_variable_gadget(tinyram_protoboard &pb, const pb_variable &packed, const std::string &annotation_prefix="") : + dual_variable_gadget(pb, packed, 2*pb.ap.w, annotation_prefix) {} +}; + +} // libsnark + +#endif // WORD_VARIABLE_GADGET_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/tinyram_cpu_checker.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/tinyram_cpu_checker.hpp new file mode 100644 index 0000000..3168ec3 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/tinyram_cpu_checker.hpp @@ -0,0 +1,101 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the TinyRAM CPU checker gadget. + + The gadget checks the correct operation for the CPU of the TinyRAM architecture. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TINYRAM_CPU_CHECKER_HPP_ +#define TINYRAM_CPU_CHECKER_HPP_ + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.hpp" +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/word_variable_gadget.hpp" +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_gadget.hpp" +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/argument_decoder_gadget.hpp" +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/consistency_enforcer_gadget.hpp" +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/memory_masking_gadget.hpp" + +namespace libsnark { + +template +class tinyram_cpu_checker : public tinyram_standard_gadget { +private: + pb_variable_array opcode; + pb_variable arg2_is_imm; + pb_variable_array desidx; + pb_variable_array arg1idx; + pb_variable_array arg2idx; + + std::vector > prev_registers; + std::vector > next_registers; + pb_variable prev_flag; + pb_variable next_flag; + pb_variable prev_tape1_exhausted; + pb_variable next_tape1_exhausted; + + std::shared_ptr > prev_pc_addr_as_word_variable; + std::shared_ptr > desval; + std::shared_ptr > arg1val; + std::shared_ptr > arg2val; + + std::shared_ptr > decode_arguments; + pb_variable_array opcode_indicators; + std::shared_ptr > ALU; + + std::shared_ptr > ls_prev_val_as_doubleword_variable; + std::shared_ptr > ls_next_val_as_doubleword_variable; + std::shared_ptr > memory_subaddress; + pb_variable memory_subcontents; + pb_linear_combination memory_access_is_word; + pb_linear_combination memory_access_is_byte; + std::shared_ptr > check_memory; + + std::shared_ptr > next_pc_addr_as_word_variable; + std::shared_ptr > consistency_enforcer; + + pb_variable_array instruction_results; + pb_variable_array instruction_flags; + + pb_variable read_not1; +public: + pb_variable_array prev_pc_addr; + pb_variable_array prev_pc_val; + pb_variable_array prev_state; + pb_variable_array ls_addr; + pb_variable_array ls_prev_val; + pb_variable_array ls_next_val; + pb_variable_array next_state; + pb_variable_array next_pc_addr; + pb_variable next_has_accepted; + + tinyram_cpu_checker(tinyram_protoboard &pb, + pb_variable_array &prev_pc_addr, + pb_variable_array &prev_pc_val, + pb_variable_array &prev_state, + pb_variable_array &ls_addr, + pb_variable_array &ls_prev_val, + pb_variable_array &ls_next_val, + pb_variable_array &next_state, + pb_variable_array &next_pc_addr, + pb_variable &next_has_accepted, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness() { assert(0); } + void generate_r1cs_witness_address(); + void generate_r1cs_witness_other(tinyram_input_tape_iterator &aux_it, + const tinyram_input_tape_iterator &aux_end); + void dump() const; +}; + +} // libsnark + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/tinyram_cpu_checker.tcc" + +#endif // TINYRAM_CPU_CHECKER_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/tinyram_cpu_checker.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/tinyram_cpu_checker.tcc new file mode 100644 index 0000000..446ec8b --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/cpu_checkers/tinyram/tinyram_cpu_checker.tcc @@ -0,0 +1,397 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the TinyRAM CPU checker gadget. + + See tinyram_cpu_checker.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TINYRAM_CPU_CHECKER_TCC_ +#define TINYRAM_CPU_CHECKER_TCC_ + +#include "algebra/fields/field_utils.hpp" + +namespace libsnark { + +template +tinyram_cpu_checker::tinyram_cpu_checker(tinyram_protoboard &pb, + pb_variable_array &prev_pc_addr, + pb_variable_array &prev_pc_val, + pb_variable_array &prev_state, + pb_variable_array &ls_addr, + pb_variable_array &ls_prev_val, + pb_variable_array &ls_next_val, + pb_variable_array &next_state, + pb_variable_array &next_pc_addr, + pb_variable &next_has_accepted, + const std::string &annotation_prefix) : +tinyram_standard_gadget(pb, annotation_prefix), prev_pc_addr(prev_pc_addr), prev_pc_val(prev_pc_val), + prev_state(prev_state), ls_addr(ls_addr), ls_prev_val(ls_prev_val), ls_next_val(ls_next_val), + next_state(next_state), next_pc_addr(next_pc_addr), next_has_accepted(next_has_accepted) +{ + /* parse previous PC value as an instruction (note that we start + parsing from LSB of the instruction doubleword and go to the + MSB) */ + auto pc_val_it = prev_pc_val.begin(); + + arg2idx = pb_variable_array(pc_val_it, pc_val_it + pb.ap.reg_arg_or_imm_width()); std::advance(pc_val_it, pb.ap.reg_arg_or_imm_width()); + std::advance(pc_val_it, pb.ap.instruction_padding_width()); + arg1idx = pb_variable_array(pc_val_it, pc_val_it + pb.ap.reg_arg_width()); std::advance(pc_val_it, pb.ap.reg_arg_width()); + desidx = pb_variable_array(pc_val_it, pc_val_it + pb.ap.reg_arg_width()); std::advance(pc_val_it, pb.ap.reg_arg_width()); + arg2_is_imm = *pc_val_it; std::advance(pc_val_it, 1); + opcode = pb_variable_array(pc_val_it, pc_val_it + pb.ap.opcode_width()); std::advance(pc_val_it, pb.ap.opcode_width()); + + assert(pc_val_it == prev_pc_val.end()); + + /* parse state as registers + flags */ + pb_variable_array packed_prev_registers, packed_next_registers; + for (size_t i = 0; i < pb.ap.k; ++i) + { + prev_registers.emplace_back(word_variable_gadget(pb, pb_variable_array(prev_state.begin() + i * pb.ap.w, prev_state.begin() + (i + 1) * pb.ap.w), FMT(annotation_prefix, " prev_registers_%zu", i))); + next_registers.emplace_back(word_variable_gadget(pb, pb_variable_array(next_state.begin() + i * pb.ap.w, next_state.begin() + (i + 1) * pb.ap.w), FMT(annotation_prefix, " next_registers_%zu", i))); + + packed_prev_registers.emplace_back(prev_registers[i].packed); + packed_next_registers.emplace_back(next_registers[i].packed); + } + prev_flag = *(++prev_state.rbegin()); + next_flag = *(++next_state.rbegin()); + prev_tape1_exhausted = *(prev_state.rbegin()); + next_tape1_exhausted = *(next_state.rbegin()); + + /* decode arguments */ + prev_pc_addr_as_word_variable.reset(new word_variable_gadget(pb, prev_pc_addr, FMT(annotation_prefix, " prev_pc_addr_as_word_variable"))); + desval.reset(new word_variable_gadget(pb, FMT(annotation_prefix, " desval"))); + arg1val.reset(new word_variable_gadget(pb, FMT(annotation_prefix, " arg1val"))); + arg2val.reset(new word_variable_gadget(pb, FMT(annotation_prefix, " arg2val"))); + + decode_arguments.reset(new argument_decoder_gadget(pb, arg2_is_imm, desidx, arg1idx, arg2idx, packed_prev_registers, + desval->packed, arg1val->packed, arg2val->packed, + FMT(annotation_prefix, " decode_arguments"))); + + /* create indicator variables for opcodes */ + opcode_indicators.allocate(pb, 1ul<(pb, opcode_indicators, *prev_pc_addr_as_word_variable, *desval, *arg1val, *arg2val, prev_flag, instruction_results, instruction_flags, + FMT(annotation_prefix, " ALU"))); + + /* check correctness of memory operations */ + ls_prev_val_as_doubleword_variable.reset(new doubleword_variable_gadget(pb, ls_prev_val, FMT(annotation_prefix, " ls_prev_val_as_doubleword_variable"))) +; + ls_next_val_as_doubleword_variable.reset(new doubleword_variable_gadget(pb, ls_next_val, FMT(annotation_prefix, " ls_next_val_as_doubleword_variable"))); + memory_subaddress.reset(new dual_variable_gadget(pb, pb_variable_array(arg2val->bits.begin(), arg2val->bits.begin() + pb.ap.subaddr_len()), + FMT(annotation_prefix, " memory_subaddress"))); + + memory_subcontents.allocate(pb, FMT(annotation_prefix, " memory_subcontents")); + memory_access_is_word.assign(pb, 1 - (opcode_indicators[tinyram_opcode_LOADB] + opcode_indicators[tinyram_opcode_STOREB])); + memory_access_is_byte.assign(pb, opcode_indicators[tinyram_opcode_LOADB] + opcode_indicators[tinyram_opcode_STOREB]); + + check_memory.reset(new memory_masking_gadget(pb, + *ls_prev_val_as_doubleword_variable, + *memory_subaddress, + memory_subcontents, + memory_access_is_word, + memory_access_is_byte, + *ls_next_val_as_doubleword_variable, + FMT(annotation_prefix, " check_memory"))); + + /* handle reads */ + read_not1.allocate(pb, FMT(annotation_prefix, " read_not1")); + + /* check consistency of the states according to the ALU results */ + next_pc_addr_as_word_variable.reset(new word_variable_gadget(pb, next_pc_addr, FMT(annotation_prefix, " next_pc_addr_as_word_variable"))); + + consistency_enforcer.reset(new consistency_enforcer_gadget(pb, opcode_indicators, instruction_results, instruction_flags, + desidx, prev_pc_addr_as_word_variable->packed, + packed_prev_registers, + desval->packed, + prev_flag, + next_pc_addr_as_word_variable->packed, + packed_next_registers, + next_flag, + FMT(annotation_prefix, " consistency_enforcer"))); +} + +template +void tinyram_cpu_checker::generate_r1cs_constraints() +{ + decode_arguments->generate_r1cs_constraints(); + + /* generate indicator variables for opcode */ + for (size_t i = 0; i < 1ul<pb.ap.opcode_width(); ++i) + { + this->pb.add_r1cs_constraint(r1cs_constraint(opcode_indicators[i], pb_packing_sum(opcode) - i, 0), + FMT(this->annotation_prefix, " opcode_indicators_%zu", i)); + } + this->pb.add_r1cs_constraint(r1cs_constraint(1, pb_sum(opcode_indicators), 1), + FMT(this->annotation_prefix, " opcode_indicators_sum_to_1")); + + /* consistency checks for repacked variables */ + for (size_t i = 0; i < this->pb.ap.k; ++i) + { + prev_registers[i].generate_r1cs_constraints(true); + next_registers[i].generate_r1cs_constraints(true); + } + prev_pc_addr_as_word_variable->generate_r1cs_constraints(true); + next_pc_addr_as_word_variable->generate_r1cs_constraints(true); + ls_prev_val_as_doubleword_variable->generate_r1cs_constraints(true); + ls_next_val_as_doubleword_variable->generate_r1cs_constraints(true); + + /* main consistency checks */ + decode_arguments->generate_r1cs_constraints(); + ALU->generate_r1cs_constraints(); + consistency_enforcer->generate_r1cs_constraints(); + + /* check correct access to memory */ + ls_prev_val_as_doubleword_variable->generate_r1cs_constraints(false); + ls_next_val_as_doubleword_variable->generate_r1cs_constraints(false); + memory_subaddress->generate_r1cs_constraints(false); + check_memory->generate_r1cs_constraints(); + + this->pb.add_r1cs_constraint(r1cs_constraint(1, + pb_packing_sum( + pb_variable_array(arg2val->bits.begin() + this->pb.ap.subaddr_len(), + arg2val->bits.end())), + pb_packing_sum(ls_addr)), + FMT(this->annotation_prefix, " ls_addr_is_arg2val_minus_subaddress")); + + /* We require that if opcode is one of load.{b,w}, then + subcontents is appropriately stored in instruction_results. If + opcode is store.b we only take the necessary portion of arg1val + (i.e. last byte), and take entire arg1val for store.w. + + Note that ls_addr is *always* going to be arg2val. If the + instruction is a non-memory instruction, we will treat it as a + load from that memory location. */ + this->pb.add_r1cs_constraint(r1cs_constraint(opcode_indicators[tinyram_opcode_LOADB], + memory_subcontents - instruction_results[tinyram_opcode_LOADB], + 0), + FMT(this->annotation_prefix, " handle_loadb")); + this->pb.add_r1cs_constraint(r1cs_constraint(opcode_indicators[tinyram_opcode_LOADW], + memory_subcontents - instruction_results[tinyram_opcode_LOADW], + 0), + FMT(this->annotation_prefix, " handle_loadw")); + this->pb.add_r1cs_constraint(r1cs_constraint(opcode_indicators[tinyram_opcode_STOREB], + memory_subcontents - pb_packing_sum( + pb_variable_array(desval->bits.begin(), + desval->bits.begin() + 8)), + 0), + FMT(this->annotation_prefix, " handle_storeb")); + this->pb.add_r1cs_constraint(r1cs_constraint(opcode_indicators[tinyram_opcode_STOREW], + memory_subcontents - desval->packed, + 0), + FMT(this->annotation_prefix, " handle_storew")); + this->pb.add_r1cs_constraint(r1cs_constraint(1 - (opcode_indicators[tinyram_opcode_STOREB] + opcode_indicators[tinyram_opcode_STOREW]), + ls_prev_val_as_doubleword_variable->packed - ls_next_val_as_doubleword_variable->packed, + 0), + FMT(this->annotation_prefix, " non_store_instructions_dont_change_memory")); + + /* specify that accepting state implies opcode = answer && arg2val == 0 */ + this->pb.add_r1cs_constraint(r1cs_constraint(next_has_accepted, + 1 - opcode_indicators[tinyram_opcode_ANSWER], + 0), + FMT(this->annotation_prefix, " accepting_requires_answer")); + this->pb.add_r1cs_constraint(r1cs_constraint(next_has_accepted, + arg2val->packed, + 0), + FMT(this->annotation_prefix, " accepting_requires_arg2val_equal_zero")); + + /* + handle tapes: + + we require that: + prev_tape1_exhausted implies next_tape1_exhausted, + prev_tape1_exhausted implies flag to be set + reads other than from tape 1 imply flag to be set + flag implies result to be 0 + */ + this->pb.add_r1cs_constraint(r1cs_constraint(prev_tape1_exhausted, + 1 - next_tape1_exhausted, + 0), + FMT(this->annotation_prefix, " prev_tape1_exhausted_implies_next_tape1_exhausted")); + this->pb.add_r1cs_constraint(r1cs_constraint(prev_tape1_exhausted, + 1 - instruction_flags[tinyram_opcode_READ], + 0), + FMT(this->annotation_prefix, " prev_tape1_exhausted_implies_flag")); + this->pb.add_r1cs_constraint(r1cs_constraint(opcode_indicators[tinyram_opcode_READ], + 1 - arg2val->packed, + read_not1), + FMT(this->annotation_prefix, " read_not1")); /* will be nonzero for read X for X != 1 */ + this->pb.add_r1cs_constraint(r1cs_constraint(read_not1, + 1 - instruction_flags[tinyram_opcode_READ], + 0), + FMT(this->annotation_prefix, " other_reads_imply_flag")); + this->pb.add_r1cs_constraint(r1cs_constraint(instruction_flags[tinyram_opcode_READ], + instruction_results[tinyram_opcode_READ], + 0), + FMT(this->annotation_prefix, " read_flag_implies_result_0")); +} + +template +void tinyram_cpu_checker::generate_r1cs_witness_address() +{ + /* decode instruction and arguments */ + prev_pc_addr_as_word_variable->generate_r1cs_witness_from_bits(); + for (size_t i = 0; i < this->pb.ap.k; ++i) + { + prev_registers[i].generate_r1cs_witness_from_bits(); + } + + decode_arguments->generate_r1cs_witness(); + + desval->generate_r1cs_witness_from_packed(); + arg1val->generate_r1cs_witness_from_packed(); + arg2val->generate_r1cs_witness_from_packed(); + + /* clear out ls_addr and fill with everything of arg2val except the subaddress */ + ls_addr.fill_with_bits_of_field_element(this->pb, this->pb.val(arg2val->packed).as_ulong() >> this->pb.ap.subaddr_len()); +} + +template +void tinyram_cpu_checker::generate_r1cs_witness_other(tinyram_input_tape_iterator &aux_it, + const tinyram_input_tape_iterator &aux_end) +{ + /* now ls_prev_val is filled with memory contents at ls_addr. we + now ensure consistency with its doubleword representation */ + ls_prev_val_as_doubleword_variable->generate_r1cs_witness_from_bits(); + + /* fill in the opcode indicators */ + const size_t opcode_val = opcode.get_field_element_from_bits(this->pb).as_ulong(); + for (size_t i = 0; i < 1ul<pb.ap.opcode_width(); ++i) + { + this->pb.val(opcode_indicators[i]) = (i == opcode_val ? FieldT::one() : FieldT::zero()); + } + + /* execute the ALU */ + ALU->generate_r1cs_witness(); + + /* fill memory_subaddress */ + memory_subaddress->bits.fill_with_bits(this->pb, pb_variable_array(arg2val->bits.begin(), + arg2val->bits.begin() + + this->pb.ap.subaddr_len()).get_bits(this->pb)); + memory_subaddress->generate_r1cs_witness_from_bits(); + + /* we distinguish four cases for memory handling: + a) load.b + b) store.b + c) store.w + d) load.w or any non-memory instruction */ + const size_t prev_doubleword = this->pb.val(ls_prev_val_as_doubleword_variable->packed).as_ulong(); + const size_t subaddress = this->pb.val(memory_subaddress->packed).as_ulong(); + + if (this->pb.val(opcode_indicators[tinyram_opcode_LOADB]) == FieldT::one()) + { + const size_t loaded_byte = (prev_doubleword >> (8 * subaddress)) & 0xFF; + this->pb.val(instruction_results[tinyram_opcode_LOADB]) = FieldT(loaded_byte); + this->pb.val(memory_subcontents) = FieldT(loaded_byte); + } + else if (this->pb.val(opcode_indicators[tinyram_opcode_STOREB]) == FieldT::one()) + { + const size_t stored_byte = (this->pb.val(desval->packed).as_ulong()) & 0xFF; + this->pb.val(memory_subcontents) = FieldT(stored_byte); + } + else if (this->pb.val(opcode_indicators[tinyram_opcode_STOREW]) == FieldT::one()) + { + const size_t stored_word = (this->pb.val(desval->packed).as_ulong()); + this->pb.val(memory_subcontents) = FieldT(stored_word); + } + else + { + const bool access_is_word0 = (this->pb.val(*memory_subaddress->bits.rbegin()) == FieldT::zero()); + const size_t loaded_word = (prev_doubleword >> (access_is_word0 ? 0 : this->pb.ap.w)) & ((1ul << this->pb.ap.w) - 1); + this->pb.val(instruction_results[tinyram_opcode_LOADW]) = FieldT(loaded_word); /* does not hurt even for non-memory instructions */ + this->pb.val(memory_subcontents) = FieldT(loaded_word); + } + + memory_access_is_word.evaluate(this->pb); + memory_access_is_byte.evaluate(this->pb); + + check_memory->generate_r1cs_witness(); + + /* handle reads */ + if (this->pb.val(prev_tape1_exhausted) == FieldT::one()) + { + /* if tape was exhausted before, it will always be + exhausted. we also need to only handle reads from tape 1, + so we can safely set flag here */ + this->pb.val(next_tape1_exhausted) = FieldT::one(); + this->pb.val(instruction_flags[tinyram_opcode_READ]) = FieldT::one(); + } + + this->pb.val(read_not1) = this->pb.val(opcode_indicators[tinyram_opcode_READ]) * (FieldT::one() - this->pb.val(arg2val->packed)); + if (this->pb.val(read_not1) != FieldT::one()) + { + /* reading from tape other than 0 raises the flag */ + this->pb.val(instruction_flags[tinyram_opcode_READ]) = FieldT::one(); + } + else + { + /* otherwise perform the actual read */ + if (aux_it != aux_end) + { + this->pb.val(instruction_results[tinyram_opcode_READ]) = FieldT(*aux_it); + if (++aux_it == aux_end) + { + /* tape has ended! */ + this->pb.val(next_tape1_exhausted) = FieldT::one(); + } + } + else + { + /* handled above, so nothing to do here */ + } + } + + /* flag implies result zero */ + if (this->pb.val(instruction_flags[tinyram_opcode_READ]) == FieldT::one()) + { + this->pb.val(instruction_results[tinyram_opcode_READ]) = FieldT::zero(); + } + + /* execute consistency enforcer */ + consistency_enforcer->generate_r1cs_witness(); + next_pc_addr_as_word_variable->generate_r1cs_witness_from_packed(); + + for (size_t i = 0; i < this->pb.ap.k; ++i) + { + next_registers[i].generate_r1cs_witness_from_packed(); + } + + /* finally set has_accepted to 1 if both the opcode is ANSWER and arg2val is 0 */ + this->pb.val(next_has_accepted) = (this->pb.val(opcode_indicators[tinyram_opcode_ANSWER]) == FieldT::one() && + this->pb.val(arg2val->packed) == FieldT::zero()) ? FieldT::one() : FieldT::zero(); +} + +template +void tinyram_cpu_checker::dump() const +{ + printf(" pc = %lu, flag = %lu\n", + this->pb.val(prev_pc_addr_as_word_variable->packed).as_ulong(), + this->pb.val(prev_flag).as_ulong()); + printf(" "); + + for (size_t j = 0; j < this->pb.ap.k; ++j) + { + printf("r%zu = %2lu ", j, this->pb.val(prev_registers[j].packed).as_ulong()); + } + printf("\n"); + + const size_t opcode_val = opcode.get_field_element_from_bits(this->pb).as_ulong(); + printf(" %s r%lu, r%lu, %s%lu\n", + tinyram_opcode_names[static_cast(opcode_val)].c_str(), + desidx.get_field_element_from_bits(this->pb).as_ulong(), + arg1idx.get_field_element_from_bits(this->pb).as_ulong(), + (this->pb.val(arg2_is_imm) == FieldT::one() ? "" : "r"), + arg2idx.get_field_element_from_bits(this->pb).as_ulong()); +} + +} // libsnark + +#endif // TINYRAM_CPU_CHECKER_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/curves/weierstrass_g1_gadget.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/curves/weierstrass_g1_gadget.hpp new file mode 100644 index 0000000..337360a --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/curves/weierstrass_g1_gadget.hpp @@ -0,0 +1,153 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for G1 gadgets. + + The gadgets verify curve arithmetic in G1 = E(F) where E/F: y^2 = x^3 + A * X + B + is an elliptic curve over F in short Weierstrass form. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WEIERSTRASS_G1_GADGET_HPP_ +#define WEIERSTRASS_G1_GADGET_HPP_ + +#include "gadgetlib1/gadget.hpp" +#include "gadgetlib1/gadgets/pairing/pairing_params.hpp" + +namespace libsnark { + +/** + * Gadget that represents a G1 variable. + */ +template +class G1_variable : public gadget > { +public: + typedef Fr FieldT; + + pb_linear_combination X; + pb_linear_combination Y; + + pb_linear_combination_array all_vars; + + G1_variable(protoboard &pb, + const std::string &annotation_prefix); + G1_variable(protoboard &pb, + const G1 > &P, + const std::string &annotation_prefix); + + void generate_r1cs_witness(const G1 > &elt); + + // (See a comment in r1cs_ppzksnark_verifier_gadget.hpp about why + // we mark this function noinline.) TODO: remove later + static size_t __attribute__((noinline)) size_in_bits(); + static size_t num_variables(); +}; + +/** + * Gadget that creates constraints for the validity of a G1 variable. + */ +template +class G1_checker_gadget : public gadget > { +public: + typedef Fr FieldT; + + G1_variable P; + pb_variable P_X_squared; + pb_variable P_Y_squared; + + G1_checker_gadget(protoboard &pb, + const G1_variable &P, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that creates constraints for G1 addition. + */ +template +class G1_add_gadget : public gadget > { +public: + typedef Fr FieldT; + + pb_variable lambda; + pb_variable inv; + + G1_variable A; + G1_variable B; + G1_variable C; + + G1_add_gadget(protoboard &pb, + const G1_variable &A, + const G1_variable &B, + const G1_variable &C, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that creates constraints for G1 doubling. + */ +template +class G1_dbl_gadget : public gadget > { +public: + typedef Fr FieldT; + + pb_variable Xsquared; + pb_variable lambda; + + G1_variable A; + G1_variable B; + + G1_dbl_gadget(protoboard &pb, + const G1_variable &A, + const G1_variable &B, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that creates constraints for G1 multi-scalar multiplication. + */ +template +class G1_multiscalar_mul_gadget : public gadget > { +public: + typedef Fr FieldT; + + std::vector > computed_results; + std::vector > chosen_results; + std::vector > adders; + std::vector > doublers; + + G1_variable base; + pb_variable_array scalars; + std::vector > points; + std::vector > points_and_powers; + G1_variable result; + + const size_t elt_size; + const size_t num_points; + const size_t scalar_size; + + G1_multiscalar_mul_gadget(protoboard &pb, + const G1_variable &base, + const pb_variable_array &scalars, + const size_t elt_size, + const std::vector > &points, + const G1_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/curves/weierstrass_g1_gadget.tcc" + +#endif // WEIERSTRASS_G1_GADGET_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/curves/weierstrass_g1_gadget.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/curves/weierstrass_g1_gadget.tcc new file mode 100644 index 0000000..d840108 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/curves/weierstrass_g1_gadget.tcc @@ -0,0 +1,326 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for G1 gadgets. + + See weierstrass_g1_gadgets.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WEIERSTRASS_G1_GADGET_TCC_ +#define WEIERSTRASS_G1_GADGET_TCC_ + +namespace libsnark { + +template +G1_variable::G1_variable(protoboard &pb, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + pb_variable X_var, Y_var; + + X_var.allocate(pb, FMT(annotation_prefix, " X")); + Y_var.allocate(pb, FMT(annotation_prefix, " Y")); + + X = pb_linear_combination(X_var); + Y = pb_linear_combination(Y_var); + + all_vars.emplace_back(X); + all_vars.emplace_back(Y); +} + +template +G1_variable::G1_variable(protoboard &pb, + const G1 > &P, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + G1 > Pcopy = P; + Pcopy.to_affine_coordinates(); + + X.assign(pb, Pcopy.X()); + Y.assign(pb, Pcopy.Y()); + X.evaluate(pb); + Y.evaluate(pb); + all_vars.emplace_back(X); + all_vars.emplace_back(Y); +} + +template +void G1_variable::generate_r1cs_witness(const G1 > &el) +{ + G1 > el_normalized = el; + el_normalized.to_affine_coordinates(); + + this->pb.lc_val(X) = el_normalized.X(); + this->pb.lc_val(Y) = el_normalized.Y(); +} + +template +size_t G1_variable::size_in_bits() +{ + return 2 * FieldT::size_in_bits(); +} + +template +size_t G1_variable::num_variables() +{ + return 2; +} + +template +G1_checker_gadget::G1_checker_gadget(protoboard &pb, const G1_variable &P, const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), P(P) +{ + P_X_squared.allocate(pb, FMT(annotation_prefix, " P_X_squared")); + P_Y_squared.allocate(pb, FMT(annotation_prefix, " P_Y_squared")); +} + +template +void G1_checker_gadget::generate_r1cs_constraints() +{ + this->pb.add_r1cs_constraint(r1cs_constraint( + { P.X }, + { P.X }, + { P_X_squared }), + FMT(this->annotation_prefix, " P_X_squared")); + this->pb.add_r1cs_constraint(r1cs_constraint( + { P.Y }, + { P.Y }, + { P_Y_squared }), + FMT(this->annotation_prefix, " P_Y_squared")); + this->pb.add_r1cs_constraint(r1cs_constraint( + { P.X }, + { P_X_squared, ONE * G1 >::coeff_a }, + { P_Y_squared, ONE * (-G1 >::coeff_b) }), + FMT(this->annotation_prefix, " curve_equation")); +} + +template +void G1_checker_gadget::generate_r1cs_witness() +{ + this->pb.val(P_X_squared) = this->pb.lc_val(P.X).squared(); + this->pb.val(P_Y_squared) = this->pb.lc_val(P.Y).squared(); +} + +template +G1_add_gadget::G1_add_gadget(protoboard &pb, + const G1_variable &A, + const G1_variable &B, + const G1_variable &C, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + A(A), + B(B), + C(C) +{ + /* + lambda = (B.y - A.y)/(B.x - A.x) + C.x = lambda^2 - A.x - B.x + C.y = lambda(A.x - C.x) - A.y + + Special cases: + + doubling: if B.y = A.y and B.x = A.x then lambda is unbound and + C = (lambda^2, lambda^3) + + addition of negative point: if B.y = -A.y and B.x = A.x then no + lambda can satisfy the first equation unless B.y - A.y = 0. But + then this reduces to doubling. + + So we need to check that A.x - B.x != 0, which can be done by + enforcing I * (B.x - A.x) = 1 + */ + lambda.allocate(pb, FMT(annotation_prefix, " lambda")); + inv.allocate(pb, FMT(annotation_prefix, " inv")); +} + +template +void G1_add_gadget::generate_r1cs_constraints() +{ + this->pb.add_r1cs_constraint(r1cs_constraint( + { lambda }, + { B.X, A.X * (-1) }, + { B.Y, A.Y * (-1) }), + FMT(this->annotation_prefix, " calc_lambda")); + + this->pb.add_r1cs_constraint(r1cs_constraint( + { lambda }, + { lambda }, + { C.X, A.X, B.X }), + FMT(this->annotation_prefix, " calc_X")); + + this->pb.add_r1cs_constraint(r1cs_constraint( + { lambda }, + { A.X, C.X * (-1) }, + { C.Y, A.Y }), + FMT(this->annotation_prefix, " calc_Y")); + + this->pb.add_r1cs_constraint(r1cs_constraint( + { inv }, + { B.X, A.X * (-1) }, + { ONE }), + FMT(this->annotation_prefix, " no_special_cases")); +} + +template +void G1_add_gadget::generate_r1cs_witness() +{ + this->pb.val(inv) = (this->pb.lc_val(B.X) - this->pb.lc_val(A.X)).inverse(); + this->pb.val(lambda) = (this->pb.lc_val(B.Y) - this->pb.lc_val(A.Y)) * this->pb.val(inv); + this->pb.lc_val(C.X) = this->pb.val(lambda).squared() - this->pb.lc_val(A.X) - this->pb.lc_val(B.X); + this->pb.lc_val(C.Y) = this->pb.val(lambda) * (this->pb.lc_val(A.X) - this->pb.lc_val(C.X)) - this->pb.lc_val(A.Y); +} + +template +G1_dbl_gadget::G1_dbl_gadget(protoboard &pb, + const G1_variable &A, + const G1_variable &B, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + A(A), + B(B) +{ + Xsquared.allocate(pb, FMT(annotation_prefix, " X_squared")); + lambda.allocate(pb, FMT(annotation_prefix, " lambda")); +} + +template +void G1_dbl_gadget::generate_r1cs_constraints() +{ + this->pb.add_r1cs_constraint(r1cs_constraint( + { A.X }, + { A.X }, + { Xsquared }), + FMT(this->annotation_prefix, " calc_Xsquared")); + + this->pb.add_r1cs_constraint(r1cs_constraint( + { lambda * 2 }, + { A.Y }, + { Xsquared * 3, ONE * G1 >::coeff_a }), + FMT(this->annotation_prefix, " calc_lambda")); + + this->pb.add_r1cs_constraint(r1cs_constraint( + { lambda }, + { lambda }, + { B.X, A.X * 2 }), + FMT(this->annotation_prefix, " calc_X")); + + this->pb.add_r1cs_constraint(r1cs_constraint( + { lambda }, + { A.X, B.X * (-1) }, + { B.Y, A.Y }), + FMT(this->annotation_prefix, " calc_Y")); +} + +template +void G1_dbl_gadget::generate_r1cs_witness() +{ + this->pb.val(Xsquared) = this->pb.lc_val(A.X).squared(); + this->pb.val(lambda) = (FieldT(3) * this->pb.val(Xsquared) + G1 >::coeff_a) * (FieldT(2) * this->pb.lc_val(A.Y)).inverse(); + this->pb.lc_val(B.X) = this->pb.val(lambda).squared() - FieldT(2) * this->pb.lc_val(A.X); + this->pb.lc_val(B.Y) = this->pb.val(lambda) * (this->pb.lc_val(A.X) - this->pb.lc_val(B.X)) - this->pb.lc_val(A.Y); +} + +template +G1_multiscalar_mul_gadget::G1_multiscalar_mul_gadget(protoboard &pb, + const G1_variable &base, + const pb_variable_array &scalars, + const size_t elt_size, + const std::vector > &points, + const G1_variable&result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + base(base), + scalars(scalars), + points(points), + result(result), + elt_size(elt_size), + num_points(points.size()), + scalar_size(scalars.size()) +{ + assert(num_points >= 1); + assert(num_points * elt_size == scalar_size); + + for (size_t i = 0; i < num_points; ++i) + { + points_and_powers.emplace_back(points[i]); + for (size_t j = 0; j < elt_size - 1; ++j) + { + points_and_powers.emplace_back(G1_variable(pb, FMT(annotation_prefix, " points_%zu_times_2_to_%zu", i, j+1))); + doublers.emplace_back(G1_dbl_gadget(pb, points_and_powers[i*elt_size + j], points_and_powers[i*elt_size + j + 1], FMT(annotation_prefix, " double_%zu_to_2_to_%zu", i, j+1))); + } + } + + chosen_results.emplace_back(base); + for (size_t i = 0; i < scalar_size; ++i) + { + computed_results.emplace_back(G1_variable(pb, FMT(annotation_prefix, " computed_results_%zu"))); + if (i < scalar_size-1) + { + chosen_results.emplace_back(G1_variable(pb, FMT(annotation_prefix, " chosen_results_%zu"))); + } + else + { + chosen_results.emplace_back(result); + } + + adders.emplace_back(G1_add_gadget(pb, chosen_results[i], points_and_powers[i], computed_results[i], FMT(annotation_prefix, " adders_%zu"))); + } +} + +template +void G1_multiscalar_mul_gadget::generate_r1cs_constraints() +{ + const size_t num_constraints_before = this->pb.num_constraints(); + + for (size_t i = 0; i < scalar_size - num_points; ++i) + { + doublers[i].generate_r1cs_constraints(); + } + + for (size_t i = 0; i < scalar_size; ++i) + { + adders[i].generate_r1cs_constraints(); + + /* + chosen_results[i+1].X = scalars[i] * computed_results[i].X + (1-scalars[i]) * chosen_results[i].X + chosen_results[i+1].X - chosen_results[i].X = scalars[i] * (computed_results[i].X - chosen_results[i].X) + */ + this->pb.add_r1cs_constraint(r1cs_constraint(scalars[i], + computed_results[i].X - chosen_results[i].X, + chosen_results[i+1].X - chosen_results[i].X), + FMT(this->annotation_prefix, " chosen_results_%zu_X", i+1)); + this->pb.add_r1cs_constraint(r1cs_constraint(scalars[i], + computed_results[i].Y - chosen_results[i].Y, + chosen_results[i+1].Y - chosen_results[i].Y), + FMT(this->annotation_prefix, " chosen_results_%zu_Y", i+1)); + } + + const size_t num_constraints_after = this->pb.num_constraints(); + assert(num_constraints_after - num_constraints_before == 4 * (scalar_size-num_points) + (4 + 2) * scalar_size); +} + +template +void G1_multiscalar_mul_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < scalar_size - num_points; ++i) + { + doublers[i].generate_r1cs_witness(); + } + + for (size_t i = 0; i < scalar_size; ++i) + { + adders[i].generate_r1cs_witness(); + this->pb.lc_val(chosen_results[i+1].X) = (this->pb.val(scalars[i]) == Fr::zero() ? this->pb.lc_val(chosen_results[i].X) : this->pb.lc_val(computed_results[i].X)); + this->pb.lc_val(chosen_results[i+1].Y) = (this->pb.val(scalars[i]) == Fr::zero() ? this->pb.lc_val(chosen_results[i].Y) : this->pb.lc_val(computed_results[i].Y)); + } +} + +} // libsnark + +#endif // WEIERSTRASS_G1_GADGET_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/curves/weierstrass_g2_gadget.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/curves/weierstrass_g2_gadget.hpp new file mode 100644 index 0000000..6310827 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/curves/weierstrass_g2_gadget.hpp @@ -0,0 +1,84 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for G2 gadgets. + + The gadgets verify curve arithmetic in G2 = E'(F) where E'/F^e: y^2 = x^3 + A' * X + B' + is an elliptic curve over F^e in short Weierstrass form. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WEIERSTRASS_G2_GADGET_HPP_ +#define WEIERSTRASS_G2_GADGET_HPP_ + +#include "gadgetlib1/gadget.hpp" +#include "gadgetlib1/gadgets/pairing/pairing_params.hpp" + +namespace libsnark { + +/** + * Gadget that represents a G2 variable. + */ +template +class G2_variable : public gadget > { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + std::shared_ptr > X; + std::shared_ptr > Y; + + pb_linear_combination_array all_vars; + + G2_variable(protoboard &pb, + const std::string &annotation_prefix); + G2_variable(protoboard &pb, + const G2 > &Q, + const std::string &annotation_prefix); + + void generate_r1cs_witness(const G2 > &Q); + + // (See a comment in r1cs_ppzksnark_verifier_gadget.hpp about why + // we mark this function noinline.) TODO: remove later + static size_t __attribute__((noinline)) size_in_bits(); + static size_t num_variables(); +}; + +/** + * Gadget that creates constraints for the validity of a G2 variable. + */ +template +class G2_checker_gadget : public gadget > { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + G2_variable Q; + + std::shared_ptr > Xsquared; + std::shared_ptr > Ysquared; + std::shared_ptr > Xsquared_plus_a; + std::shared_ptr > Ysquared_minus_b; + + std::shared_ptr > compute_Xsquared; + std::shared_ptr > compute_Ysquared; + std::shared_ptr > curve_equation; + + G2_checker_gadget(protoboard &pb, + const G2_variable &Q, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/curves/weierstrass_g2_gadget.tcc" + +#endif // WEIERSTRASS_G2_GADGET_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/curves/weierstrass_g2_gadget.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/curves/weierstrass_g2_gadget.tcc new file mode 100644 index 0000000..7e5dc48 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/curves/weierstrass_g2_gadget.tcc @@ -0,0 +1,130 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for G2 gadgets. + + See weierstrass_g2_gadgets.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WEIERSTRASS_G2_GADGET_TCC_ +#define WEIERSTRASS_G2_GADGET_TCC_ + +#include "algebra/scalar_multiplication/wnaf.hpp" + +namespace libsnark { + +template +G2_variable::G2_variable(protoboard &pb, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + X.reset(new Fqe_variable(pb, FMT(annotation_prefix, " X"))); + Y.reset(new Fqe_variable(pb, FMT(annotation_prefix, " Y"))); + + all_vars.insert(all_vars.end(), X->all_vars.begin(), X->all_vars.end()); + all_vars.insert(all_vars.end(), Y->all_vars.begin(), Y->all_vars.end()); +} + +template +G2_variable::G2_variable(protoboard &pb, + const G2 > &Q, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + G2 > Q_copy = Q; + Q_copy.to_affine_coordinates(); + + X.reset(new Fqe_variable(pb, Q_copy.X(), FMT(annotation_prefix, " X"))); + Y.reset(new Fqe_variable(pb, Q_copy.Y(), FMT(annotation_prefix, " Y"))); + + all_vars.insert(all_vars.end(), X->all_vars.begin(), X->all_vars.end()); + all_vars.insert(all_vars.end(), Y->all_vars.begin(), Y->all_vars.end()); +} + +template +void G2_variable::generate_r1cs_witness(const G2 > &Q) +{ + G2 > Qcopy = Q; + Qcopy.to_affine_coordinates(); + + X->generate_r1cs_witness(Qcopy.X()); + Y->generate_r1cs_witness(Qcopy.Y()); +} + +template +size_t G2_variable::size_in_bits() +{ + return 2 * Fqe_variable::size_in_bits(); +} + +template +size_t G2_variable::num_variables() +{ + return 2 * Fqe_variable::num_variables(); +} + +template +G2_checker_gadget::G2_checker_gadget(protoboard &pb, + const G2_variable &Q, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + Q(Q) +{ + Xsquared.reset(new Fqe_variable(pb, FMT(annotation_prefix, " Xsquared"))); + Ysquared.reset(new Fqe_variable(pb, FMT(annotation_prefix, " Ysquared"))); + + compute_Xsquared.reset(new Fqe_sqr_gadget(pb, *(Q.X), *Xsquared, FMT(annotation_prefix, " compute_Xsquared"))); + compute_Ysquared.reset(new Fqe_sqr_gadget(pb, *(Q.Y), *Ysquared, FMT(annotation_prefix, " compute_Ysquared"))); + + Xsquared_plus_a.reset(new Fqe_variable((*Xsquared) + G2 >::coeff_a)); + Ysquared_minus_b.reset(new Fqe_variable((*Ysquared) + (-G2 >::coeff_b))); + + curve_equation.reset(new Fqe_mul_gadget(pb, *(Q.X), *Xsquared_plus_a, *Ysquared_minus_b, FMT(annotation_prefix, " curve_equation"))); +} + +template +void G2_checker_gadget::generate_r1cs_constraints() +{ + compute_Xsquared->generate_r1cs_constraints(); + compute_Ysquared->generate_r1cs_constraints(); + curve_equation->generate_r1cs_constraints(); +} + +template +void G2_checker_gadget::generate_r1cs_witness() +{ + compute_Xsquared->generate_r1cs_witness(); + compute_Ysquared->generate_r1cs_witness(); + Xsquared_plus_a->evaluate(); + curve_equation->generate_r1cs_witness(); +} + +template +void test_G2_checker_gadget(const std::string &annotation) +{ + protoboard > pb; + G2_variable g(pb, "g"); + G2_checker_gadget g_check(pb, g, "g_check"); + g_check.generate_r1cs_constraints(); + + printf("positive test\n"); + g.generate_r1cs_witness(G2 >::one()); + g_check.generate_r1cs_witness(); + assert(pb.is_satisfied()); + + printf("negative test\n"); + g.generate_r1cs_witness(G2 >::zero()); + g_check.generate_r1cs_witness(); + assert(!pb.is_satisfied()); + + printf("number of constraints for G2 checker (Fr is %s) = %zu\n", annotation.c_str(), pb.num_constraints()); +} + +} // libsnark + +#endif // WEIERSTRASS_G2_GADGET_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/delegated_ra_memory/memory_load_gadget.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/delegated_ra_memory/memory_load_gadget.hpp new file mode 100644 index 0000000..09a4c5b --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/delegated_ra_memory/memory_load_gadget.hpp @@ -0,0 +1,25 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the memory load gadget. + The gadget can be used to verify a memory load from a "delegated memory". + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MEMORY_LOAD_GADGET_HPP_ +#define MEMORY_LOAD_GADGET_HPP_ + +#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp" + +namespace libsnark { + +template +using memory_load_gadget = merkle_tree_check_read_gadget; + +} // libsnark + +#endif // MEMORY_LOAD_GADGET_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/delegated_ra_memory/memory_load_store_gadget.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/delegated_ra_memory/memory_load_store_gadget.hpp new file mode 100644 index 0000000..222a1dc --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/delegated_ra_memory/memory_load_store_gadget.hpp @@ -0,0 +1,27 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the memory load&store gadget. + + The gadget can be used to verify a memory load, followed by a store to the + same address, from a "delegated memory". + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MEMORY_LOAD_STORE_GADGET_HPP_ +#define MEMORY_LOAD_STORE_GADGET_HPP_ + +#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp" + +namespace libsnark { + +template +using memory_load_store_gadget = merkle_tree_check_update_gadget; + +} // libsnark + +#endif // MEMORY_LOAD_STORE_GADGET_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/fields/exponentiation_gadget.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/fields/exponentiation_gadget.hpp new file mode 100644 index 0000000..f54b786 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/fields/exponentiation_gadget.hpp @@ -0,0 +1,64 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the exponentiation gadget. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EXPONENTIATION_GADGET_HPP_ +#define EXPONENTIATION_GADGET_HPP_ + +#include +#include +#include "algebra/fields/bigint.hpp" +#include "algebra/scalar_multiplication/wnaf.hpp" +#include "gadgetlib1/gadget.hpp" + +namespace libsnark { + +/** + * The exponentiation gadget verifies field exponentiation in the field F_{p^k}. + * + * Note that the power is a constant (i.e., hardcoded into the gadget). + */ +template class Fpk_variableT, template class Fpk_mul_gadgetT, template class Fpk_sqr_gadgetT, mp_size_t m> +class exponentiation_gadget : gadget { +public: + typedef typename FpkT::my_Fp FieldT; + std::vector NAF; + + std::vector > > intermediate; + std::vector > > addition_steps; + std::vector > > subtraction_steps; + std::vector > > doubling_steps; + + Fpk_variableT elt; + bigint power; + Fpk_variableT result; + + size_t intermed_count; + size_t add_count; + size_t sub_count; + size_t dbl_count; + + exponentiation_gadget(protoboard &pb, + const Fpk_variableT &elt, + const bigint &power, + const Fpk_variableT &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template class Fpk_variableT, template class Fpk_mul_gadgetT, template class Fpk_sqr_gadgetT, mp_size_t m> +void test_exponentiation_gadget(const bigint &power, const std::string &annotation); + +} // libsnark + +#include "gadgetlib1/gadgets/fields/exponentiation_gadget.tcc" + +#endif // EXPONENTIATION_GADGET_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/fields/exponentiation_gadget.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/fields/exponentiation_gadget.tcc new file mode 100644 index 0000000..d65f7ac --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/fields/exponentiation_gadget.tcc @@ -0,0 +1,206 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the exponentiation gadget. + + See exponentiation_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EXPONENTIATION_GADGET_TCC_ +#define EXPONENTIATION_GADGET_TCC_ + +namespace libsnark { + +template class Fpk_variableT, template class Fpk_mul_gadgetT, template class Fpk_sqr_gadgetT, mp_size_t m> +exponentiation_gadget::exponentiation_gadget(protoboard &pb, + const Fpk_variableT &elt, + const bigint &power, + const Fpk_variableT &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), elt(elt), power(power), result(result) +{ + NAF = find_wnaf(1, power); + + intermed_count = 0; + add_count = 0; + sub_count = 0; + dbl_count = 0; + + bool found_nonzero = false; + for (long i = NAF.size() - 1; i >= 0; --i) + { + if (found_nonzero) + { + ++dbl_count; + ++intermed_count; + } + + if (NAF[i] != 0) + { + found_nonzero = true; + + if (NAF[i] > 0) + { + ++add_count; + ++intermed_count; + } + else + { + ++sub_count; + ++intermed_count; + } + } + } + + intermediate.resize(intermed_count); + intermediate[0].reset(new Fpk_variableT(pb, FpkT::one(), FMT(annotation_prefix, " intermediate_0"))); + for (size_t i = 1; i < intermed_count; ++i) + { + intermediate[i].reset(new Fpk_variableT(pb, FMT(annotation_prefix, " intermediate_%zu", i))); + } + addition_steps.resize(add_count); + subtraction_steps.resize(sub_count); + doubling_steps.resize(dbl_count); + + found_nonzero = false; + + size_t dbl_id = 0, add_id = 0, sub_id = 0, intermed_id = 0; + + for (long i = NAF.size() - 1; i >= 0; --i) + { + if (found_nonzero) + { + doubling_steps[dbl_id].reset(new Fpk_sqr_gadgetT(pb, + *intermediate[intermed_id], + (intermed_id + 1 == intermed_count ? result : *intermediate[intermed_id+1]), + FMT(annotation_prefix, " doubling_steps_%zu", dbl_count))); + ++intermed_id; + ++dbl_id; + } + + if (NAF[i] != 0) + { + found_nonzero = true; + + if (NAF[i] > 0) + { + /* next = cur * elt */ + addition_steps[add_id].reset(new Fpk_mul_gadgetT(pb, + *intermediate[intermed_id], + elt, + (intermed_id + 1 == intermed_count ? result : *intermediate[intermed_id+1]), + FMT(annotation_prefix, " addition_steps_%zu", dbl_count))); + ++add_id; + ++intermed_id; + } + else + { + /* next = cur / elt, i.e. next * elt = cur */ + subtraction_steps[sub_id].reset(new Fpk_mul_gadgetT(pb, + (intermed_id + 1 == intermed_count ? result : *intermediate[intermed_id+1]), + elt, + *intermediate[intermed_id], + FMT(annotation_prefix, " subtraction_steps_%zu", dbl_count))); + ++sub_id; + ++intermed_id; + } + } + } +} + +template class Fpk_variableT, template class Fpk_mul_gadgetT, template class Fpk_sqr_gadgetT, mp_size_t m> +void exponentiation_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < add_count; ++i) + { + addition_steps[i]->generate_r1cs_constraints(); + } + + for (size_t i = 0; i < sub_count; ++i) + { + subtraction_steps[i]->generate_r1cs_constraints(); + } + + for (size_t i = 0; i < dbl_count; ++i) + { + doubling_steps[i]->generate_r1cs_constraints(); + } +} + +template class Fpk_variableT, template class Fpk_mul_gadgetT, template class Fpk_sqr_gadgetT, mp_size_t m> +void exponentiation_gadget::generate_r1cs_witness() +{ + intermediate[0]->generate_r1cs_witness(FpkT::one()); + + bool found_nonzero = false; + size_t dbl_id = 0, add_id = 0, sub_id = 0, intermed_id = 0; + + for (long i = NAF.size() - 1; i >= 0; --i) + { + if (found_nonzero) + { + doubling_steps[dbl_id]->generate_r1cs_witness(); + ++intermed_id; + ++dbl_id; + } + + if (NAF[i] != 0) + { + found_nonzero = true; + + if (NAF[i] > 0) + { + addition_steps[add_id]->generate_r1cs_witness(); + ++intermed_id; + ++add_id; + } + else + { + const FpkT cur_val = intermediate[intermed_id]->get_element(); + const FpkT elt_val = elt.get_element(); + const FpkT next_val = cur_val * elt_val.inverse(); + + (intermed_id + 1 == intermed_count ? result : *intermediate[intermed_id+1]).generate_r1cs_witness(next_val); + + subtraction_steps[sub_id]->generate_r1cs_witness(); + + ++intermed_id; + ++sub_id; + } + } + } +} + +template class Fpk_variableT, template class Fpk_mul_gadgetT, template class Fpk_sqr_gadgetT, mp_size_t m> +void test_exponentiation_gadget(const bigint &power, const std::string &annotation) +{ + typedef typename FpkT::my_Fp FieldT; + + protoboard pb; + Fpk_variableT x(pb, "x"); + Fpk_variableT x_to_power(pb, "x_to_power"); + exponentiation_gadget exp_gadget(pb, x, power, x_to_power, "exp_gadget"); + exp_gadget.generate_r1cs_constraints(); + + for (size_t i = 0; i < 10; ++i) + { + const FpkT x_val = FpkT::random_element(); + x.generate_r1cs_witness(x_val); + exp_gadget.generate_r1cs_witness(); + const FpkT res = x_to_power.get_element(); + assert(pb.is_satisfied()); + assert(res == (x_val ^ power)); + } + printf("number of constraints for %s_exp = %zu\n", annotation.c_str(), pb.num_constraints()); + printf("exponent was: "); + power.print(); +} + +} // libsnark + +#endif // EXPONENTIATION_GADGET_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/fields/fp2_gadgets.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/fields/fp2_gadgets.hpp new file mode 100644 index 0000000..ac968fd --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/fields/fp2_gadgets.hpp @@ -0,0 +1,132 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for Fp2 gadgets. + + The gadgets verify field arithmetic in Fp2 = Fp[U]/(U^2-non_residue), + where non_residue is in Fp. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP2_GADGETS_HPP_ +#define FP2_GADGETS_HPP_ + +#include "gadgetlib1/gadget.hpp" +#include + +namespace libsnark { + +/** + * Gadget that represents an Fp2 variable. + */ +template +class Fp2_variable : public gadget { +public: + typedef typename Fp2T::my_Fp FieldT; + + pb_linear_combination c0; + pb_linear_combination c1; + + pb_linear_combination_array all_vars; + + Fp2_variable(protoboard &pb, + const std::string &annotation_prefix); + Fp2_variable(protoboard &pb, + const Fp2T &el, + const std::string &annotation_prefix); + Fp2_variable(protoboard &pb, + const Fp2T &el, + const pb_linear_combination &coeff, + const std::string &annotation_prefix); + Fp2_variable(protoboard &pb, + const pb_linear_combination &c0, + const pb_linear_combination &c1, + const std::string &annotation_prefix); + + void generate_r1cs_equals_const_constraints(const Fp2T &el); + void generate_r1cs_witness(const Fp2T &el); + Fp2T get_element(); + + Fp2_variable operator*(const FieldT &coeff) const; + Fp2_variable operator+(const Fp2_variable &other) const; + Fp2_variable operator+(const Fp2T &other) const; + Fp2_variable mul_by_X() const; + void evaluate() const; + bool is_constant() const; + + static size_t size_in_bits(); + static size_t num_variables(); +}; + +/** + * Gadget that creates constraints for Fp2 by Fp2 multiplication. + */ +template +class Fp2_mul_gadget : public gadget { +public: + typedef typename Fp2T::my_Fp FieldT; + + Fp2_variable A; + Fp2_variable B; + Fp2_variable result; + + pb_variable v1; + + Fp2_mul_gadget(protoboard &pb, + const Fp2_variable &A, + const Fp2_variable &B, + const Fp2_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that creates constraints for Fp2 multiplication by a linear combination. + */ +template +class Fp2_mul_by_lc_gadget : public gadget { +public: + typedef typename Fp2T::my_Fp FieldT; + + Fp2_variable A; + pb_linear_combination lc; + Fp2_variable result; + + Fp2_mul_by_lc_gadget(protoboard &pb, + const Fp2_variable &A, + const pb_linear_combination &lc, + const Fp2_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that creates constraints for Fp2 squaring. + */ +template +class Fp2_sqr_gadget : public gadget { +public: + typedef typename Fp2T::my_Fp FieldT; + + Fp2_variable A; + Fp2_variable result; + + Fp2_sqr_gadget(protoboard &pb, + const Fp2_variable &A, + const Fp2_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/fields/fp2_gadgets.tcc" + +#endif // FP2_GADGETS_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/fields/fp2_gadgets.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/fields/fp2_gadgets.tcc new file mode 100644 index 0000000..2b080c2 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/fields/fp2_gadgets.tcc @@ -0,0 +1,281 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for Fp2 gadgets. + + See fp2_gadgets.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP2_GADGETS_TCC_ +#define FP2_GADGETS_TCC_ + +namespace libsnark { + +template +Fp2_variable::Fp2_variable(protoboard &pb, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + pb_variable c0_var, c1_var; + c0_var.allocate(pb, FMT(annotation_prefix, " c0")); + c1_var.allocate(pb, FMT(annotation_prefix, " c1")); + + c0 = pb_linear_combination(c0_var); + c1 = pb_linear_combination(c1_var); + + all_vars.emplace_back(c0); + all_vars.emplace_back(c1); +} + +template +Fp2_variable::Fp2_variable(protoboard &pb, + const Fp2T &el, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + c0.assign(pb, el.c0); + c1.assign(pb, el.c1); + + c0.evaluate(pb); + c1.evaluate(pb); + + all_vars.emplace_back(c0); + all_vars.emplace_back(c1); +} + +template +Fp2_variable::Fp2_variable(protoboard &pb, + const Fp2T &el, + const pb_linear_combination &coeff, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + c0.assign(pb, el.c0 * coeff); + c1.assign(pb, el.c1 * coeff); + + all_vars.emplace_back(c0); + all_vars.emplace_back(c1); +} + +template +Fp2_variable::Fp2_variable(protoboard &pb, + const pb_linear_combination &c0, + const pb_linear_combination &c1, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), c0(c0), c1(c1) +{ + all_vars.emplace_back(c0); + all_vars.emplace_back(c1); +} + +template +void Fp2_variable::generate_r1cs_equals_const_constraints(const Fp2T &el) +{ + this->pb.add_r1cs_constraint(r1cs_constraint(1, el.c0, c0), + FMT(this->annotation_prefix, " c0")); + this->pb.add_r1cs_constraint(r1cs_constraint(1, el.c1, c1), + FMT(this->annotation_prefix, " c1")); +} + +template +void Fp2_variable::generate_r1cs_witness(const Fp2T &el) +{ + this->pb.lc_val(c0) = el.c0; + this->pb.lc_val(c1) = el.c1; +} + +template +Fp2T Fp2_variable::get_element() +{ + Fp2T el; + el.c0 = this->pb.lc_val(c0); + el.c1 = this->pb.lc_val(c1); + return el; +} + +template +Fp2_variable Fp2_variable::operator*(const FieldT &coeff) const +{ + pb_linear_combination new_c0, new_c1; + new_c0.assign(this->pb, this->c0 * coeff); + new_c1.assign(this->pb, this->c1 * coeff); + return Fp2_variable(this->pb, new_c0, new_c1, FMT(this->annotation_prefix, " operator*")); +} + +template +Fp2_variable Fp2_variable::operator+(const Fp2_variable &other) const +{ + pb_linear_combination new_c0, new_c1; + new_c0.assign(this->pb, this->c0 + other.c0); + new_c1.assign(this->pb, this->c1 + other.c1); + return Fp2_variable(this->pb, new_c0, new_c1, FMT(this->annotation_prefix, " operator+")); +} + +template +Fp2_variable Fp2_variable::operator+(const Fp2T &other) const +{ + pb_linear_combination new_c0, new_c1; + new_c0.assign(this->pb, this->c0 + other.c0); + new_c1.assign(this->pb, this->c1 + other.c1); + return Fp2_variable(this->pb, new_c0, new_c1, FMT(this->annotation_prefix, " operator+")); +} + +template +Fp2_variable Fp2_variable::mul_by_X() const +{ + pb_linear_combination new_c0, new_c1; + new_c0.assign(this->pb, this->c1 * Fp2T::non_residue); + new_c1.assign(this->pb, this->c0); + return Fp2_variable(this->pb, new_c0, new_c1, FMT(this->annotation_prefix, " mul_by_X")); +} + +template +void Fp2_variable::evaluate() const +{ + c0.evaluate(this->pb); + c1.evaluate(this->pb); +} + +template +bool Fp2_variable::is_constant() const +{ + return (c0.is_constant() && c1.is_constant()); +} + +template +size_t Fp2_variable::size_in_bits() +{ + return 2 * FieldT::size_in_bits(); +} + +template +size_t Fp2_variable::num_variables() +{ + return 2; +} + +template +Fp2_mul_gadget::Fp2_mul_gadget(protoboard &pb, + const Fp2_variable &A, + const Fp2_variable &B, + const Fp2_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), B(B), result(result) +{ + v1.allocate(pb, FMT(annotation_prefix, " v1")); +} + +template +void Fp2_mul_gadget::generate_r1cs_constraints() +{ +/* + Karatsuba multiplication for Fp2: + v0 = A.c0 * B.c0 + v1 = A.c1 * B.c1 + result.c0 = v0 + non_residue * v1 + result.c1 = (A.c0 + A.c1) * (B.c0 + B.c1) - v0 - v1 + + Enforced with 3 constraints: + A.c1 * B.c1 = v1 + A.c0 * B.c0 = result.c0 - non_residue * v1 + (A.c0+A.c1)*(B.c0+B.c1) = result.c1 + result.c0 + (1 - non_residue) * v1 + + Reference: + "Multiplication and Squaring on Pairing-Friendly Fields" + Devegili, OhEigeartaigh, Scott, Dahab +*/ + this->pb.add_r1cs_constraint(r1cs_constraint(A.c1, B.c1, v1), + FMT(this->annotation_prefix, " v1")); + this->pb.add_r1cs_constraint(r1cs_constraint(A.c0, B.c0, result.c0 + v1 * (-Fp2T::non_residue)), + FMT(this->annotation_prefix, " result.c0")); + this->pb.add_r1cs_constraint(r1cs_constraint(A.c0 + A.c1, B.c0 + B.c1, + result.c1 + result.c0 + v1 * (FieldT::one() - Fp2T::non_residue)), + FMT(this->annotation_prefix, " result.c1")); +} + +template +void Fp2_mul_gadget::generate_r1cs_witness() +{ + const FieldT aA = this->pb.lc_val(A.c0) * this->pb.lc_val(B.c0); + this->pb.val(v1) = this->pb.lc_val(A.c1) * this->pb.lc_val(B.c1); + this->pb.lc_val(result.c0) = aA + Fp2T::non_residue * this->pb.val(v1); + this->pb.lc_val(result.c1) = (this->pb.lc_val(A.c0) + this->pb.lc_val(A.c1)) * (this->pb.lc_val(B.c0) + this->pb.lc_val(B.c1)) - aA - this->pb.lc_val(v1); +} + +template +Fp2_mul_by_lc_gadget::Fp2_mul_by_lc_gadget(protoboard &pb, + const Fp2_variable &A, + const pb_linear_combination &lc, + const Fp2_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), lc(lc), result(result) +{ +} + +template +void Fp2_mul_by_lc_gadget::generate_r1cs_constraints() +{ + this->pb.add_r1cs_constraint(r1cs_constraint(A.c0, lc, result.c0), + FMT(this->annotation_prefix, " result.c0")); + this->pb.add_r1cs_constraint(r1cs_constraint(A.c1, lc, result.c1), + FMT(this->annotation_prefix, " result.c1")); +} + +template +void Fp2_mul_by_lc_gadget::generate_r1cs_witness() +{ + this->pb.lc_val(result.c0) = this->pb.lc_val(A.c0) * this->pb.lc_val(lc); + this->pb.lc_val(result.c1) = this->pb.lc_val(A.c1) * this->pb.lc_val(lc); +} + +template +Fp2_sqr_gadget::Fp2_sqr_gadget(protoboard &pb, + const Fp2_variable &A, + const Fp2_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), result(result) +{ +} + +template +void Fp2_sqr_gadget::generate_r1cs_constraints() +{ +/* + Complex multiplication for Fp2: + v0 = A.c0 * A.c1 + result.c0 = (A.c0 + A.c1) * (A.c0 + non_residue * A.c1) - (1 + non_residue) * v0 + result.c1 = 2 * v0 + + Enforced with 2 constraints: + (2*A.c0) * A.c1 = result.c1 + (A.c0 + A.c1) * (A.c0 + non_residue * A.c1) = result.c0 + result.c1 * (1 + non_residue)/2 + + Reference: + "Multiplication and Squaring on Pairing-Friendly Fields" + Devegili, OhEigeartaigh, Scott, Dahab +*/ + this->pb.add_r1cs_constraint(r1cs_constraint(2 * A.c0, A.c1, result.c1), + FMT(this->annotation_prefix, " result.c1")); + this->pb.add_r1cs_constraint(r1cs_constraint(A.c0 + A.c1, + A.c0 + Fp2T::non_residue * A.c1, + result.c0 + result.c1 * (FieldT::one() + Fp2T::non_residue) * FieldT(2).inverse()), + FMT(this->annotation_prefix, " result.c0")); +} + +template +void Fp2_sqr_gadget::generate_r1cs_witness() +{ + const FieldT a = this->pb.lc_val(A.c0); + const FieldT b = this->pb.lc_val(A.c1); + this->pb.lc_val(result.c1) = FieldT(2) * a * b; + this->pb.lc_val(result.c0) = (a + b) * (a + Fp2T::non_residue * b) - a*b - Fp2T::non_residue * a* b; +} + +} // libsnark + +#endif // FP2_GADGETS_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/fields/fp3_gadgets.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/fields/fp3_gadgets.hpp new file mode 100644 index 0000000..4a6f4b1 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/fields/fp3_gadgets.hpp @@ -0,0 +1,135 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for Fp3 gadgets. + + The gadgets verify field arithmetic in Fp3 = Fp[U]/(U^3-non_residue), + where non_residue is in Fp. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP3_GADGETS_HPP_ +#define FP3_GADGETS_HPP_ + +namespace libsnark { + +/** + * Gadget that represents an Fp3 variable. + */ +template +class Fp3_variable : public gadget { +public: + typedef typename Fp3T::my_Fp FieldT; + + pb_linear_combination c0; + pb_linear_combination c1; + pb_linear_combination c2; + + pb_linear_combination_array all_vars; + + Fp3_variable(protoboard &pb, + const std::string &annotation_prefix); + Fp3_variable(protoboard &pb, + const Fp3T &el, + const std::string &annotation_prefix); + Fp3_variable(protoboard &pb, + const Fp3T &el, + const pb_linear_combination &coeff, + const std::string &annotation_prefix); + Fp3_variable(protoboard &pb, + const pb_linear_combination &c0, + const pb_linear_combination &c1, + const pb_linear_combination &c2, + const std::string &annotation_prefix); + + void generate_r1cs_equals_const_constraints(const Fp3T &el); + void generate_r1cs_witness(const Fp3T &el); + Fp3T get_element(); + + Fp3_variable operator*(const FieldT &coeff) const; + Fp3_variable operator+(const Fp3_variable &other) const; + Fp3_variable operator+(const Fp3T &other) const; + Fp3_variable mul_by_X() const; + void evaluate() const; + bool is_constant() const; + + static size_t size_in_bits(); + static size_t num_variables(); +}; + +/** + * Gadget that creates constraints for Fp3 by Fp3 multiplication. + */ +template +class Fp3_mul_gadget : public gadget { +public: + typedef typename Fp3T::my_Fp FieldT; + + Fp3_variable A; + Fp3_variable B; + Fp3_variable result; + + pb_variable v0; + pb_variable v4; + + Fp3_mul_gadget(protoboard &pb, + const Fp3_variable &A, + const Fp3_variable &B, + const Fp3_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that creates constraints for Fp3 multiplication by a linear combination. + */ +template +class Fp3_mul_by_lc_gadget : public gadget { +public: + typedef typename Fp3T::my_Fp FieldT; + + Fp3_variable A; + pb_linear_combination lc; + Fp3_variable result; + + Fp3_mul_by_lc_gadget(protoboard &pb, + const Fp3_variable &A, + const pb_linear_combination &lc, + const Fp3_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that creates constraints for Fp3 squaring. + */ +template +class Fp3_sqr_gadget : public gadget { +public: + typedef typename Fp3T::my_Fp FieldT; + + Fp3_variable A; + Fp3_variable result; + + std::shared_ptr > mul; + + Fp3_sqr_gadget(protoboard &pb, + const Fp3_variable &A, + const Fp3_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + + +} // libsnark + +#include "gadgetlib1/gadgets/fields/fp3_gadgets.tcc" + +#endif // FP3_GADGETS_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/fields/fp3_gadgets.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/fields/fp3_gadgets.tcc new file mode 100644 index 0000000..22b1df5 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/fields/fp3_gadgets.tcc @@ -0,0 +1,316 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for Fp3 gadgets. + + See fp3_gadgets.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP3_GADGETS_TCC_ +#define FP3_GADGETS_TCC_ + +namespace libsnark { + +template +Fp3_variable::Fp3_variable(protoboard &pb, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + pb_variable c0_var, c1_var, c2_var; + c0_var.allocate(pb, FMT(annotation_prefix, " c0")); + c1_var.allocate(pb, FMT(annotation_prefix, " c1")); + c2_var.allocate(pb, FMT(annotation_prefix, " c2")); + + c0 = pb_linear_combination(c0_var); + c1 = pb_linear_combination(c1_var); + c2 = pb_linear_combination(c2_var); + + all_vars.emplace_back(c0); + all_vars.emplace_back(c1); + all_vars.emplace_back(c2); +} + +template +Fp3_variable::Fp3_variable(protoboard &pb, + const Fp3T &el, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + c0.assign(pb, el.c0); + c1.assign(pb, el.c1); + c2.assign(pb, el.c2); + + c0.evaluate(pb); + c1.evaluate(pb); + c2.evaluate(pb); + + all_vars.emplace_back(c0); + all_vars.emplace_back(c1); + all_vars.emplace_back(c2); +} + +template +Fp3_variable::Fp3_variable(protoboard &pb, + const Fp3T &el, + const pb_linear_combination &coeff, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + c0.assign(pb, el.c0 * coeff); + c1.assign(pb, el.c1 * coeff); + c2.assign(pb, el.c2 * coeff); + + all_vars.emplace_back(c0); + all_vars.emplace_back(c1); + all_vars.emplace_back(c2); +} + +template +Fp3_variable::Fp3_variable(protoboard &pb, + const pb_linear_combination &c0, + const pb_linear_combination &c1, + const pb_linear_combination &c2, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), c0(c0), c1(c1), c2(c2) +{ + all_vars.emplace_back(c0); + all_vars.emplace_back(c1); + all_vars.emplace_back(c2); +} + +template +void Fp3_variable::generate_r1cs_equals_const_constraints(const Fp3T &el) +{ + this->pb.add_r1cs_constraint(r1cs_constraint(1, el.c0, c0), + FMT(this->annotation_prefix, " c0")); + this->pb.add_r1cs_constraint(r1cs_constraint(1, el.c1, c1), + FMT(this->annotation_prefix, " c1")); + this->pb.add_r1cs_constraint(r1cs_constraint(1, el.c2, c2), + FMT(this->annotation_prefix, " c2")); +} + +template +void Fp3_variable::generate_r1cs_witness(const Fp3T &el) +{ + this->pb.lc_val(c0) = el.c0; + this->pb.lc_val(c1) = el.c1; + this->pb.lc_val(c2) = el.c2; +} + +template +Fp3T Fp3_variable::get_element() +{ + Fp3T el; + el.c0 = this->pb.lc_val(c0); + el.c1 = this->pb.lc_val(c1); + el.c2 = this->pb.lc_val(c2); + return el; +} + +template +Fp3_variable Fp3_variable::operator*(const FieldT &coeff) const +{ + pb_linear_combination new_c0, new_c1, new_c2; + new_c0.assign(this->pb, this->c0 * coeff); + new_c1.assign(this->pb, this->c1 * coeff); + new_c2.assign(this->pb, this->c2 * coeff); + return Fp3_variable(this->pb, new_c0, new_c1, new_c2, FMT(this->annotation_prefix, " operator*")); +} + +template +Fp3_variable Fp3_variable::operator+(const Fp3_variable &other) const +{ + pb_linear_combination new_c0, new_c1, new_c2; + new_c0.assign(this->pb, this->c0 + other.c0); + new_c1.assign(this->pb, this->c1 + other.c1); + new_c2.assign(this->pb, this->c2 + other.c2); + return Fp3_variable(this->pb, new_c0, new_c1, new_c2, FMT(this->annotation_prefix, " operator+")); +} + +template +Fp3_variable Fp3_variable::operator+(const Fp3T &other) const +{ + pb_linear_combination new_c0, new_c1, new_c2; + new_c0.assign(this->pb, this->c0 + other.c0); + new_c1.assign(this->pb, this->c1 + other.c1); + new_c2.assign(this->pb, this->c2 + other.c2); + return Fp3_variable(this->pb, new_c0, new_c1, new_c2, FMT(this->annotation_prefix, " operator+")); +} + +template +Fp3_variable Fp3_variable::mul_by_X() const +{ + pb_linear_combination new_c0, new_c1, new_c2; + new_c0.assign(this->pb, this->c2 * Fp3T::non_residue); + new_c1.assign(this->pb, this->c0); + new_c2.assign(this->pb, this->c1); + return Fp3_variable(this->pb, new_c0, new_c1, new_c2, FMT(this->annotation_prefix, " mul_by_X")); +} + +template +void Fp3_variable::evaluate() const +{ + c0.evaluate(this->pb); + c1.evaluate(this->pb); + c2.evaluate(this->pb); +} + +template +bool Fp3_variable::is_constant() const +{ + return (c0.is_constant() && c1.is_constant() && c2.is_constant()); +} + +template +size_t Fp3_variable::size_in_bits() +{ + return 3 * FieldT::size_in_bits(); +} + +template +size_t Fp3_variable::num_variables() +{ + return 3; +} + +template +Fp3_mul_gadget::Fp3_mul_gadget(protoboard &pb, + const Fp3_variable &A, + const Fp3_variable &B, + const Fp3_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), B(B), result(result) +{ + v0.allocate(pb, FMT(annotation_prefix, " v0")); + v4.allocate(pb, FMT(annotation_prefix, " v4")); +} + +template +void Fp3_mul_gadget::generate_r1cs_constraints() +{ +/* + Tom-Cook-3x for Fp3: + v0 = A.c0 * B.c0 + v1 = (A.c0 + A.c1 + A.c2) * (B.c0 + B.c1 + B.c2) + v2 = (A.c0 - A.c1 + A.c2) * (B.c0 - B.c1 + B.c2) + v3 = (A.c0 + 2*A.c1 + 4*A.c2) * (B.c0 + 2*B.c1 + 4*B.c2) + v4 = A.c2 * B.c2 + result.c0 = v0 + non_residue * (v0/2 - v1/2 - v2/6 + v3/6 - 2*v4) + result.c1 = -(1/2) v0 + v1 - (1/3) v2 - (1/6) v3 + 2 v4 + non_residue*v4 + result.c2 = -v0 + (1/2) v1 + (1/2) v2 - v4 + + Enforced with 5 constraints. Doing so requires some care, as we first + compute two of the v_i explicitly, and then "inline" result.c1/c2/c3 + in computations of teh remaining three v_i. + + Concretely, we first compute v0 and v4 explicitly, via 2 constraints: + A.c0 * B.c0 = v0 + A.c2 * B.c2 = v4 + Then we use the following 3 additional constraints: + v1 = result.c1 + result.c2 + (result.c0 - v0)/non_residue + v0 + v4 - non_residue v4 + v2 = -result.c1 + result.c2 + v0 + (-result.c0 + v0)/non_residue + v4 + non_residue v4 + v3 = 2 * result.c1 + 4 result.c2 + (8*(result.c0 - v0))/non_residue + v0 + 16 * v4 - 2 * non_residue * v4 + + Reference: + "Multiplication and Squaring on Pairing-Friendly Fields" + Devegili, OhEigeartaigh, Scott, Dahab + + NOTE: the expressions above were cherry-picked from the Mathematica result + of the following command: + + (# -> Solve[{c0 == v0 + non_residue*(v0/2 - v1/2 - v2/6 + v3/6 - 2 v4), + c1 == -(1/2) v0 + v1 - (1/3) v2 - (1/6) v3 + 2 v4 + non_residue*v4, + c2 == -v0 + (1/2) v1 + (1/2) v2 - v4}, #] // FullSimplify) & /@ + Subsets[{v0, v1, v2, v3, v4}, {3}] +*/ + this->pb.add_r1cs_constraint(r1cs_constraint(A.c0, B.c0, v0), FMT(this->annotation_prefix, " v0")); + this->pb.add_r1cs_constraint(r1cs_constraint(A.c2, B.c2, v4), FMT(this->annotation_prefix, " v4")); + + const FieldT beta = Fp3T::non_residue; + + this->pb.add_r1cs_constraint(r1cs_constraint(A.c0 + A.c1 + A.c2, + B.c0 + B.c1 + B.c2, + result.c1 + result.c2 + result.c0 * beta.inverse() + v0 * (FieldT(1) - beta.inverse()) + v4 * (FieldT(1) - beta)), + FMT(this->annotation_prefix, " v1")); + this->pb.add_r1cs_constraint(r1cs_constraint(A.c0 - A.c1 + A.c2, + B.c0 - B.c1 + B.c2, + -result.c1 + result.c2 + v0 * (FieldT(1) + beta.inverse()) - result.c0 * beta.inverse() + v4 * (FieldT(1) + beta)), + FMT(this->annotation_prefix, " v2")); + this->pb.add_r1cs_constraint(r1cs_constraint(A.c0 + 2 * A.c1 + 4 * A.c2, + B.c0 + 2 * B.c1 + 4 * B.c2, + 2 * result.c1 + 4 * result.c2 + result.c0 * (FieldT(8) * beta.inverse()) + v0 * (FieldT(1) - FieldT(8) * beta.inverse()) + v4 * (FieldT(16) - FieldT(2) * beta)), + FMT(this->annotation_prefix, " v3")); +} + +template +void Fp3_mul_gadget::generate_r1cs_witness() +{ + this->pb.val(v0) = this->pb.lc_val(A.c0) * this->pb.lc_val(B.c0); + this->pb.val(v4) = this->pb.lc_val(A.c2) * this->pb.lc_val(B.c2); + + const Fp3T Aval = A.get_element(); + const Fp3T Bval = B.get_element(); + const Fp3T Rval = Aval * Bval; + result.generate_r1cs_witness(Rval); +} + +template +Fp3_mul_by_lc_gadget::Fp3_mul_by_lc_gadget(protoboard &pb, + const Fp3_variable &A, + const pb_linear_combination &lc, + const Fp3_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), lc(lc), result(result) +{ +} + +template +void Fp3_mul_by_lc_gadget::generate_r1cs_constraints() +{ + this->pb.add_r1cs_constraint(r1cs_constraint(A.c0, lc, result.c0), + FMT(this->annotation_prefix, " result.c0")); + this->pb.add_r1cs_constraint(r1cs_constraint(A.c1, lc, result.c1), + FMT(this->annotation_prefix, " result.c1")); + this->pb.add_r1cs_constraint(r1cs_constraint(A.c2, lc, result.c2), + FMT(this->annotation_prefix, " result.c2")); +} + +template +void Fp3_mul_by_lc_gadget::generate_r1cs_witness() +{ + this->pb.lc_val(result.c0) = this->pb.lc_val(A.c0) * this->pb.lc_val(lc); + this->pb.lc_val(result.c1) = this->pb.lc_val(A.c1) * this->pb.lc_val(lc); + this->pb.lc_val(result.c2) = this->pb.lc_val(A.c2) * this->pb.lc_val(lc); +} + +template +Fp3_sqr_gadget::Fp3_sqr_gadget(protoboard &pb, + const Fp3_variable &A, + const Fp3_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), result(result) +{ + mul.reset(new Fp3_mul_gadget(pb, A, A, result, FMT(annotation_prefix, " mul"))); +} + +template +void Fp3_sqr_gadget::generate_r1cs_constraints() +{ + // We can't do better than 5 constraints for squaring, so we just use multiplication. + mul->generate_r1cs_constraints(); +} + +template +void Fp3_sqr_gadget::generate_r1cs_witness() +{ + mul->generate_r1cs_witness(); +} + +} // libsnark + +#endif // FP3_GADGETS_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/fields/fp4_gadgets.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/fields/fp4_gadgets.hpp new file mode 100644 index 0000000..6ff79fa --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/fields/fp4_gadgets.hpp @@ -0,0 +1,200 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for Fp4 gadgets. + + The gadgets verify field arithmetic in Fp4 = Fp2[V]/(V^2-U) where + Fp2 = Fp[U]/(U^2-non_residue) and non_residue is in Fp. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP4_GADGETS_HPP_ +#define FP4_GADGETS_HPP_ + +namespace libsnark { + +/** + * Gadget that represents an Fp4 variable. + */ +template +class Fp4_variable : public gadget { +public: + typedef typename Fp4T::my_Fp FieldT; + typedef typename Fp4T::my_Fpe Fp2T; + + Fp2_variable c0; + Fp2_variable c1; + + Fp4_variable(protoboard &pb, const std::string &annotation_prefix); + Fp4_variable(protoboard &pb, const Fp4T &el, const std::string &annotation_prefix); + Fp4_variable(protoboard &pb, const Fp2_variable &c0, const Fp2_variable &c1, const std::string &annotation_prefix); + void generate_r1cs_equals_const_constraints(const Fp4T &el); + void generate_r1cs_witness(const Fp4T &el); + Fp4T get_element(); + + Fp4_variable Frobenius_map(const size_t power) const; + void evaluate() const; +}; + +/** + * Gadget that creates constraints for Fp4 multiplication (towering formulas). + */ +template +class Fp4_tower_mul_gadget : public gadget { +public: + typedef typename Fp4T::my_Fp FieldT; + typedef typename Fp4T::my_Fpe Fp2T; + + Fp4_variable A; + Fp4_variable B; + Fp4_variable result; + + pb_linear_combination v0_c0; + pb_linear_combination v0_c1; + + pb_linear_combination Ac0_plus_Ac1_c0; + pb_linear_combination Ac0_plus_Ac1_c1; + std::shared_ptr > Ac0_plus_Ac1; + + std::shared_ptr > v0; + std::shared_ptr > v1; + + pb_linear_combination Bc0_plus_Bc1_c0; + pb_linear_combination Bc0_plus_Bc1_c1; + std::shared_ptr > Bc0_plus_Bc1; + + pb_linear_combination result_c1_plus_v0_plus_v1_c0; + pb_linear_combination result_c1_plus_v0_plus_v1_c1; + + std::shared_ptr > result_c1_plus_v0_plus_v1; + + std::shared_ptr > compute_v0; + std::shared_ptr > compute_v1; + std::shared_ptr > compute_result_c1; + + Fp4_tower_mul_gadget(protoboard &pb, + const Fp4_variable &A, + const Fp4_variable &B, + const Fp4_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that creates constraints for Fp4 multiplication (direct formulas). + */ +template +class Fp4_direct_mul_gadget : public gadget { +public: + typedef typename Fp4T::my_Fp FieldT; + typedef typename Fp4T::my_Fpe Fp2T; + + Fp4_variable A; + Fp4_variable B; + Fp4_variable result; + + pb_variable v1; + pb_variable v2; + pb_variable v6; + + Fp4_direct_mul_gadget(protoboard &pb, + const Fp4_variable &A, + const Fp4_variable &B, + const Fp4_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Alias default multiplication gadget + */ +template +using Fp4_mul_gadget = Fp4_direct_mul_gadget; + +/** + * Gadget that creates constraints for Fp4 squaring. + */ +template +class Fp4_sqr_gadget : public gadget { +public: + typedef typename Fp4T::my_Fp FieldT; + typedef typename Fp4T::my_Fpe Fp2T; + + Fp4_variable A; + Fp4_variable result; + + std::shared_ptr > v1; + + pb_linear_combination v0_c0; + pb_linear_combination v0_c1; + std::shared_ptr > v0; + + std::shared_ptr > compute_v0; + std::shared_ptr > compute_v1; + + pb_linear_combination Ac0_plus_Ac1_c0; + pb_linear_combination Ac0_plus_Ac1_c1; + std::shared_ptr > Ac0_plus_Ac1; + + pb_linear_combination result_c1_plus_v0_plus_v1_c0; + pb_linear_combinationresult_c1_plus_v0_plus_v1_c1; + + std::shared_ptr > result_c1_plus_v0_plus_v1; + + std::shared_ptr > compute_result_c1; + + Fp4_sqr_gadget(protoboard &pb, + const Fp4_variable &A, + const Fp4_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that creates constraints for Fp4 cyclotomic squaring + */ +template +class Fp4_cyclotomic_sqr_gadget : public gadget { +public: +/* +*/ + typedef typename Fp4T::my_Fp FieldT; + typedef typename Fp4T::my_Fpe Fp2T; + + Fp4_variable A; + Fp4_variable result; + + pb_linear_combination c0_expr_c0; + pb_linear_combination c0_expr_c1; + std::shared_ptr > c0_expr; + std::shared_ptr > compute_c0_expr; + + pb_linear_combination A_c0_plus_A_c1_c0; + pb_linear_combination A_c0_plus_A_c1_c1; + std::shared_ptr > A_c0_plus_A_c1; + + pb_linear_combination c1_expr_c0; + pb_linear_combination c1_expr_c1; + std::shared_ptr > c1_expr; + std::shared_ptr > compute_c1_expr; + + Fp4_cyclotomic_sqr_gadget(protoboard &pb, + const Fp4_variable &A, + const Fp4_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/fields/fp4_gadgets.tcc" + +#endif // FP4_GADGETS_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/fields/fp4_gadgets.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/fields/fp4_gadgets.tcc new file mode 100644 index 0000000..5ba1727 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/fields/fp4_gadgets.tcc @@ -0,0 +1,434 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for Fp4 gadgets. + + See fp4_gadgets.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP4_GADGETS_TCC_ +#define FP4_GADGETS_TCC_ + +namespace libsnark { + +template +Fp4_variable::Fp4_variable(protoboard &pb, const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), c0(pb, FMT(annotation_prefix, " c0")), c1(pb, FMT(annotation_prefix, " c1")) +{ +} + +template +Fp4_variable::Fp4_variable(protoboard &pb, + const Fp4T &el, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), c0(pb, el.c0, FMT(annotation_prefix, " c0")), c1(pb, el.c1, FMT(annotation_prefix, " c1")) +{ +} + +template +Fp4_variable::Fp4_variable(protoboard &pb, const Fp2_variable &c0, const Fp2_variable &c1, const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), c0(c0), c1(c1) +{ +} + +template +void Fp4_variable::generate_r1cs_equals_const_constraints(const Fp4T &el) +{ + c0.generate_r1cs_equals_const_constraints(el.c0); + c1.generate_r1cs_equals_const_constraints(el.c1); +} + +template +void Fp4_variable::generate_r1cs_witness(const Fp4T &el) +{ + c0.generate_r1cs_witness(el.c0); + c1.generate_r1cs_witness(el.c1); +} + +template +Fp4T Fp4_variable::get_element() +{ + Fp4T el; + el.c0 = c0.get_element(); + el.c1 = c1.get_element(); + return el; +} + +template +Fp4_variable Fp4_variable::Frobenius_map(const size_t power) const +{ + pb_linear_combination new_c0c0, new_c0c1, new_c1c0, new_c1c1; + new_c0c0.assign(this->pb, c0.c0); + new_c0c1.assign(this->pb, c0.c1 * Fp2T::Frobenius_coeffs_c1[power % 2]); + new_c1c0.assign(this->pb, c1.c0 * Fp4T::Frobenius_coeffs_c1[power % 4]); + new_c1c1.assign(this->pb, c1.c1 * Fp4T::Frobenius_coeffs_c1[power % 4] * Fp2T::Frobenius_coeffs_c1[power % 2]); + + return Fp4_variable(this->pb, + Fp2_variable(this->pb, new_c0c0, new_c0c1, FMT(this->annotation_prefix, " Frobenius_map_c0")), + Fp2_variable(this->pb, new_c1c0, new_c1c1, FMT(this->annotation_prefix, " Frobenius_map_c1")), + FMT(this->annotation_prefix, " Frobenius_map")); +} + +template +void Fp4_variable::evaluate() const +{ + c0.evaluate(); + c1.evaluate(); +} + +template +Fp4_tower_mul_gadget::Fp4_tower_mul_gadget(protoboard &pb, + const Fp4_variable &A, + const Fp4_variable &B, + const Fp4_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), B(B), result(result) +{ +/* + Karatsuba multiplication for Fp4 as a quadratic extension of Fp2: + v0 = A.c0 * B.c0 + v1 = A.c1 * B.c1 + result.c0 = v0 + non_residue * v1 + result.c1 = (A.c0 + A.c1) * (B.c0 + B.c1) - v0 - v1 + where "non_residue * elem" := (non_residue * elt.c1, elt.c0) + + Enforced with 3 Fp2_mul_gadget's that ensure that: + A.c1 * B.c1 = v1 + A.c0 * B.c0 = v0 + (A.c0+A.c1)*(B.c0+B.c1) = result.c1 + v0 + v1 + + Reference: + "Multiplication and Squaring on Pairing-Friendly Fields" + Devegili, OhEigeartaigh, Scott, Dahab +*/ + v1.reset(new Fp2_variable(pb, FMT(annotation_prefix, " v1"))); + + compute_v1.reset(new Fp2_mul_gadget(pb, A.c1, B.c1, *v1, FMT(annotation_prefix, " compute_v1"))); + + v0_c0.assign(pb, result.c0.c0 - Fp4T::non_residue * v1->c1); + v0_c1.assign(pb, result.c0.c1 - v1->c0); + v0.reset(new Fp2_variable(pb, v0_c0, v0_c1, FMT(annotation_prefix, " v0"))); + + compute_v0.reset(new Fp2_mul_gadget(pb, A.c0, B.c0, *v0, FMT(annotation_prefix, " compute_v0"))); + + Ac0_plus_Ac1_c0.assign(pb, A.c0.c0 + A.c1.c0); + Ac0_plus_Ac1_c1.assign(pb, A.c0.c1 + A.c1.c1); + Ac0_plus_Ac1.reset(new Fp2_variable(pb, Ac0_plus_Ac1_c0, Ac0_plus_Ac1_c1, FMT(annotation_prefix, " Ac0_plus_Ac1"))); + + Bc0_plus_Bc1_c0.assign(pb, B.c0.c0 + B.c1.c0); + Bc0_plus_Bc1_c1.assign(pb, B.c0.c1 + B.c1.c1); + Bc0_plus_Bc1.reset(new Fp2_variable(pb, Bc0_plus_Bc1_c0, Bc0_plus_Bc1_c1, FMT(annotation_prefix, " Bc0_plus_Bc1"))); + + result_c1_plus_v0_plus_v1_c0.assign(pb, result.c1.c0 + v0->c0 + v1->c0); + result_c1_plus_v0_plus_v1_c1.assign(pb, result.c1.c1 + v0->c1 + v1->c1); + result_c1_plus_v0_plus_v1.reset(new Fp2_variable(pb, result_c1_plus_v0_plus_v1_c0, result_c1_plus_v0_plus_v1_c1, FMT(annotation_prefix, " result_c1_plus_v0_plus_v1"))); + + compute_result_c1.reset(new Fp2_mul_gadget(pb, *Ac0_plus_Ac1, *Bc0_plus_Bc1, *result_c1_plus_v0_plus_v1, FMT(annotation_prefix, " compute_result_c1"))); +} + +template +void Fp4_tower_mul_gadget::generate_r1cs_constraints() +{ + compute_v0->generate_r1cs_constraints(); + compute_v1->generate_r1cs_constraints(); + compute_result_c1->generate_r1cs_constraints(); +} + +template +void Fp4_tower_mul_gadget::generate_r1cs_witness() +{ + compute_v0->generate_r1cs_witness(); + compute_v1->generate_r1cs_witness(); + + Ac0_plus_Ac1_c0.evaluate(this->pb); + Ac0_plus_Ac1_c1.evaluate(this->pb); + + Bc0_plus_Bc1_c0.evaluate(this->pb); + Bc0_plus_Bc1_c1.evaluate(this->pb); + + compute_result_c1->generate_r1cs_witness(); + + const Fp4T Aval = A.get_element(); + const Fp4T Bval = B.get_element(); + const Fp4T Rval = Aval * Bval; + + result.generate_r1cs_witness(Rval); +} + +template +Fp4_direct_mul_gadget::Fp4_direct_mul_gadget(protoboard &pb, + const Fp4_variable &A, + const Fp4_variable &B, + const Fp4_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), B(B), result(result) +{ +/* + Tom-Cook-4x for Fp4 (beta is the quartic non-residue): + v0 = a0*b0, + v1 = (a0+a1+a2+a3)*(b0+b1+b2+b3), + v2 = (a0-a1+a2-a3)*(b0-b1+b2-b3), + v3 = (a0+2a1+4a2+8a3)*(b0+2b1+4b2+8b3), + v4 = (a0-2a1+4a2-8a3)*(b0-2b1+4b2-8b3), + v5 = (a0+3a1+9a2+27a3)*(b0+3b1+9b2+27b3), + v6 = a3*b3 + + result.c0 = v0+beta((1/4)v0-(1/6)(v1+v2)+(1/24)(v3+v4)-5v6), + result.c1 = -(1/3)v0+v1-(1/2)v2-(1/4)v3+(1/20)v4+(1/30)v5-12v6+beta(-(1/12)(v0-v1)+(1/24)(v2-v3)-(1/120)(v4-v5)-3v6), + result.c2 = -(5/4)v0+(2/3)(v1+v2)-(1/24)(v3+v4)+4v6+beta v6, + result.c3 = (1/12)(5v0-7v1)-(1/24)(v2-7v3+v4+v5)+15v6 + + Enforced with 7 constraints. Doing so requires some care, as we first + compute three of the v_i explicitly, and then "inline" result.c0/c1/c2/c3 + in computations of the remaining four v_i. + + Concretely, we first compute v1, v2 and v6 explicitly, via 3 constraints as above. + v1 = (a0+a1+a2+a3)*(b0+b1+b2+b3), + v2 = (a0-a1+a2-a3)*(b0-b1+b2-b3), + v6 = a3*b3 + + Then we use the following 4 additional constraints: + (1-beta) v0 = c0 + beta c2 - (beta v1)/2 - (beta v2)/ 2 - (-1 + beta) beta v6 + (1-beta) v3 = -15 c0 - 30 c1 - 3 (4 + beta) c2 - 6 (4 + beta) c3 + (24 - (3 beta)/2) v1 + (-8 + beta/2) v2 + 3 (-16 + beta) (-1 + beta) v6 + (1-beta) v4 = -15 c0 + 30 c1 - 3 (4 + beta) c2 + 6 (4 + beta) c3 + (-8 + beta/2) v1 + (24 - (3 beta)/2) v2 + 3 (-16 + beta) (-1 + beta) v6 + (1-beta) v5 = -80 c0 - 240 c1 - 8 (9 + beta) c2 - 24 (9 + beta) c3 - 2 (-81 + beta) v1 + (-81 + beta) v2 + 8 (-81 + beta) (-1 + beta) v6 + + The isomorphism between the representation above and towering is: + (a0, a1, a2, a3) <-> (a.c0.c0, a.c1.c0, a.c0.c1, a.c1.c1) + + Reference: + "Multiplication and Squaring on Pairing-Friendly Fields" + Devegili, OhEigeartaigh, Scott, Dahab + + NOTE: the expressions above were cherry-picked from the Mathematica result + of the following command: + + (# -> Solve[{c0 == v0+beta((1/4)v0-(1/6)(v1+v2)+(1/24)(v3+v4)-5v6), + c1 == -(1/3)v0+v1-(1/2)v2-(1/4)v3+(1/20)v4+(1/30)v5-12v6+beta(-(1/12)(v0-v1)+(1/24)(v2-v3)-(1/120)(v4-v5)-3v6), + c2 == -(5/4)v0+(2/3)(v1+v2)-(1/24)(v3+v4)+4v6+beta v6, + c3 == (1/12)(5v0-7v1)-(1/24)(v2-7v3+v4+v5)+15v6}, #] // FullSimplify) & /@ Subsets[{v0, v1, v2, v3, v4, v5}, {4}] + + and simplified by multiplying the selected result by (1-beta) +*/ + v1.allocate(pb, FMT(annotation_prefix, " v1")); + v2.allocate(pb, FMT(annotation_prefix, " v2")); + v6.allocate(pb, FMT(annotation_prefix, " v6")); +} + +template +void Fp4_direct_mul_gadget::generate_r1cs_constraints() +{ + const FieldT beta = Fp4T::non_residue; + const FieldT u = (FieldT::one() - beta).inverse(); + + const pb_linear_combination + &a0 = A.c0.c0, &a1 = A.c1.c0, &a2 = A.c0.c1, &a3 = A.c1.c1, + &b0 = B.c0.c0, &b1 = B.c1.c0, &b2 = B.c0.c1, &b3 = B.c1.c1, + &c0 = result.c0.c0, &c1 = result.c1.c0, &c2 = result.c0.c1, &c3 = result.c1.c1; + + this->pb.add_r1cs_constraint(r1cs_constraint( + a0 + a1 + a2 + a3, + b0 + b1 + b2 + b3, + v1), + FMT(this->annotation_prefix, " v1")); + this->pb.add_r1cs_constraint(r1cs_constraint( + a0 - a1 + a2 - a3, + b0 - b1 + b2 - b3, + v2), + FMT(this->annotation_prefix, " v2")); + this->pb.add_r1cs_constraint(r1cs_constraint( + a3, + b3, + v6), + FMT(this->annotation_prefix, " v6")); + + this->pb.add_r1cs_constraint(r1cs_constraint( + a0, + b0, + u * c0 + beta * u * c2 - beta * u * FieldT(2).inverse() * v1 - beta * u * FieldT(2).inverse() * v2 + beta * v6), + FMT(this->annotation_prefix, " v0")); + this->pb.add_r1cs_constraint(r1cs_constraint( + a0 + FieldT(2)*a1 + FieldT(4)*a2 + FieldT(8)*a3, + b0 + FieldT(2)*b1 + FieldT(4)*b2 + FieldT(8)*b3, + - FieldT(15) * u * c0 - FieldT(30) * u * c1 - FieldT(3) * (FieldT(4) + beta) * u * c2 - FieldT(6) * (FieldT(4) + beta) * u * c3 + (FieldT(24) - FieldT(3) * beta * FieldT(2).inverse()) * u * v1 + (-FieldT(8) + beta * FieldT(2).inverse()) * u * v2 - FieldT(3) * (-FieldT(16) + beta) * v6), + FMT(this->annotation_prefix, " v3")); + this->pb.add_r1cs_constraint(r1cs_constraint( + a0 - FieldT(2)*a1 + FieldT(4)*a2 - FieldT(8)*a3, + b0 - FieldT(2)*b1 + FieldT(4)*b2 - FieldT(8)*b3, + - FieldT(15) * u * c0 + FieldT(30) * u * c1 - FieldT(3) * (FieldT(4) + beta) * u * c2 + FieldT(6) * (FieldT(4) + beta) * u * c3 + (FieldT(24) - FieldT(3) * beta * FieldT(2).inverse()) * u * v2 + (-FieldT(8) + beta * FieldT(2).inverse()) * u * v1 + - FieldT(3) * (-FieldT(16) + beta) * v6), + FMT(this->annotation_prefix, " v4")); + this->pb.add_r1cs_constraint(r1cs_constraint( + a0 + FieldT(3)*a1 + FieldT(9)*a2 + FieldT(27)*a3, + b0 + FieldT(3)*b1 + FieldT(9)*b2 + FieldT(27)*b3, + - FieldT(80) * u * c0 - FieldT(240) * u * c1 - FieldT(8) * (FieldT(9) + beta) * u * c2 - FieldT(24) * (FieldT(9) + beta) * u * c3 - FieldT(2) * (-FieldT(81) + beta) * u * v1 + (-FieldT(81) + beta) * u * v2 - FieldT(8) * (-FieldT(81) + beta) * v6), + FMT(this->annotation_prefix, " v5")); +} + +template +void Fp4_direct_mul_gadget::generate_r1cs_witness() +{ + const pb_linear_combination + &a0 = A.c0.c0, &a1 = A.c1.c0, &a2 = A.c0.c1, &a3 = A.c1.c1, + &b0 = B.c0.c0, &b1 = B.c1.c0, &b2 = B.c0.c1, &b3 = B.c1.c1; + + this->pb.val(v1) = ((this->pb.lc_val(a0) + this->pb.lc_val(a1) + this->pb.lc_val(a2) + this->pb.lc_val(a3)) * + (this->pb.lc_val(b0) + this->pb.lc_val(b1) + this->pb.lc_val(b2) + this->pb.lc_val(b3))); + this->pb.val(v2) = ((this->pb.lc_val(a0) - this->pb.lc_val(a1) + this->pb.lc_val(a2) - this->pb.lc_val(a3)) * + (this->pb.lc_val(b0) - this->pb.lc_val(b1) + this->pb.lc_val(b2) - this->pb.lc_val(b3))); + this->pb.val(v6) = this->pb.lc_val(a3) * this->pb.lc_val(b3); + + const Fp4T Aval = A.get_element(); + const Fp4T Bval = B.get_element(); + const Fp4T Rval = Aval * Bval; + + result.generate_r1cs_witness(Rval); +} + +template +Fp4_sqr_gadget::Fp4_sqr_gadget(protoboard &pb, + const Fp4_variable &A, + const Fp4_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), result(result) +{ +/* + Karatsuba squaring for Fp4 as a quadratic extension of Fp2: + v0 = A.c0^2 + v1 = A.c1^2 + result.c0 = v0 + non_residue * v1 + result.c1 = (A.c0 + A.c1)^2 - v0 - v1 + where "non_residue * elem" := (non_residue * elt.c1, elt.c0) + + Enforced with 3 Fp2_sqr_gadget's that ensure that: + A.c1^2 = v1 + A.c0^2 = v0 + (A.c0+A.c1)^2 = result.c1 + v0 + v1 + + Reference: + "Multiplication and Squaring on Pairing-Friendly Fields" + Devegili, OhEigeartaigh, Scott, Dahab +*/ + v1.reset(new Fp2_variable(pb, FMT(annotation_prefix, " v1"))); + compute_v1.reset(new Fp2_sqr_gadget(pb, A.c1, *v1, FMT(annotation_prefix, " compute_v1"))); + + v0_c0.assign(pb, result.c0.c0 - Fp4T::non_residue * v1->c1); + v0_c1.assign(pb, result.c0.c1 - v1->c0); + v0.reset(new Fp2_variable(pb, v0_c0, v0_c1, FMT(annotation_prefix, " v0"))); + + compute_v0.reset(new Fp2_sqr_gadget(pb, A.c0, *v0, FMT(annotation_prefix, " compute_v0"))); + + Ac0_plus_Ac1_c0.assign(pb, A.c0.c0 + A.c1.c0); + Ac0_plus_Ac1_c1.assign(pb, A.c0.c1 + A.c1.c1); + Ac0_plus_Ac1.reset(new Fp2_variable(pb, Ac0_plus_Ac1_c0, Ac0_plus_Ac1_c1, FMT(annotation_prefix, " Ac0_plus_Ac1"))); + + result_c1_plus_v0_plus_v1_c0.assign(pb, result.c1.c0 + v0->c0 + v1->c0); + result_c1_plus_v0_plus_v1_c1.assign(pb, result.c1.c1 + v0->c1 + v1->c1); + result_c1_plus_v0_plus_v1.reset(new Fp2_variable(pb, result_c1_plus_v0_plus_v1_c0, result_c1_plus_v0_plus_v1_c1, FMT(annotation_prefix, " result_c1_plus_v0_plus_v1"))); + + compute_result_c1.reset(new Fp2_sqr_gadget(pb, *Ac0_plus_Ac1, *result_c1_plus_v0_plus_v1, FMT(annotation_prefix, " compute_result_c1"))); +} + +template +void Fp4_sqr_gadget::generate_r1cs_constraints() +{ + compute_v1->generate_r1cs_constraints(); + compute_v0->generate_r1cs_constraints(); + compute_result_c1->generate_r1cs_constraints(); +} + +template +void Fp4_sqr_gadget::generate_r1cs_witness() +{ + compute_v1->generate_r1cs_witness(); + + v0_c0.evaluate(this->pb); + v0_c1.evaluate(this->pb); + compute_v0->generate_r1cs_witness(); + + Ac0_plus_Ac1_c0.evaluate(this->pb); + Ac0_plus_Ac1_c1.evaluate(this->pb); + compute_result_c1->generate_r1cs_witness(); + + const Fp4T Aval = A.get_element(); + const Fp4T Rval = Aval.squared(); + result.generate_r1cs_witness(Rval); +} + +template +Fp4_cyclotomic_sqr_gadget::Fp4_cyclotomic_sqr_gadget(protoboard &pb, + const Fp4_variable &A, + const Fp4_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), result(result) +{ +/* + A = elt.c1 ^ 2 + B = elt.c1 + elt.c0; + C = B ^ 2 - A + D = Fp2(A.c1 * non_residue, A.c0) + E = C - D + F = D + D + Fp2::one() + G = E - Fp2::one() + + return Fp4(F, G); + + Enforced with 2 Fp2_sqr_gadget's that ensure that: + + elt.c1 ^ 2 = Fp2(result.c0.c1 / 2, (result.c0.c0 - 1) / (2 * non_residue)) = A + (elt.c1 + elt.c0) ^ 2 = A + result.c1 + Fp2(A.c1 * non_residue + 1, A.c0) + + (elt.c1 + elt.c0) ^ 2 = Fp2(result.c0.c1 / 2 + result.c1.c0 + (result.c0.c0 - 1) / 2 + 1, + (result.c0.c0 - 1) / (2 * non_residue) + result.c1.c1 + result.c0.c1 / 2) + + Corresponding test code: + + assert(B.squared() == A + G + my_Fp2(A.c1 * non_residue + my_Fp::one(), A.c0)); + assert(this->c1.squared().c0 == F.c1 * my_Fp(2).inverse()); + assert(this->c1.squared().c1 == (F.c0 - my_Fp(1)) * (my_Fp(2) * non_residue).inverse()); +*/ + c0_expr_c0.assign(pb, result.c0.c1 * FieldT(2).inverse()); + c0_expr_c1.assign(pb, (result.c0.c0 - FieldT(1)) * (FieldT(2) * Fp4T::non_residue).inverse()); + c0_expr.reset(new Fp2_variable(pb, c0_expr_c0, c0_expr_c1, FMT(annotation_prefix, " c0_expr"))); + compute_c0_expr.reset(new Fp2_sqr_gadget(pb, A.c1, *c0_expr, FMT(annotation_prefix, " compute_c0_expr"))); + + A_c0_plus_A_c1_c0.assign(pb, A.c0.c0 + A.c1.c0); + A_c0_plus_A_c1_c1.assign(pb, A.c0.c1 + A.c1.c1); + A_c0_plus_A_c1.reset(new Fp2_variable(pb, A_c0_plus_A_c1_c0, A_c0_plus_A_c1_c1, FMT(annotation_prefix, " A_c0_plus_A_c1"))); + + c1_expr_c0.assign(pb, (result.c0.c1 + result.c0.c0 - FieldT(1)) * FieldT(2).inverse() + result.c1.c0 + FieldT(1)); + c1_expr_c1.assign(pb, (result.c0.c0 - FieldT(1)) * (FieldT(2) * Fp4T::non_residue).inverse() + result.c1.c1 + result.c0.c1 * FieldT(2).inverse()); + c1_expr.reset(new Fp2_variable(pb, c1_expr_c0, c1_expr_c1, FMT(annotation_prefix, " c1_expr"))); + + compute_c1_expr.reset(new Fp2_sqr_gadget(pb, *A_c0_plus_A_c1, *c1_expr, FMT(annotation_prefix, " compute_c1_expr"))); +} + +template +void Fp4_cyclotomic_sqr_gadget::generate_r1cs_constraints() +{ + compute_c0_expr->generate_r1cs_constraints(); + compute_c1_expr->generate_r1cs_constraints(); +} + +template +void Fp4_cyclotomic_sqr_gadget::generate_r1cs_witness() +{ + compute_c0_expr->generate_r1cs_witness(); + + A_c0_plus_A_c1_c0.evaluate(this->pb); + A_c0_plus_A_c1_c1.evaluate(this->pb); + compute_c1_expr->generate_r1cs_witness(); + + const Fp4T Aval = A.get_element(); + const Fp4T Rval = Aval.squared(); + result.generate_r1cs_witness(Rval); +} + +} // libsnark + +#endif // FP4_GADGETS_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/fields/fp6_gadgets.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/fields/fp6_gadgets.hpp new file mode 100644 index 0000000..efb978b --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/fields/fp6_gadgets.hpp @@ -0,0 +1,205 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for Fp6 gadgets. + + The gadgets verify field arithmetic in Fp6 = Fp3[Y]/(Y^2-X) where + Fp3 = Fp[X]/(X^3-non_residue) and non_residue is in Fp. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP6_GADGETS_HPP_ +#define FP6_GADGETS_HPP_ + +#include "gadgetlib1/gadgets/fields/fp2_gadgets.hpp" + +namespace libsnark { + +/** + * Gadget that represents an Fp6 variable. + */ +template +class Fp6_variable : public gadget { +public: + typedef typename Fp6T::my_Fp FieldT; + typedef typename Fp6T::my_Fpe Fp3T; + + Fp3_variable c0; + Fp3_variable c1; + + Fp6_variable(protoboard &pb, const std::string &annotation_prefix); + Fp6_variable(protoboard &pb, const Fp6T &el, const std::string &annotation_prefix); + Fp6_variable(protoboard &pb, const Fp3_variable &c0, const Fp3_variable &c1, const std::string &annotation_prefix); + void generate_r1cs_equals_const_constraints(const Fp6T &el); + void generate_r1cs_witness(const Fp6T &el); + Fp6T get_element(); + Fp6_variable Frobenius_map(const size_t power) const; + void evaluate() const; +}; + +/** + * Gadget that creates constraints for Fp6 multiplication. + */ +template +class Fp6_mul_gadget : public gadget { +public: + typedef typename Fp6T::my_Fp FieldT; + typedef typename Fp6T::my_Fpe Fp3T; + + Fp6_variable A; + Fp6_variable B; + Fp6_variable result; + + pb_linear_combination v0_c0; + pb_linear_combination v0_c1; + pb_linear_combination v0_c2; + + pb_linear_combination Ac0_plus_Ac1_c0; + pb_linear_combination Ac0_plus_Ac1_c1; + pb_linear_combination Ac0_plus_Ac1_c2; + std::shared_ptr > Ac0_plus_Ac1; + + std::shared_ptr > v0; + std::shared_ptr > v1; + + pb_linear_combination Bc0_plus_Bc1_c0; + pb_linear_combination Bc0_plus_Bc1_c1; + pb_linear_combination Bc0_plus_Bc1_c2; + std::shared_ptr > Bc0_plus_Bc1; + + pb_linear_combination result_c1_plus_v0_plus_v1_c0; + pb_linear_combination result_c1_plus_v0_plus_v1_c1; + pb_linear_combination result_c1_plus_v0_plus_v1_c2; + std::shared_ptr > result_c1_plus_v0_plus_v1; + + std::shared_ptr > compute_v0; + std::shared_ptr > compute_v1; + std::shared_ptr > compute_result_c1; + + Fp6_mul_gadget(protoboard &pb, + const Fp6_variable &A, + const Fp6_variable &B, + const Fp6_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that creates constraints for Fp6 multiplication by a Fp6 element B for which B.c0.c0 = B.c0.c1 = 0. + */ +template +class Fp6_mul_by_2345_gadget : public gadget { +public: + typedef typename Fp6T::my_Fp FieldT; + typedef typename Fp6T::my_Fpe Fp3T; + + Fp6_variable A; + Fp6_variable B; + Fp6_variable result; + + pb_linear_combination v0_c0; + pb_linear_combination v0_c1; + pb_linear_combination v0_c2; + + pb_linear_combination Ac0_plus_Ac1_c0; + pb_linear_combination Ac0_plus_Ac1_c1; + pb_linear_combination Ac0_plus_Ac1_c2; + std::shared_ptr > Ac0_plus_Ac1; + + std::shared_ptr > v0; + std::shared_ptr > v1; + + pb_linear_combination Bc0_plus_Bc1_c0; + pb_linear_combination Bc0_plus_Bc1_c1; + pb_linear_combination Bc0_plus_Bc1_c2; + std::shared_ptr > Bc0_plus_Bc1; + + pb_linear_combination result_c1_plus_v0_plus_v1_c0; + pb_linear_combination result_c1_plus_v0_plus_v1_c1; + pb_linear_combination result_c1_plus_v0_plus_v1_c2; + std::shared_ptr > result_c1_plus_v0_plus_v1; + + std::shared_ptr > compute_v1; + std::shared_ptr > compute_result_c1; + + Fp6_mul_by_2345_gadget(protoboard &pb, + const Fp6_variable &A, + const Fp6_variable &B, + const Fp6_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that creates constraints for Fp6 squaring. + */ +template +class Fp6_sqr_gadget : public gadget { +public: + typedef typename Fp6T::my_Fp FieldT; + + Fp6_variable A; + Fp6_variable result; + + std::shared_ptr > mul; + + Fp6_sqr_gadget(protoboard &pb, + const Fp6_variable &A, + const Fp6_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that creates constraints for Fp6 cyclotomic squaring + */ +template +class Fp6_cyclotomic_sqr_gadget : public gadget { +public: + typedef typename Fp6T::my_Fp FieldT; + typedef typename Fp6T::my_Fp2 Fp2T; + + Fp6_variable A; + Fp6_variable result; + + std::shared_ptr > a; + std::shared_ptr > b; + std::shared_ptr > c; + + pb_linear_combination asq_c0; + pb_linear_combination asq_c1; + + pb_linear_combination bsq_c0; + pb_linear_combination bsq_c1; + + pb_linear_combination csq_c0; + pb_linear_combination csq_c1; + + std::shared_ptr > asq; + std::shared_ptr > bsq; + std::shared_ptr > csq; + + std::shared_ptr > compute_asq; + std::shared_ptr > compute_bsq; + std::shared_ptr > compute_csq; + + Fp6_cyclotomic_sqr_gadget(protoboard &pb, + const Fp6_variable &A, + const Fp6_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/fields/fp6_gadgets.tcc" + +#endif // FP6_GADGETS_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/fields/fp6_gadgets.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/fields/fp6_gadgets.tcc new file mode 100644 index 0000000..62cb43b --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/fields/fp6_gadgets.tcc @@ -0,0 +1,396 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for Fp6 gadgets. + + See fp6_gadgets.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP6_GADGETS_TCC_ +#define FP6_GADGETS_TCC_ + +namespace libsnark { + +template +Fp6_variable::Fp6_variable(protoboard &pb, const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), c0(pb, FMT(annotation_prefix, " c0")), c1(pb, FMT(annotation_prefix, " c1")) +{ +} + +template +Fp6_variable::Fp6_variable(protoboard &pb, + const Fp6T &el, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), c0(pb, el.c0, FMT(annotation_prefix, " c0")), c1(pb, el.c1, FMT(annotation_prefix, " c1")) +{ +} + +template +Fp6_variable::Fp6_variable(protoboard &pb, const Fp3_variable &c0, const Fp3_variable &c1, const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), c0(c0), c1(c1) +{ +} + +template +void Fp6_variable::generate_r1cs_equals_const_constraints(const Fp6T &el) +{ + c0.generate_r1cs_equals_const_constraints(el.c0); + c1.generate_r1cs_equals_const_constraints(el.c1); +} + +template +void Fp6_variable::generate_r1cs_witness(const Fp6T &el) +{ + c0.generate_r1cs_witness(el.c0); + c1.generate_r1cs_witness(el.c1); +} + +template +Fp6T Fp6_variable::get_element() +{ + Fp6T el; + el.c0 = c0.get_element(); + el.c1 = c1.get_element(); + return el; +} + +template +Fp6_variable Fp6_variable::Frobenius_map(const size_t power) const +{ + pb_linear_combination new_c0c0, new_c0c1, new_c0c2, new_c1c0, new_c1c1, new_c1c2; + new_c0c0.assign(this->pb, c0.c0); + new_c0c1.assign(this->pb, c0.c1 * Fp3T::Frobenius_coeffs_c1[power % 3]); + new_c0c2.assign(this->pb, c0.c2 * Fp3T::Frobenius_coeffs_c2[power % 3]); + new_c1c0.assign(this->pb, c1.c0 * Fp6T::Frobenius_coeffs_c1[power % 6]); + new_c1c1.assign(this->pb, c1.c1 * (Fp6T::Frobenius_coeffs_c1[power % 6] * Fp3T::Frobenius_coeffs_c1[power % 3])); + new_c1c2.assign(this->pb, c1.c2 * (Fp6T::Frobenius_coeffs_c1[power % 6] * Fp3T::Frobenius_coeffs_c2[power % 3])); + + return Fp6_variable(this->pb, + Fp3_variable(this->pb, new_c0c0, new_c0c1, new_c0c2, FMT(this->annotation_prefix, " Frobenius_map_c0")), + Fp3_variable(this->pb, new_c1c0, new_c1c1, new_c1c2, FMT(this->annotation_prefix, " Frobenius_map_c1")), + FMT(this->annotation_prefix, " Frobenius_map")); +} + +template +void Fp6_variable::evaluate() const +{ + c0.evaluate(); + c1.evaluate(); +} + +template +Fp6_mul_gadget::Fp6_mul_gadget(protoboard &pb, + const Fp6_variable &A, + const Fp6_variable &B, + const Fp6_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), B(B), result(result) +{ +/* + Karatsuba multiplication for Fp6 as a quadratic extension of Fp3: + v0 = A.c0 * B.c0 + v1 = A.c1 * B.c1 + result.c0 = v0 + non_residue * v1 + result.c1 = (A.c0 + A.c1) * (B.c0 + B.c1) - v0 - v1 + where "non_residue * elem" := (non_residue * elem.c2, elem.c0, elem.c1) + + Enforced with 3 Fp3_mul_gadget's that ensure that: + A.c1 * B.c1 = v1 + A.c0 * B.c0 = v0 + (A.c0+A.c1)*(B.c0+B.c1) = result.c1 + v0 + v1 + + Reference: + "Multiplication and Squaring on Pairing-Friendly Fields" + Devegili, OhEigeartaigh, Scott, Dahab +*/ + v1.reset(new Fp3_variable(pb, FMT(annotation_prefix, " v1"))); + + compute_v1.reset(new Fp3_mul_gadget(pb, A.c1, B.c1, *v1, FMT(annotation_prefix, " compute_v1"))); + + v0_c0.assign(pb, result.c0.c0 - Fp6T::non_residue * v1->c2); + v0_c1.assign(pb, result.c0.c1 - v1->c0); + v0_c2.assign(pb, result.c0.c2 - v1->c1); + v0.reset(new Fp3_variable(pb, v0_c0, v0_c1, v0_c2, FMT(annotation_prefix, " v0"))); + + compute_v0.reset(new Fp3_mul_gadget(pb, A.c0, B.c0, *v0, FMT(annotation_prefix, " compute_v0"))); + + Ac0_plus_Ac1_c0.assign(pb, A.c0.c0 + A.c1.c0); + Ac0_plus_Ac1_c1.assign(pb, A.c0.c1 + A.c1.c1); + Ac0_plus_Ac1_c2.assign(pb, A.c0.c2 + A.c1.c2); + Ac0_plus_Ac1.reset(new Fp3_variable(pb, Ac0_plus_Ac1_c0, Ac0_plus_Ac1_c1, Ac0_plus_Ac1_c2, FMT(annotation_prefix, " Ac0_plus_Ac1"))); + + Bc0_plus_Bc1_c0.assign(pb, B.c0.c0 + B.c1.c0); + Bc0_plus_Bc1_c1.assign(pb, B.c0.c1 + B.c1.c1); + Bc0_plus_Bc1_c2.assign(pb, B.c0.c2 + B.c1.c2); + Bc0_plus_Bc1.reset(new Fp3_variable(pb, Bc0_plus_Bc1_c0, Bc0_plus_Bc1_c1, Bc0_plus_Bc1_c2, FMT(annotation_prefix, " Bc0_plus_Bc1"))); + + result_c1_plus_v0_plus_v1_c0.assign(pb, result.c1.c0 + v0->c0 + v1->c0); + result_c1_plus_v0_plus_v1_c1.assign(pb, result.c1.c1 + v0->c1 + v1->c1); + result_c1_plus_v0_plus_v1_c2.assign(pb, result.c1.c2 + v0->c2 + v1->c2); + result_c1_plus_v0_plus_v1.reset(new Fp3_variable(pb, + result_c1_plus_v0_plus_v1_c0, + result_c1_plus_v0_plus_v1_c1, + result_c1_plus_v0_plus_v1_c2, + FMT(annotation_prefix, " result_c1_plus_v0_plus_v1"))); + + compute_result_c1.reset(new Fp3_mul_gadget(pb, *Ac0_plus_Ac1, *Bc0_plus_Bc1, *result_c1_plus_v0_plus_v1, FMT(annotation_prefix, " compute_result_c1"))); +} + +template +void Fp6_mul_gadget::generate_r1cs_constraints() +{ + compute_v0->generate_r1cs_constraints(); + compute_v1->generate_r1cs_constraints(); + compute_result_c1->generate_r1cs_constraints(); +} + +template +void Fp6_mul_gadget::generate_r1cs_witness() +{ + compute_v0->generate_r1cs_witness(); + compute_v1->generate_r1cs_witness(); + + Ac0_plus_Ac1_c0.evaluate(this->pb); + Ac0_plus_Ac1_c1.evaluate(this->pb); + Ac0_plus_Ac1_c2.evaluate(this->pb); + + Bc0_plus_Bc1_c0.evaluate(this->pb); + Bc0_plus_Bc1_c1.evaluate(this->pb); + Bc0_plus_Bc1_c2.evaluate(this->pb); + + compute_result_c1->generate_r1cs_witness(); + + const Fp6T Aval = A.get_element(); + const Fp6T Bval = B.get_element(); + const Fp6T Rval = Aval * Bval; + + result.generate_r1cs_witness(Rval); + + result_c1_plus_v0_plus_v1_c0.evaluate(this->pb); + result_c1_plus_v0_plus_v1_c1.evaluate(this->pb); + result_c1_plus_v0_plus_v1_c2.evaluate(this->pb); + + compute_result_c1->generate_r1cs_witness(); +} + +template +Fp6_mul_by_2345_gadget::Fp6_mul_by_2345_gadget(protoboard &pb, + const Fp6_variable &A, + const Fp6_variable &B, + const Fp6_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), B(B), result(result) +{ +/* + Karatsuba multiplication for Fp6 as a quadratic extension of Fp3: + v0 = A.c0 * B.c0 + v1 = A.c1 * B.c1 + result.c0 = v0 + non_residue * v1 + result.c1 = (A.c0 + A.c1) * (B.c0 + B.c1) - v0 - v1 + where "non_residue * elem" := (non_residue * elem.c2, elem.c0, elem.c1) + + We know that B.c0.c0 = B.c0.c1 = 0 + + Enforced with 2 Fp3_mul_gadget's that ensure that: + A.c1 * B.c1 = v1 + (A.c0+A.c1)*(B.c0+B.c1) = result.c1 + v0 + v1 + + And one multiplication (three direct constraints) that enforces A.c0 * B.c0 + = v0, where B.c0.c0 = B.c0.c1 = 0. + + Note that (u + v * X + t * X^2) * (0 + 0 * X + z * X^2) = + (v * z * non_residue + t * z * non_residue * X + u * z * X^2) + + Reference: + "Multiplication and Squaring on Pairing-Friendly Fields" + Devegili, OhEigeartaigh, Scott, Dahab +*/ + v1.reset(new Fp3_variable(pb, FMT(annotation_prefix, " v1"))); + compute_v1.reset(new Fp3_mul_gadget(pb, A.c1, B.c1, *v1, FMT(annotation_prefix, " compute_v1"))); + + /* we inline result.c0 in v0 as follows: v0 = (result.c0.c0 - Fp6T::non_residue * v1->c2, result.c0.c1 - v1->c0, result.c0.c2 - v1->c1) */ + v0.reset(new Fp3_variable(pb, FMT(annotation_prefix, " v0"))); + + Ac0_plus_Ac1_c0.assign(pb, A.c0.c0 + A.c1.c0); + Ac0_plus_Ac1_c1.assign(pb, A.c0.c1 + A.c1.c1); + Ac0_plus_Ac1_c2.assign(pb, A.c0.c2 + A.c1.c2); + Ac0_plus_Ac1.reset(new Fp3_variable(pb, Ac0_plus_Ac1_c0, Ac0_plus_Ac1_c1, Ac0_plus_Ac1_c2, FMT(annotation_prefix, " Ac0_plus_Ac1"))); + + Bc0_plus_Bc1_c0.assign(pb, B.c0.c0 + B.c1.c0); + Bc0_plus_Bc1_c1.assign(pb, B.c0.c1 + B.c1.c1); + Bc0_plus_Bc1_c2.assign(pb, B.c0.c2 + B.c1.c2); + Bc0_plus_Bc1.reset(new Fp3_variable(pb, Bc0_plus_Bc1_c0, Bc0_plus_Bc1_c1, Bc0_plus_Bc1_c2, FMT(annotation_prefix, " Bc0_plus_Bc1"))); + + result_c1_plus_v0_plus_v1_c0.assign(pb, result.c1.c0 + v0->c0 + v1->c0); + result_c1_plus_v0_plus_v1_c1.assign(pb, result.c1.c1 + v0->c1 + v1->c1); + result_c1_plus_v0_plus_v1_c2.assign(pb, result.c1.c2 + v0->c2 + v1->c2); + result_c1_plus_v0_plus_v1.reset(new Fp3_variable(pb, + result_c1_plus_v0_plus_v1_c0, + result_c1_plus_v0_plus_v1_c1, + result_c1_plus_v0_plus_v1_c2, + FMT(annotation_prefix, " result_c1_plus_v0_plus_v1"))); + + compute_result_c1.reset(new Fp3_mul_gadget(pb, *Ac0_plus_Ac1, *Bc0_plus_Bc1, *result_c1_plus_v0_plus_v1, FMT(annotation_prefix, " compute_result_c1"))); +} + +template +void Fp6_mul_by_2345_gadget::generate_r1cs_constraints() +{ + compute_v1->generate_r1cs_constraints(); + this->pb.add_r1cs_constraint(r1cs_constraint(A.c0.c1, + Fp3T::non_residue * B.c0.c2, + result.c0.c0 - Fp6T::non_residue * v1->c2), + FMT(this->annotation_prefix, " v0.c0")); + this->pb.add_r1cs_constraint(r1cs_constraint(A.c0.c2, + Fp3T::non_residue * B.c0.c2, + result.c0.c1 - v1->c0), + FMT(this->annotation_prefix, " v0.c1")); + this->pb.add_r1cs_constraint(r1cs_constraint(A.c0.c0, + B.c0.c2, + result.c0.c2 - v1->c1), + FMT(this->annotation_prefix, " v0.c2")); + compute_result_c1->generate_r1cs_constraints(); +} + +template +void Fp6_mul_by_2345_gadget::generate_r1cs_witness() +{ + compute_v1->generate_r1cs_witness(); + + const Fp3T A_c0_val = A.c0.get_element(); + const Fp3T B_c0_val = B.c0.get_element(); + assert(B_c0_val.c0.is_zero()); + assert(B_c0_val.c1.is_zero()); + + const Fp3T v0_val = A_c0_val * B_c0_val; + v0->generate_r1cs_witness(v0_val); + + Ac0_plus_Ac1_c0.evaluate(this->pb); + Ac0_plus_Ac1_c1.evaluate(this->pb); + Ac0_plus_Ac1_c2.evaluate(this->pb); + + Bc0_plus_Bc1_c0.evaluate(this->pb); + Bc0_plus_Bc1_c1.evaluate(this->pb); + Bc0_plus_Bc1_c2.evaluate(this->pb); + + compute_result_c1->generate_r1cs_witness(); + + const Fp6T Aval = A.get_element(); + const Fp6T Bval = B.get_element(); + const Fp6T Rval = Aval * Bval; + + result.generate_r1cs_witness(Rval); + + result_c1_plus_v0_plus_v1_c0.evaluate(this->pb); + result_c1_plus_v0_plus_v1_c1.evaluate(this->pb); + result_c1_plus_v0_plus_v1_c2.evaluate(this->pb); + + compute_result_c1->generate_r1cs_witness(); +} + +template +Fp6_sqr_gadget::Fp6_sqr_gadget(protoboard &pb, + const Fp6_variable &A, + const Fp6_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), result(result) +{ + // We can't do better than 3 Fp3_mul_gadget's for squaring, so we just use multiplication. + mul.reset(new Fp6_mul_gadget(pb, A, A, result, FMT(annotation_prefix, " mul"))); +} + +template +void Fp6_sqr_gadget::generate_r1cs_constraints() +{ + mul->generate_r1cs_constraints(); +} + +template +void Fp6_sqr_gadget::generate_r1cs_witness() +{ + mul->generate_r1cs_witness(); +} + +template +Fp6_cyclotomic_sqr_gadget::Fp6_cyclotomic_sqr_gadget(protoboard &pb, + const Fp6_variable &A, + const Fp6_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), result(result) +{ +/* + my_Fp2 a = my_Fp2(c0.c0, c1.c1); + my_Fp2 b = my_Fp2(c1.c0, c0.c2); + my_Fp2 c = my_Fp2(c0.c1, c1.c2); + + my_Fp2 asq = a.squared(); + my_Fp2 bsq = b.squared(); + my_Fp2 csq = c.squared(); + + result.c0.c0 = 3 * asq_a - 2 * a_a; + result.c1.c1 = 3 * asq_b + 2 * a_b; + + result.c0.c1 = 3 * bsq_a - 2 * c_a; + result.c1.c2 = 3 * bsq_b + 2 * c_b; + + result.c0.c2 = 3 * csq_a - 2 * b_b; + result.c1.c0 = 3 * my_Fp3::non_residue * csq_b + 2 * b_a; + + return Fp6_2over3_model(my_Fp3(A_a, C_a, B_b), + my_Fp3(B_a, A_b, C_b)) +*/ + a.reset(new Fp2_variable(pb, A.c0.c0, A.c1.c1, FMT(annotation_prefix, " a"))); + b.reset(new Fp2_variable(pb, A.c1.c0, A.c0.c2, FMT(annotation_prefix, " b"))); + c.reset(new Fp2_variable(pb, A.c0.c1, A.c1.c2, FMT(annotation_prefix, " c"))); + + asq_c0.assign(pb, (result.c0.c0 + 2 * a->c0) * FieldT(3).inverse()); + asq_c1.assign(pb, (result.c1.c1 - 2 * a->c1) * FieldT(3).inverse()); + + bsq_c0.assign(pb, (result.c0.c1 + 2 * c->c0) * FieldT(3).inverse()); + bsq_c1.assign(pb, (result.c1.c2 - 2 * c->c1) * FieldT(3).inverse()); + + csq_c0.assign(pb, (result.c0.c2 + 2 * b->c1) * FieldT(3).inverse()); + csq_c1.assign(pb, (result.c1.c0 - 2 * b->c0) * (FieldT(3) * Fp2T::non_residue).inverse()); + + asq.reset(new Fp2_variable(pb, asq_c0, asq_c1, FMT(annotation_prefix, " asq"))); + bsq.reset(new Fp2_variable(pb, bsq_c0, bsq_c1, FMT(annotation_prefix, " bsq"))); + csq.reset(new Fp2_variable(pb, csq_c0, csq_c1, FMT(annotation_prefix, " csq"))); + + compute_asq.reset(new Fp2_sqr_gadget(pb, *a, *asq, FMT(annotation_prefix, " compute_asq"))); + compute_bsq.reset(new Fp2_sqr_gadget(pb, *b, *bsq, FMT(annotation_prefix, " compute_bsq"))); + compute_csq.reset(new Fp2_sqr_gadget(pb, *c, *csq, FMT(annotation_prefix, " compute_csq"))); +} + +template +void Fp6_cyclotomic_sqr_gadget::generate_r1cs_constraints() +{ + compute_asq->generate_r1cs_constraints(); + compute_bsq->generate_r1cs_constraints(); + compute_csq->generate_r1cs_constraints(); +} + +template +void Fp6_cyclotomic_sqr_gadget::generate_r1cs_witness() +{ + const Fp6T Aval = A.get_element(); + const Fp6T Rval = Aval.cyclotomic_squared(); + + result.generate_r1cs_witness(Rval); + + asq->evaluate(); + bsq->evaluate(); + csq->evaluate(); + + compute_asq->generate_r1cs_witness(); + compute_bsq->generate_r1cs_witness(); + compute_csq->generate_r1cs_witness(); +} + +} // libsnark + +#endif // FP6_GADGETS_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/gadget_from_r1cs.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/gadget_from_r1cs.hpp new file mode 100644 index 0000000..e4b8a2a --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/gadget_from_r1cs.hpp @@ -0,0 +1,45 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a gadget that can be created from an R1CS constraint system. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef GADGET_FROM_R1CS_HPP_ +#define GADGET_FROM_R1CS_HPP_ + +#include + +#include "gadgetlib1/gadget.hpp" + +namespace libsnark { + +template +class gadget_from_r1cs : public gadget { + +private: + const std::vector > vars; + const r1cs_constraint_system cs; + std::map cs_to_vars; + +public: + + gadget_from_r1cs(protoboard &pb, + const std::vector > &vars, + const r1cs_constraint_system &cs, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(const r1cs_primary_input &primary_input, + const r1cs_auxiliary_input &auxiliary_input); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/gadget_from_r1cs.tcc" + +#endif // GADGET_FROM_R1CS_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/gadget_from_r1cs.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/gadget_from_r1cs.tcc new file mode 100644 index 0000000..bc59b45 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/gadget_from_r1cs.tcc @@ -0,0 +1,123 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a gadget that can be created from an R1CS constraint system. + + See gadget_from_r1cs.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef GADGET_FROM_R1CS_TCC_ +#define GADGET_FROM_R1CS_TCC_ + +namespace libsnark { + +template +gadget_from_r1cs::gadget_from_r1cs(protoboard &pb, + const std::vector > &vars, + const r1cs_constraint_system &cs, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + vars(vars), + cs(cs) +{ + cs_to_vars[0] = 0; /* constant term maps to constant term */ + + size_t cs_var_idx = 1; + for (auto va : vars) + { +#ifdef DEBUG + printf("gadget_from_r1cs: translating a block of variables with length %zu\n", va.size()); +#endif + for (auto v : va) + { + cs_to_vars[cs_var_idx] = v.index; + +#ifdef DEBUG + if (v.index != 0) + { + // handle annotations, except for re-annotating constant term + const std::map::const_iterator it = cs.variable_annotations.find(cs_var_idx); + + std::string annotation = FMT(annotation_prefix, " variable_%zu", cs_var_idx); + if (it != cs.variable_annotations.end()) + { + annotation = annotation_prefix + " " + it->second; + } + + pb.augment_variable_annotation(v, annotation); + } +#endif + ++cs_var_idx; + } + } + +#ifdef DEBUG + printf("gadget_from_r1cs: sum of all block lengths: %zu\n", cs_var_idx-1); + printf("gadget_from_r1cs: cs.num_variables(): %zu\n", cs.num_variables()); +#endif + + assert(cs_var_idx - 1 == cs.num_variables()); +} + +template +void gadget_from_r1cs::generate_r1cs_constraints() +{ + for (size_t i = 0; i < cs.num_constraints(); ++i) + { + const r1cs_constraint &constr = cs.constraints[i]; + r1cs_constraint translated_constr; + + for (const linear_term &t: constr.a.terms) + { + translated_constr.a.terms.emplace_back(linear_term(pb_variable(cs_to_vars[t.index]), t.coeff)); + } + + for (const linear_term &t: constr.b.terms) + { + translated_constr.b.terms.emplace_back(linear_term(pb_variable(cs_to_vars[t.index]), t.coeff)); + } + + for (const linear_term &t: constr.c.terms) + { + translated_constr.c.terms.emplace_back(linear_term(pb_variable(cs_to_vars[t.index]), t.coeff)); + } + + std::string annotation = FMT(this->annotation_prefix, " constraint_%zu", i); + +#ifdef DEBUG + auto it = cs.constraint_annotations.find(i); + if (it != cs.constraint_annotations.end()) + { + annotation = this->annotation_prefix + " " + it->second; + } +#endif + this->pb.add_r1cs_constraint(translated_constr, annotation); + } +} + +template +void gadget_from_r1cs::generate_r1cs_witness(const r1cs_primary_input &primary_input, + const r1cs_auxiliary_input &auxiliary_input) +{ + assert(cs.num_inputs() == primary_input.size()); + assert(cs.num_variables() == primary_input.size() + auxiliary_input.size()); + + for (size_t i = 0; i < primary_input.size(); ++i) + { + this->pb.val(pb_variable(cs_to_vars[i+1])) = primary_input[i]; + } + + for (size_t i = 0; i < auxiliary_input.size(); ++i) + { + this->pb.val(pb_variable(cs_to_vars[primary_input.size()+i+1])) = auxiliary_input[i]; + } +} + +} // libsnark + +#endif // GADGET_FROM_R1CS_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/crh_gadget.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/crh_gadget.hpp new file mode 100644 index 0000000..80338a3 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/crh_gadget.hpp @@ -0,0 +1,24 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef CRH_GADGET_HPP_ +#define CRH_GADGET_HPP_ + +#include "gadgetlib1/gadgets/hashes/knapsack/knapsack_gadget.hpp" + +namespace libsnark { + +// for now all CRH gadgets are knapsack CRH's; can be easily extended +// later to more expressive selector types. +template +using CRH_with_field_out_gadget = knapsack_CRH_with_field_out_gadget; + +template +using CRH_with_bit_out_gadget = knapsack_CRH_with_bit_out_gadget; + +} // libsnark + +#endif // CRH_GADGET_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp new file mode 100644 index 0000000..a7598b9 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp @@ -0,0 +1,42 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef DIGEST_SELECTOR_GADGET_HPP_ +#define DIGEST_SELECTOR_GADGET_HPP_ + +#include + +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" + +namespace libsnark { + +template +class digest_selector_gadget : public gadget { +public: + size_t digest_size; + digest_variable input; + pb_linear_combination is_right; + digest_variable left; + digest_variable right; + + digest_selector_gadget(protoboard &pb, + const size_t digest_size, + const digest_variable &input, + const pb_linear_combination &is_right, + const digest_variable &left, + const digest_variable &right, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc" + +#endif // DIGEST_SELECTOR_GADGET_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc new file mode 100644 index 0000000..422ee17 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc @@ -0,0 +1,62 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef DIGEST_SELECTOR_GADGET_TCC_ +#define DIGEST_SELECTOR_GADGET_TCC_ + +namespace libsnark { + +template +digest_selector_gadget::digest_selector_gadget(protoboard &pb, + const size_t digest_size, + const digest_variable &input, + const pb_linear_combination &is_right, + const digest_variable &left, + const digest_variable &right, + const std::string &annotation_prefix) : +gadget(pb, annotation_prefix), digest_size(digest_size), input(input), is_right(is_right), left(left), right(right) +{ +} + +template +void digest_selector_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < digest_size; ++i) + { + /* + input = is_right * right + (1-is_right) * left + input - left = is_right(right - left) + */ + this->pb.add_r1cs_constraint(r1cs_constraint(is_right, right.bits[i] - left.bits[i], input.bits[i] - left.bits[i]), + FMT(this->annotation_prefix, " propagate_%zu", i)); + } +} + +template +void digest_selector_gadget::generate_r1cs_witness() +{ + is_right.evaluate(this->pb); + + assert(this->pb.lc_val(is_right) == FieldT::one() || this->pb.lc_val(is_right) == FieldT::zero()); + if (this->pb.lc_val(is_right) == FieldT::one()) + { + for (size_t i = 0; i < digest_size; ++i) + { + this->pb.val(right.bits[i]) = this->pb.val(input.bits[i]); + } + } + else + { + for (size_t i = 0; i < digest_size; ++i) + { + this->pb.val(left.bits[i]) = this->pb.val(input.bits[i]); + } + } +} + +} // libsnark + +#endif // DIGEST_SELECTOR_GADGET_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/hash_io.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/hash_io.hpp new file mode 100644 index 0000000..80ca19c --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/hash_io.hpp @@ -0,0 +1,63 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef HASH_IO_HPP_ +#define HASH_IO_HPP_ +#include +#include +#include "gadgetlib1/gadgets/basic_gadgets.hpp" + +namespace libsnark { + +template +class digest_variable : public gadget { +public: + size_t digest_size; + pb_variable_array bits; + + digest_variable(protoboard &pb, + const size_t digest_size, + const std::string &annotation_prefix); + + digest_variable(protoboard &pb, + const size_t digest_size, + const pb_variable_array &partial_bits, + const pb_variable &padding, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(const bit_vector& contents); + bit_vector get_digest() const; +}; + +template +class block_variable : public gadget { +public: + size_t block_size; + pb_variable_array bits; + + block_variable(protoboard &pb, + const size_t block_size, + const std::string &annotation_prefix); + + block_variable(protoboard &pb, + const std::vector > &parts, + const std::string &annotation_prefix); + + block_variable(protoboard &pb, + const digest_variable &left, + const digest_variable &right, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(const bit_vector& contents); + bit_vector get_block() const; +}; + +} // libsnark +#include "gadgetlib1/gadgets/hashes/hash_io.tcc" + +#endif // HASH_IO_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/hash_io.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/hash_io.tcc new file mode 100644 index 0000000..b122d8f --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/hash_io.tcc @@ -0,0 +1,105 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef HASH_IO_TCC_ +#define HASH_IO_TCC_ + +namespace libsnark { + +template +digest_variable::digest_variable(protoboard &pb, + const size_t digest_size, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), digest_size(digest_size) +{ + bits.allocate(pb, digest_size, FMT(this->annotation_prefix, " bits")); +} + +template +digest_variable::digest_variable(protoboard &pb, + const size_t digest_size, + const pb_variable_array &partial_bits, + const pb_variable &padding, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), digest_size(digest_size) +{ + assert(bits.size() <= digest_size); + bits = partial_bits; + while (bits.size() != digest_size) + { + bits.emplace_back(padding); + } +} + +template +void digest_variable::generate_r1cs_constraints() +{ + for (size_t i = 0; i < digest_size; ++i) + { + generate_boolean_r1cs_constraint(this->pb, bits[i], FMT(this->annotation_prefix, " bits_%zu", i)); + } +} + +template +void digest_variable::generate_r1cs_witness(const bit_vector& contents) +{ + bits.fill_with_bits(this->pb, contents); +} + +template +bit_vector digest_variable::get_digest() const +{ + return bits.get_bits(this->pb); +} + +template +block_variable::block_variable(protoboard &pb, + const size_t block_size, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), block_size(block_size) +{ + bits.allocate(pb, block_size, FMT(this->annotation_prefix, " bits")); +} + +template +block_variable::block_variable(protoboard &pb, + const std::vector > &parts, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + for (auto &part : parts) + { + bits.insert(bits.end(), part.begin(), part.end()); + } +} + +template +block_variable::block_variable(protoboard &pb, + const digest_variable &left, + const digest_variable &right, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + assert(left.bits.size() == right.bits.size()); + block_size = 2 * left.bits.size(); + bits.insert(bits.end(), left.bits.begin(), left.bits.end()); + bits.insert(bits.end(), right.bits.begin(), right.bits.end()); +} + +template +void block_variable::generate_r1cs_witness(const bit_vector& contents) +{ + bits.fill_with_bits(this->pb, contents); +} + +template +bit_vector block_variable::get_block() const +{ + return bits.get_bits(this->pb); +} + +} // libsnark +#endif // HASH_IO_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/knapsack/knapsack_gadget.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/knapsack/knapsack_gadget.hpp new file mode 100644 index 0000000..571a498 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/knapsack/knapsack_gadget.hpp @@ -0,0 +1,134 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the knapsack gadget. + + The gadget checks the correct execution of a knapsack (modular subset-sum) over + the field specified in the template parameter. With suitable choices of parameters + such knapsacks are collision-resistant hashes (CRHs). See \[Ajt96] and \[GGH96]. + + Given two positive integers m (the input length) and d (the dimension), + and a matrix M over the field F and of dimension dxm, the hash H_M maps {0,1}^m + to F^d by sending x to M*x. Security of the function (very roughly) depends on + d*log(|F|). + + Below, we give two different gadgets: + - knapsack_CRH_with_field_out_gadget, which verifies H_M + - knapsack_CRH_with_bit_out_gadget, which verifies H_M when its output is "expanded" to bits. + In both cases, a method ("sample_randomness") allows to sample M. + + The parameter d (the dimension) is fixed at compile time in the struct + knapsack_dimension below. The parameter m (the input lenght) can be chosen + at run time (in either gadget). + + + References: + + \[Ajt96]: + "Generating hard instances of lattice problems", + Miklos Ajtai, + STOC 1996 + + \[GGH96]: + "Collision-free hashing from lattice problems", + Oded Goldreich, Shafi Goldwasser, Shai Halevi, + ECCC TR95-042 + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef KNAPSACK_GADGET_HPP_ +#define KNAPSACK_GADGET_HPP_ + +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" +#include "common/data_structures/merkle_tree.hpp" + +namespace libsnark { + +/************************** Choice of dimension ******************************/ + +template +struct knapsack_dimension { + // the size of FieldT should be (approximately) at least 200 bits + static const size_t dimension = 1; +}; + +/*********************** Knapsack with field output **************************/ + +template +class knapsack_CRH_with_field_out_gadget : public gadget { +private: + static std::vector knapsack_coefficients; + static size_t num_cached_coefficients; + +public: + size_t input_len; + size_t dimension; + + block_variable input_block; + pb_linear_combination_array output; + + knapsack_CRH_with_field_out_gadget(protoboard &pb, + const size_t input_len, + const block_variable &input_block, + const pb_linear_combination_array &output, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); + + static size_t get_digest_len(); + static size_t get_block_len(); /* return 0 as block length, as the hash function is variable-input */ + static std::vector get_hash(const bit_vector &input); + static void sample_randomness(const size_t input_len); + + /* for debugging */ + static size_t expected_constraints(); +}; + +/********************** Knapsack with binary output **************************/ + +template +class knapsack_CRH_with_bit_out_gadget : public gadget { +public: + typedef bit_vector hash_value_type; + typedef merkle_authentication_path merkle_authentication_path_type; + + size_t input_len; + size_t dimension; + + pb_linear_combination_array output; + + std::shared_ptr > hasher; + + block_variable input_block; + digest_variable output_digest; + + knapsack_CRH_with_bit_out_gadget(protoboard &pb, + const size_t input_len, + const block_variable &input_block, + const digest_variable &output_digest, + const std::string &annotation_prefix); + void generate_r1cs_constraints(const bool enforce_bitness=true); + void generate_r1cs_witness(); + + static size_t get_digest_len(); + static size_t get_block_len(); /* return 0 as block length, as the hash function is variable-input */ + static hash_value_type get_hash(const bit_vector &input); + static void sample_randomness(const size_t input_len); + + /* for debugging */ + static size_t expected_constraints(const bool enforce_bitness=true); +}; + +template +void test_knapsack_CRH_with_bit_out_gadget(); + +} // libsnark + +#include "gadgetlib1/gadgets/hashes/knapsack/knapsack_gadget.tcc" + +#endif // KNAPSACK_GADGET_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/knapsack/knapsack_gadget.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/knapsack/knapsack_gadget.tcc new file mode 100644 index 0000000..ca3b5aa --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/knapsack/knapsack_gadget.tcc @@ -0,0 +1,259 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the knapsack gadget. + + See knapsack_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef KNAPSACK_GADGET_TCC_ +#define KNAPSACK_GADGET_TCC_ + +#include "algebra/fields/field_utils.hpp" +#include "common/rng.hpp" + +namespace libsnark { + +template +std::vector knapsack_CRH_with_field_out_gadget::knapsack_coefficients; +template +size_t knapsack_CRH_with_field_out_gadget::num_cached_coefficients; + +template +knapsack_CRH_with_field_out_gadget::knapsack_CRH_with_field_out_gadget(protoboard &pb, + const size_t input_len, + const block_variable &input_block, + const pb_linear_combination_array &output, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + input_len(input_len), + dimension(knapsack_dimension::dimension), + input_block(input_block), + output(output) +{ + assert(input_block.bits.size() == input_len); + if (num_cached_coefficients < dimension * input_len) + { + sample_randomness(input_len); + } + assert(output.size() == this->get_digest_len()); +} + +template +void knapsack_CRH_with_field_out_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < dimension; ++i) + { + this->pb.add_r1cs_constraint(r1cs_constraint(1, + pb_coeff_sum(input_block.bits, + std::vector(knapsack_coefficients.begin() + input_len * i, + knapsack_coefficients.begin() + input_len * (i+1))), + output[i]), FMT(this->annotation_prefix, " knapsack_%zu", i)); + } +} + +template +void knapsack_CRH_with_field_out_gadget::generate_r1cs_witness() +{ + const bit_vector input = input_block.get_block(); + + for (size_t i = 0; i < dimension; ++i) + { + FieldT sum = FieldT::zero(); + for (size_t k = 0; k < input_len; ++k) + { + if (input[k]) + { + sum += knapsack_coefficients[input_len*i + k]; + } + } + + this->pb.lc_val(output[i]) = sum; + } +} + +template +size_t knapsack_CRH_with_field_out_gadget::get_digest_len() +{ + return knapsack_dimension::dimension; +} + +template +size_t knapsack_CRH_with_field_out_gadget::get_block_len() +{ + return 0; +} + +template +std::vector knapsack_CRH_with_field_out_gadget::get_hash(const bit_vector &input) +{ + const size_t dimension = knapsack_dimension::dimension; + if (num_cached_coefficients < dimension * input.size()) + { + sample_randomness(input.size()); + } + + std::vector result(dimension, FieldT::zero()); + + for (size_t i = 0; i < dimension; ++i) + { + for (size_t k = 0; k < input.size(); ++k) + { + if (input[k]) + { + result[i] += knapsack_coefficients[input.size()*i + k]; + } + } + } + + return result; +} + +template +size_t knapsack_CRH_with_field_out_gadget::expected_constraints() +{ + return knapsack_dimension::dimension; +} + +template +void knapsack_CRH_with_field_out_gadget::sample_randomness(const size_t input_len) +{ + const size_t num_coefficients = knapsack_dimension::dimension * input_len; + if (num_coefficients > num_cached_coefficients) + { + knapsack_coefficients.resize(num_coefficients); + for (size_t i = num_cached_coefficients; i < num_coefficients; ++i) + { + knapsack_coefficients[i] = SHA512_rng(i); + } + num_cached_coefficients = num_coefficients; + } +} + +template +knapsack_CRH_with_bit_out_gadget::knapsack_CRH_with_bit_out_gadget(protoboard &pb, + const size_t input_len, + const block_variable &input_block, + const digest_variable &output_digest, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + input_len(input_len), + dimension(knapsack_dimension::dimension), + input_block(input_block), + output_digest(output_digest) +{ + assert(output_digest.bits.size() == this->get_digest_len()); + + output.resize(dimension); + + for (size_t i = 0; i < dimension; ++i) + { + output[i].assign(pb, pb_packing_sum(pb_variable_array(output_digest.bits.begin() + i * FieldT::size_in_bits(), + output_digest.bits.begin() + (i + 1) * FieldT::size_in_bits()))); + } + + hasher.reset(new knapsack_CRH_with_field_out_gadget(pb, input_len, input_block, output, FMT(annotation_prefix, " hasher"))); +} + + +template +void knapsack_CRH_with_bit_out_gadget::generate_r1cs_constraints(const bool enforce_bitness) +{ + hasher->generate_r1cs_constraints(); + + if (enforce_bitness) + { + for (size_t k = 0; k < output_digest.bits.size(); ++k) + { + generate_boolean_r1cs_constraint(this->pb, output_digest.bits[k], FMT(this->annotation_prefix, " output_digest_%zu", k)); + } + } +} + +template +void knapsack_CRH_with_bit_out_gadget::generate_r1cs_witness() +{ + hasher->generate_r1cs_witness(); + + /* do unpacking in place */ + const bit_vector input = input_block.bits.get_bits(this->pb); + for (size_t i = 0; i < dimension; ++i) + { + pb_variable_array va(output_digest.bits.begin() + i * FieldT::size_in_bits(), + output_digest.bits.begin() + (i + 1) * FieldT::size_in_bits()); + va.fill_with_bits_of_field_element(this->pb, this->pb.lc_val(output[i])); + } +} + +template +size_t knapsack_CRH_with_bit_out_gadget::get_digest_len() +{ + return knapsack_dimension::dimension * FieldT::size_in_bits(); +} + +template +size_t knapsack_CRH_with_bit_out_gadget::get_block_len() +{ + return 0; +} + +template +bit_vector knapsack_CRH_with_bit_out_gadget::get_hash(const bit_vector &input) +{ + const std::vector hash_elems = knapsack_CRH_with_field_out_gadget::get_hash(input); + hash_value_type result; + + for (const FieldT &elt : hash_elems) + { + bit_vector elt_bits = convert_field_element_to_bit_vector(elt); + result.insert(result.end(), elt_bits.begin(), elt_bits.end()); + } + + return result; +} + +template +size_t knapsack_CRH_with_bit_out_gadget::expected_constraints(const bool enforce_bitness) +{ + const size_t hasher_constraints = knapsack_CRH_with_field_out_gadget::expected_constraints(); + const size_t bitness_constraints = (enforce_bitness ? get_digest_len() : 0); + return hasher_constraints + bitness_constraints; +} + +template +void knapsack_CRH_with_bit_out_gadget::sample_randomness(const size_t input_len) +{ + knapsack_CRH_with_field_out_gadget::sample_randomness(input_len); +} + +template +void test_knapsack_CRH_with_bit_out_gadget_internal(const size_t dimension, const bit_vector &input_bits, const bit_vector &digest_bits) +{ + assert(knapsack_dimension::dimension == dimension); + knapsack_CRH_with_bit_out_gadget::sample_randomness(input_bits.size()); + protoboard pb; + + block_variable input_block(pb, input_bits.size(), "input_block"); + digest_variable output_digest(pb, knapsack_CRH_with_bit_out_gadget::get_digest_len(), "output_digest"); + knapsack_CRH_with_bit_out_gadget H(pb, input_bits.size(), input_block, output_digest, "H"); + + input_block.generate_r1cs_witness(input_bits); + H.generate_r1cs_constraints(); + H.generate_r1cs_witness(); + + assert(output_digest.get_digest().size() == digest_bits.size()); + assert(pb.is_satisfied()); + + const size_t num_constraints = pb.num_constraints(); + const size_t expected_constraints = knapsack_CRH_with_bit_out_gadget::expected_constraints(); + assert(num_constraints == expected_constraints); +} + +} // libsnark + +#endif // KNAPSACK_GADGET_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/knapsack/tests/generate_knapsack_tests.py b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/knapsack/tests/generate_knapsack_tests.py new file mode 100644 index 0000000..fb16de2 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/knapsack/tests/generate_knapsack_tests.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +## +# @author This file is part of libsnark, developed by SCIPR Lab +# and contributors (see AUTHORS). +# @copyright MIT license (see LICENSE file) + +import random +import hashlib +import struct +import math + +def bitlength(p): + return int(math.ceil(math.log(p, 2))) + +def SHA512_prng(i, p): + """Generates nothing-up-my-sleeve random numbers. i-th random number + is obtained by applying SHA512 to successively (i || 0), (i || 1), + ... (both i and the counter treated as 64-bit integers) until the + first of them, when having all but ceil(log(p)) bits cleared, is + less than p. + + TODO: describe byte order + + """ + mask = 2 ** bitlength(p) + it = 0 + while True: + val = int(hashlib.sha512(struct.pack("=QQ", i, it)).digest()[::-1].encode('hex'), 16) % mask + if val < p: + return val + else: + it += 1 + +def int_to_bits(i, p): + outbits = bin(i)[2:][::-1] + outbits = outbits + '0' * (bitlength(p) - len(outbits)) + return [int(b) for b in outbits] + +def bool_arr(bits): + return '{%s}' % ','.join(str(b) for b in bits) + +def knapsack_hash(bits, p, dimension): + result = [] + for chunk in xrange(dimension): + total = 0 + for i, b in enumerate(bits): + total = (total + b * SHA512_prng(chunk * len(bits) + i, p)) % p + print '// hash_vector[%d] = %d' % (chunk, total) + result += int_to_bits(total, p) + return result + +def generate_knapsack_test(p_name, dimension, bits): + print "// tests for knapsack_CRH_with_bit_output<%s> and dimension %d" % (p_name, dimension) + p = globals()[p_name] + print 'const size_t dimension = %d;' % dimension + print 'const bit_vector input_bits = %s;' % bool_arr(bits) + h = knapsack_hash(bits, p, dimension) + print 'const bit_vector digest_bits = %s;' % bool_arr(h) + +def rand_bits(count): + return [random.randint(0, 1) for i in xrange(count)] + +bn128_r = 21888242871839275222246405745257275088548364400416034343698204186575808495617 +edwards_r = 1552511030102430251236801561344621993261920897571225601 +mnt4_r = 475922286169261325753349249653048451545124878552823515553267735739164647307408490559963137 +mnt6_r = 475922286169261325753349249653048451545124879242694725395555128576210262817955800483758081 + +if __name__ == '__main__': + random.seed(0) # for reproducibility + + contents = rand_bits(10) + for dimension in [1,3]: + generate_knapsack_test("bn128_r", dimension, contents) + generate_knapsack_test("edwards_r", dimension, contents) + generate_knapsack_test("mnt4_r", dimension, contents) + generate_knapsack_test("mnt6_r", dimension, contents) diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/knapsack/tests/test_knapsack_gadget.cpp b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/knapsack/tests/test_knapsack_gadget.cpp new file mode 100644 index 0000000..54a7119 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/knapsack/tests/test_knapsack_gadget.cpp @@ -0,0 +1,156 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifdef CURVE_BN128 +#include "algebra/curves/bn128/bn128_pp.hpp" +#endif +#include "algebra/curves/edwards/edwards_pp.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +#include "gadgetlib1/gadgets/hashes/knapsack/knapsack_gadget.hpp" + +namespace libsnark { + +/* These are fully specialized so cannot live in the corresponding + * .tcc file. Furthermore, the tests are autogenerated (see + * generate_knapsack_tests.py) and contain hard-to-read constants. */ + +#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled +template<> +void test_knapsack_CRH_with_bit_out_gadget >() +{ + typedef Fr FieldT; + const size_t dimension = knapsack_dimension::dimension; + const bit_vector input_bits = {1,1,0,0,1,0,1,0,0,1}; + bit_vector digest_bits; + + if (dimension == 1) + { + // hash_vector[0] = 19358128397917746746715486768528331499472172224025066869640626465460783114989 + digest_bits = {1,0,1,1,0,1,1,1,0,1,0,1,0,1,1,0,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,0,0,1,1,1,0,1,0,0,0,1,0,1,0,1,0,0,1,0,0,0,1,0,1,0,1,1,0,0,1,1,0,0,1,0,0,1,1,0,0,1,1,1,0,1,1,1,0,0,1,0,1,1,0,0,1,1,1,1,0,1,0,1,1,0,0,1,1,1,0,0,1,0,1,0,1,1,0,0,1,1,0,0,0,0,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,0,0,0,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,0,1,0,0,1,1,0,0,0,1,0,0,0,0,1,0,1,0,1,0,0,0,0,1,0,0,0,0,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,0,0,0,1,0,1,1,0,1,1,0,1,0,0,0,1,1,0,0,0,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,0,0,0,1,1,0,0,1,1,0,1,0,1,0,1}; + } + else if (dimension == 3) + { + // hash_vector[0] = 19358128397917746746715486768528331499472172224025066869640626465460783114989 + // hash_vector[1] = 14647747576997998233659818696206913383172548767133711974605617840575181365754 + // hash_vector[2] = 2920097934141708417756781671323464432263982766704831772622221878471527707999 + digest_bits = {1,0,1,1,0,1,1,1,0,1,0,1,0,1,1,0,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,0,0,1,1,1,0,1,0,0,0,1,0,1,0,1,0,0,1,0,0,0,1,0,1,0,1,1,0,0,1,1,0,0,1,0,0,1,1,0,0,1,1,1,0,1,1,1,0,0,1,0,1,1,0,0,1,1,1,1,0,1,0,1,1,0,0,1,1,1,0,0,1,0,1,0,1,1,0,0,1,1,0,0,0,0,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,0,0,0,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,0,1,0,0,1,1,0,0,0,1,0,0,0,0,1,0,1,0,1,0,0,0,0,1,0,0,0,0,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,0,0,0,1,0,1,1,0,1,1,0,1,0,0,0,1,1,0,0,0,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,0,0,0,1,1,0,0,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,0,0,0,0,1,0,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,0,0,1,1,0,1,0,0,1,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,1,0,1,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,0,1,0,0,0,1,1,1,0,1,0,0,1,0,0,1,1,1,0,1,1,0,1,0,1,0,0,1,1,1,0,1,0,0,1,1,1,0,1,0,0,0,0,1,0,0,0,1,1,1,1,0,0,1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,1,0,1,1,0,1,0,0,0,0,1,1,1,0,1,0,0,0,1,1,0,1,1,1,0,0,1,0,1,0,0,1,0,1,0,1,1,1,0,0,0,0,1,0,1,0,0,1,1,0,0,1,1,0,0,0,1,1,0,1,0,0,0,0,0,0,1,0,0,0,0,1,0,0,1,0,1,1,0,0,1,0,1,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,0,0,1,1,1,1,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,0,1,0,0,0,0,1,0,0,1,1,0,1,1,0,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,0,0,0,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,0,0,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,0,1,1,0,0,1,0,1,0,0,0,1,0,0,1,1,0,0,1,1,1,1,0,1,1,0,1,0,1,1,0,0,0,1,1,1,0,1,1,1,1,0,1,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,1,1,1,1,1,1,0,1,1,0,0,0,1,0,1,1,1,1,0,1,1,0,1,1,0,1,1,0,1,0,0,1,1,1,1,0,0,1,0,1,0,1,0,1,0,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,0,0,0,1,1,1,1,0,1,1,0,1,0,0,1,0,1,1,1,0,0,1,1,0,0,0}; + } + else + { + printf("unsupported dimension\n"); + return; + } + + test_knapsack_CRH_with_bit_out_gadget_internal(dimension, input_bits, digest_bits); +} +#endif + +template<> +void test_knapsack_CRH_with_bit_out_gadget >() +{ + typedef Fr FieldT; + const size_t dimension = knapsack_dimension::dimension; + const bit_vector input_bits = {1,1,0,0,1,0,1,0,0,1}; + bit_vector digest_bits; + + if (dimension == 1) + { + // hash_vector[0] = 212682788919191185746369136465846038795231156077120478 + digest_bits = {0,1,1,1,1,0,1,1,1,1,0,1,0,0,1,1,0,0,1,0,0,1,1,1,0,1,0,1,0,1,1,0,1,0,1,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,0,1,0,0,1,1,0,1,0,1,0,0,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,0,0,0,0,1,0,0,1,1,1,0,0,1,0,1,0,0,0,0,1,1,1,1,1,1,0,1,0,0,1,1,1,0,1,0,0,0,0,0,1,1,0,1,0,1,1,1,0,0,1,1,1,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,1,1,0,1,1,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,1,0,0,0}; + } + else if (dimension == 3) + { + // hash_vector[0] = 212682788919191185746369136465846038795231156077120478 + // hash_vector[1] = 208444103178970253386051017880119245406612361624666932 + // hash_vector[2] = 753512267902403701181906991398452949644481965281690464 + digest_bits = {0,1,1,1,1,0,1,1,1,1,0,1,0,0,1,1,0,0,1,0,0,1,1,1,0,1,0,1,0,1,1,0,1,0,1,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,0,1,0,0,1,1,0,1,0,1,0,0,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,0,0,0,0,1,0,0,1,1,1,0,0,1,0,1,0,0,0,0,1,1,1,1,1,1,0,1,0,0,1,1,1,0,1,0,0,0,0,0,1,1,0,1,0,1,1,1,0,0,1,1,1,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,1,1,0,1,1,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,1,0,0,0,0,0,1,0,1,1,0,0,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,1,0,1,1,1,0,0,0,1,1,0,0,0,0,0,1,1,0,1,0,0,1,0,1,0,0,0,0,1,1,0,1,1,1,0,1,1,0,1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,1,0,0,0,1,1,1,1,0,1,0,0,0,0,1,1,0,0,1,1,1,0,0,1,0,0,0,1,1,1,1,1,1,0,0,0,0,0,1,0,1,0,1,0,1,1,1,0,1,0,1,1,0,0,0,1,1,1,1,1,0,0,1,1,1,1,1,0,0,0,1,0,1,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,1,0,1,1,0,0,0,0,1,1,0,1,1,0,1,1,1,1,0,1,0,1,0,0,1,0,0,1,1,0,0,1,1,1,0,1,1,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,1,1,1,1,0,1,1,0,1,0,1,0,1,1,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,1,1,0,0,0,0,1,0,0,0,1,1,0,0,1,1,0,0,1,0,0,0,0,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,1,1,0,0,0,1,0,0,1,1,1,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0,0}; + } + else + { + printf("unsupported dimension\n"); + return; + } + + test_knapsack_CRH_with_bit_out_gadget_internal(dimension, input_bits, digest_bits); +} + +template<> +void test_knapsack_CRH_with_bit_out_gadget >() +{ + typedef Fr FieldT; + const size_t dimension = knapsack_dimension::dimension; + const bit_vector input_bits = {1,1,0,0,1,0,1,0,0,1}; + bit_vector digest_bits; + + if (dimension == 1) + { + // hash_vector[0] = 5849873898117023322885358421738220900336336792093854367505800858141298949423761399689551 + digest_bits = {1,1,1,1,0,0,1,0,1,0,0,0,1,1,0,0,1,1,0,0,1,0,0,0,0,1,0,1,0,0,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,0,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,0,0,1,1,0,0,1,0,1,0,1,0,0,1,0,1,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1,0,0,0,0,0,1,1,0,0,0,1,1,1,1,0,1,0,1,0,1,1,0,1,0,0,1,0,0,0,1,1,1,1,1,1,1,1,0,1,0,1,0,0,0,0,0,1,1,1,1,0,0,0,1,0,0,1,1,1,0,0,0,1,1,1,1,1,1,0,1,0,1,0,0,1,1,0,0,1,1,1,1,0,0,0,1,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,0,0,1,1,0,1,0,1,1,0,1,1,1,0,0,1,1,1,1,1,0,1,0,0,0,1,0,0,1,1,1,0,1,1,0,1,1,0,0,1,1,0,0,0,0,0,1,0,1,1,0,0,0,0,1,1,1,1,0,1,0,0,0,0,0,0}; + } + else if (dimension == 3) + { + // hash_vector[0] = 5849873898117023322885358421738220900336336792093854367505800858141298949423761399689551 + // hash_vector[1] = 53446030978469113922159049491079907226345855403292835149508287198951741313094713251809734 + // hash_vector[2] = 40260485387428589838404886401807432179330886729322245141417568340931755675196614173996382 +digest_bits = {1,1,1,1,0,0,1,0,1,0,0,0,1,1,0,0,1,1,0,0,1,0,0,0,0,1,0,1,0,0,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,0,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,0,0,1,1,0,0,1,0,1,0,1,0,0,1,0,1,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1,0,0,0,0,0,1,1,0,0,0,1,1,1,1,0,1,0,1,0,1,1,0,1,0,0,1,0,0,0,1,1,1,1,1,1,1,1,0,1,0,1,0,0,0,0,0,1,1,1,1,0,0,0,1,0,0,1,1,1,0,0,0,1,1,1,1,1,1,0,1,0,1,0,0,1,1,0,0,1,1,1,1,0,0,0,1,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,0,0,1,1,0,1,0,1,1,0,1,1,1,0,0,1,1,1,1,1,0,1,0,0,0,1,0,0,1,1,1,0,1,1,0,1,1,0,0,1,1,0,0,0,0,0,1,0,1,1,0,0,0,0,1,1,1,1,0,1,0,0,0,0,0,0,0,1,1,0,0,0,1,1,1,0,0,1,0,0,1,0,1,0,0,0,0,0,1,0,1,1,0,0,0,0,1,1,0,0,0,1,1,1,1,1,0,1,0,1,1,0,1,1,1,1,1,1,0,0,1,0,1,0,0,1,0,0,1,0,1,1,1,1,1,1,1,1,0,1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,1,1,1,0,1,0,0,0,0,1,1,1,1,1,0,1,1,0,1,1,1,0,0,1,0,1,1,1,0,0,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,1,0,1,1,0,1,1,0,1,0,1,0,0,0,0,0,1,0,1,1,0,1,0,1,0,0,0,1,1,1,0,1,1,0,0,1,0,1,0,0,1,1,0,1,1,0,0,0,1,0,0,0,0,0,1,1,1,1,1,1,0,1,1,0,0,0,1,1,1,0,0,0,1,0,0,1,1,1,1,0,1,1,0,1,1,0,1,0,0,0,1,0,0,1,0,0,1,1,1,1,1,0,1,1,0,0,1,0,1,1,1,1,0,1,1,1,0,1,1,0,1,0,1,1,0,0,0,0,1,1,1,1,0,1,0,1,0,1,0,1,1,0,0,1,1,1,1,0,1,0,0,1,0,1,0,0,1,1,0,0,1,1,1,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,0,1,0,1,0,1,1,0,1,0,0,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,1,1,0,1,1,1,0,0,0,1,0,1,1,1,1,0,0,0,0,1,0,0,0,0,1,0,0,1,0,0,0,1,0,1,1,0,0,1,0,0,0,1,0,1,0,0,1,0,1,0,1,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,1,0,1,0,1,1,1,1,1,0,1,0,0,1,1,1,0,0,1,1,0,0,1,1,1,0,0,1,0,1,1,0,1,0,1,1,1,1,0,0,1,1,0,0,1,1,1,1,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,1,0,0,0,0,1,0,0,1,0,1,1,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1,1,1,1,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,1,1,1,0,0,0,0,1,0,1,0,0,0}; + } + else + { + printf("unsupported dimension\n"); + return; + } + + test_knapsack_CRH_with_bit_out_gadget_internal(dimension, input_bits, digest_bits); +} + +template<> +void test_knapsack_CRH_with_bit_out_gadget >() +{ + typedef Fr FieldT; + const size_t dimension = knapsack_dimension::dimension; + const bit_vector input_bits = {1,1,0,0,1,0,1,0,0,1}; + bit_vector digest_bits; + + if (dimension == 1) + { + // hash_vector[0] = 5849873898117023322885358421738220900336335412351434682931015184050067928329141552099663 + digest_bits = {1,1,1,1,0,0,1,0,1,0,0,0,1,1,0,0,1,1,1,0,0,0,1,0,1,1,1,0,0,1,1,1,1,0,0,0,0,1,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,0,1,0,1,1,0,1,1,0,1,0,1,1,1,1,0,1,0,0,0,0,0,1,0,1,1,0,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,1,1,1,0,0,1,1,0,0,1,0,0,0,0,0,1,1,1,0,1,1,1,0,0,0,1,0,1,0,1,1,0,0,0,1,1,1,0,0,1,1,0,1,1,0,1,0,1,1,0,1,1,0,0,0,0,1,1,1,1,1,1,1,0,1,0,1,0,0,0,0,0,1,1,1,1,0,0,0,1,0,0,1,1,1,0,0,0,1,1,1,1,1,1,0,1,0,1,0,0,1,1,0,0,1,1,1,1,0,0,0,1,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,0,0,1,1,0,1,0,1,1,0,1,1,1,0,0,1,1,1,1,1,0,1,0,0,0,1,0,0,1,1,1,0,1,1,0,1,1,0,0,1,1,0,0,0,0,0,1,0,1,1,0,0,0,0,1,1,1,1,0,1,0,0,0,0,0,0}; + } + else if (dimension == 3) + { + // hash_vector[0] = 5849873898117023322885358421738220900336335412351434682931015184050067928329141552099663 + // hash_vector[1] = 53446030978469113922159049491079907226345854023550415464933501524860510292000093404219846 + // hash_vector[2] = 40260485387428589838404886401807432179330884659708615614555389829794909143554684402611550 + digest_bits = {1,1,1,1,0,0,1,0,1,0,0,0,1,1,0,0,1,1,1,0,0,0,1,0,1,1,1,0,0,1,1,1,1,0,0,0,0,1,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,0,1,0,1,1,0,1,1,0,1,0,1,1,1,1,0,1,0,0,0,0,0,1,0,1,1,0,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,1,1,1,0,0,1,1,0,0,1,0,0,0,0,0,1,1,1,0,1,1,1,0,0,0,1,0,1,0,1,1,0,0,0,1,1,1,0,0,1,1,0,1,1,0,1,0,1,1,0,1,1,0,0,0,0,1,1,1,1,1,1,1,0,1,0,1,0,0,0,0,0,1,1,1,1,0,0,0,1,0,0,1,1,1,0,0,0,1,1,1,1,1,1,0,1,0,1,0,0,1,1,0,0,1,1,1,1,0,0,0,1,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,0,0,1,1,0,1,0,1,1,0,1,1,1,0,0,1,1,1,1,1,0,1,0,0,0,1,0,0,1,1,1,0,1,1,0,1,1,0,0,1,1,0,0,0,0,0,1,0,1,1,0,0,0,0,1,1,1,1,0,1,0,0,0,0,0,0,0,1,1,0,0,0,1,1,1,0,0,1,0,0,1,0,1,0,1,0,1,1,1,0,0,0,0,0,0,1,1,1,1,1,0,1,0,0,0,1,1,1,1,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,1,1,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,0,0,1,0,1,0,1,1,1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,1,0,1,1,0,1,1,0,1,0,1,0,0,0,0,0,1,0,1,1,0,1,0,1,0,0,0,1,1,1,0,1,1,0,0,1,0,1,0,0,1,1,0,1,1,0,0,0,1,0,0,0,0,0,1,1,1,1,1,1,0,1,1,0,0,0,1,1,1,0,0,0,1,0,0,1,1,1,1,0,1,1,0,1,1,0,1,0,0,0,1,0,0,1,0,0,1,1,1,1,1,0,1,1,0,0,1,0,1,1,1,1,0,1,1,1,0,1,1,0,1,0,1,1,0,0,0,0,1,1,1,1,0,1,0,1,0,1,0,1,1,0,0,1,0,1,1,1,1,1,1,0,0,0,0,1,0,0,0,1,1,0,1,0,1,0,0,0,1,0,1,1,0,0,0,1,1,0,0,1,0,0,1,1,0,0,1,0,1,0,0,0,1,1,1,0,0,1,1,1,0,0,0,1,1,0,1,1,0,1,1,0,1,0,0,1,1,0,1,0,0,0,0,1,1,0,1,0,0,0,0,1,1,0,1,1,0,1,0,1,1,1,1,0,1,0,1,1,0,0,0,1,1,1,0,1,0,0,1,0,1,0,1,1,1,1,1,0,0,0,1,0,0,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,0,1,1,1,0,0,1,1,0,0,1,1,1,0,0,1,0,1,1,0,1,0,1,1,1,1,0,0,1,1,0,0,1,1,1,1,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,1,0,0,0,0,1,0,0,1,0,1,1,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1,1,1,1,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,1,1,1,0,0,0,0,1,0,1,0,0,0}; + } + else + { + printf("unsupported dimension\n"); + return; + } + + test_knapsack_CRH_with_bit_out_gadget_internal(dimension, input_bits, digest_bits); +} + +} // libsnark + +using namespace libsnark; + +int main(void) +{ +#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled + bn128_pp::init_public_params(); + test_knapsack_CRH_with_bit_out_gadget >(); +#endif + edwards_pp::init_public_params(); + test_knapsack_CRH_with_bit_out_gadget >(); + mnt4_pp::init_public_params(); + test_knapsack_CRH_with_bit_out_gadget >(); + mnt6_pp::init_public_params(); + test_knapsack_CRH_with_bit_out_gadget >(); +} diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp new file mode 100644 index 0000000..e0c7a7e --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp @@ -0,0 +1,160 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for auxiliary gadgets for the SHA256 gadget. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SHA256_AUX_HPP_ +#define SHA256_AUX_HPP_ + +#include "gadgetlib1/gadgets/basic_gadgets.hpp" + +namespace libsnark { + +template +class lastbits_gadget : public gadget { +public: + pb_variable X; + size_t X_bits; + pb_variable result; + pb_linear_combination_array result_bits; + + pb_linear_combination_array full_bits; + std::shared_ptr > unpack_bits; + std::shared_ptr > pack_result; + + lastbits_gadget(protoboard &pb, + const pb_variable &X, + const size_t X_bits, + const pb_variable &result, + const pb_linear_combination_array &result_bits, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +class XOR3_gadget : public gadget { +private: + pb_variable tmp; +public: + pb_linear_combination A; + pb_linear_combination B; + pb_linear_combination C; + bool assume_C_is_zero; + pb_linear_combination out; + + XOR3_gadget(protoboard &pb, + const pb_linear_combination &A, + const pb_linear_combination &B, + const pb_linear_combination &C, + const bool assume_C_is_zero, + const pb_linear_combination &out, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ +template +class small_sigma_gadget : public gadget { +private: + pb_variable_array W; + pb_variable result; +public: + pb_variable_array result_bits; + std::vector > > compute_bits; + std::shared_ptr > pack_result; + + small_sigma_gadget(protoboard &pb, + const pb_variable_array &W, + const pb_variable &result, + const size_t rot1, + const size_t rot2, + const size_t shift, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ +template +class big_sigma_gadget : public gadget { +private: + pb_linear_combination_array W; + pb_variable result; +public: + pb_variable_array result_bits; + std::vector > > compute_bits; + std::shared_ptr > pack_result; + + big_sigma_gadget(protoboard &pb, + const pb_linear_combination_array &W, + const pb_variable &result, + const size_t rot1, + const size_t rot2, + const size_t rot3, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ +template +class choice_gadget : public gadget { +private: + pb_variable_array result_bits; +public: + pb_linear_combination_array X; + pb_linear_combination_array Y; + pb_linear_combination_array Z; + pb_variable result; + std::shared_ptr > pack_result; + + choice_gadget(protoboard &pb, + const pb_linear_combination_array &X, + const pb_linear_combination_array &Y, + const pb_linear_combination_array &Z, + const pb_variable &result, const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ +template +class majority_gadget : public gadget { +private: + pb_variable_array result_bits; + std::shared_ptr > pack_result; +public: + pb_linear_combination_array X; + pb_linear_combination_array Y; + pb_linear_combination_array Z; + pb_variable result; + + majority_gadget(protoboard &pb, + const pb_linear_combination_array &X, + const pb_linear_combination_array &Y, + const pb_linear_combination_array &Z, + const pb_variable &result, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc" + +#endif // SHA256_AUX_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc new file mode 100644 index 0000000..8ab67be --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc @@ -0,0 +1,297 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for auxiliary gadgets for the SHA256 gadget. + + See sha256_aux.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SHA256_AUX_TCC_ +#define SHA256_AUX_TCC_ + +namespace libsnark { + +template +lastbits_gadget::lastbits_gadget(protoboard &pb, + const pb_variable &X, + const size_t X_bits, + const pb_variable &result, + const pb_linear_combination_array &result_bits, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + X(X), + X_bits(X_bits), + result(result), + result_bits(result_bits) +{ + full_bits = result_bits; + for (size_t i = result_bits.size(); i < X_bits; ++i) + { + pb_variable full_bits_overflow; + full_bits_overflow.allocate(pb, FMT(this->annotation_prefix, " full_bits_%zu", i)); + full_bits.emplace_back(full_bits_overflow); + } + + unpack_bits.reset(new packing_gadget(pb, full_bits, X, FMT(this->annotation_prefix, " unpack_bits"))); + pack_result.reset(new packing_gadget(pb, result_bits, result, FMT(this->annotation_prefix, " pack_result"))); +} + +template +void lastbits_gadget::generate_r1cs_constraints() +{ + unpack_bits->generate_r1cs_constraints(true); + pack_result->generate_r1cs_constraints(false); +} + +template +void lastbits_gadget::generate_r1cs_witness() +{ + unpack_bits->generate_r1cs_witness_from_packed(); + pack_result->generate_r1cs_witness_from_bits(); +} + +template +XOR3_gadget::XOR3_gadget(protoboard &pb, + const pb_linear_combination &A, + const pb_linear_combination &B, + const pb_linear_combination &C, + const bool assume_C_is_zero, + const pb_linear_combination &out, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + A(A), + B(B), + C(C), + assume_C_is_zero(assume_C_is_zero), + out(out) +{ + if (!assume_C_is_zero) + { + tmp.allocate(pb, FMT(this->annotation_prefix, " tmp")); + } +} + +template +void XOR3_gadget::generate_r1cs_constraints() +{ + /* + tmp = A + B - 2AB i.e. tmp = A xor B + out = tmp + C - 2tmp C i.e. out = tmp xor C + */ + if (assume_C_is_zero) + { + this->pb.add_r1cs_constraint(r1cs_constraint(2*A, B, A + B - out), FMT(this->annotation_prefix, " implicit_tmp_equals_out")); + } + else + { + this->pb.add_r1cs_constraint(r1cs_constraint(2*A, B, A + B - tmp), FMT(this->annotation_prefix, " tmp")); + this->pb.add_r1cs_constraint(r1cs_constraint(2 * tmp, C, tmp + C - out), FMT(this->annotation_prefix, " out")); + } +} + +template +void XOR3_gadget::generate_r1cs_witness() +{ + if (assume_C_is_zero) + { + this->pb.lc_val(out) = this->pb.lc_val(A) + this->pb.lc_val(B) - FieldT(2) * this->pb.lc_val(A) * this->pb.lc_val(B); + } + else + { + this->pb.val(tmp) = this->pb.lc_val(A) + this->pb.lc_val(B) - FieldT(2) * this->pb.lc_val(A) * this->pb.lc_val(B); + this->pb.lc_val(out) = this->pb.val(tmp) + this->pb.lc_val(C) - FieldT(2) * this->pb.val(tmp) * this->pb.lc_val(C); + } +} + +#define SHA256_GADGET_ROTR(A, i, k) A[((i)+(k)) % 32] + +/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ +template +small_sigma_gadget::small_sigma_gadget(protoboard &pb, + const pb_variable_array &W, + const pb_variable &result, + const size_t rot1, + const size_t rot2, + const size_t shift, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + W(W), + result(result) +{ + result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits")); + compute_bits.resize(32); + for (size_t i = 0; i < 32; ++i) + { + compute_bits[i].reset(new XOR3_gadget(pb, SHA256_GADGET_ROTR(W, i, rot1), SHA256_GADGET_ROTR(W, i, rot2), + (i + shift < 32 ? W[i+shift] : ONE), + (i + shift >= 32), result_bits[i], + FMT(this->annotation_prefix, " compute_bits_%zu", i))); + } + pack_result.reset(new packing_gadget(pb, result_bits, result, FMT(this->annotation_prefix, " pack_result"))); +} + +template +void small_sigma_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < 32; ++i) + { + compute_bits[i]->generate_r1cs_constraints(); + } + + pack_result->generate_r1cs_constraints(false); +} + +template +void small_sigma_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < 32; ++i) + { + compute_bits[i]->generate_r1cs_witness(); + } + + pack_result->generate_r1cs_witness_from_bits(); +} + +template +big_sigma_gadget::big_sigma_gadget(protoboard &pb, + const pb_linear_combination_array &W, + const pb_variable &result, + const size_t rot1, + const size_t rot2, + const size_t rot3, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + W(W), + result(result) +{ + result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits")); + compute_bits.resize(32); + for (size_t i = 0; i < 32; ++i) + { + compute_bits[i].reset(new XOR3_gadget(pb, SHA256_GADGET_ROTR(W, i, rot1), SHA256_GADGET_ROTR(W, i, rot2), SHA256_GADGET_ROTR(W, i, rot3), false, result_bits[i], + FMT(this->annotation_prefix, " compute_bits_%zu", i))); + } + + pack_result.reset(new packing_gadget(pb, result_bits, result, FMT(this->annotation_prefix, " pack_result"))); +} + +template +void big_sigma_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < 32; ++i) + { + compute_bits[i]->generate_r1cs_constraints(); + } + + pack_result->generate_r1cs_constraints(false); +} + +template +void big_sigma_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < 32; ++i) + { + compute_bits[i]->generate_r1cs_witness(); + } + + pack_result->generate_r1cs_witness_from_bits(); +} + +/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ +template +choice_gadget::choice_gadget(protoboard &pb, + const pb_linear_combination_array &X, + const pb_linear_combination_array &Y, + const pb_linear_combination_array &Z, + const pb_variable &result, const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + X(X), + Y(Y), + Z(Z), + result(result) +{ + result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits")); + pack_result.reset(new packing_gadget(pb, result_bits, result, FMT(this->annotation_prefix, " result"))); +} + +template +void choice_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < 32; ++i) + { + /* + result = x * y + (1-x) * z + result - z = x * (y - z) + */ + this->pb.add_r1cs_constraint(r1cs_constraint(X[i], Y[i] - Z[i], result_bits[i] - Z[i]), FMT(this->annotation_prefix, " result_bits_%zu", i)); + } + pack_result->generate_r1cs_constraints(false); +} + +template +void choice_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < 32; ++i) + { + this->pb.val(result_bits[i]) = this->pb.lc_val(X[i]) * this->pb.lc_val(Y[i]) + (FieldT::one() - this->pb.lc_val(X[i])) * this->pb.lc_val(Z[i]); + } + pack_result->generate_r1cs_witness_from_bits(); +} + +/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ +template +majority_gadget::majority_gadget(protoboard &pb, + const pb_linear_combination_array &X, + const pb_linear_combination_array &Y, + const pb_linear_combination_array &Z, + const pb_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + X(X), + Y(Y), + Z(Z), + result(result) +{ + result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits")); + pack_result.reset(new packing_gadget(pb, result_bits, result, FMT(this->annotation_prefix, " result"))); +} + +template +void majority_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < 32; ++i) + { + /* + 2*result + aux = x + y + z + x, y, z, aux -- bits + aux = x + y + z - 2*result + */ + generate_boolean_r1cs_constraint(this->pb, result_bits[i], FMT(this->annotation_prefix, " result_%zu", i)); + this->pb.add_r1cs_constraint(r1cs_constraint(X[i] + Y[i] + Z[i] - 2 * result_bits[i], + 1 - (X[i] + Y[i] + Z[i] - 2 * result_bits[i]), + 0), + FMT(this->annotation_prefix, " result_bits_%zu", i)); + } + pack_result->generate_r1cs_constraints(false); +} + +template +void majority_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < 32; ++i) + { + const long v = (this->pb.lc_val(X[i]) + this->pb.lc_val(Y[i]) + this->pb.lc_val(Z[i])).as_ulong(); + this->pb.val(result_bits[i]) = FieldT(v / 2); + } + + pack_result->generate_r1cs_witness_from_bits(); +} + +} // libsnark + +#endif // SHA256_AUX_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp new file mode 100644 index 0000000..c2f31e3 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp @@ -0,0 +1,108 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for gadgets for the SHA256 message schedule and round function. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SHA256_COMPONENTS_HPP_ +#define SHA256_COMPONENTS_HPP_ + +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" +#include "gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp" + +namespace libsnark { + +const size_t SHA256_digest_size = 256; +const size_t SHA256_block_size = 512; + +template +pb_linear_combination_array SHA256_default_IV(protoboard &pb); + +template +class sha256_message_schedule_gadget : public gadget { +public: + std::vector > W_bits; + std::vector > > pack_W; + + std::vector > sigma0; + std::vector > sigma1; + std::vector > > compute_sigma0; + std::vector > > compute_sigma1; + std::vector > unreduced_W; + std::vector > > mod_reduce_W; +public: + pb_variable_array M; + pb_variable_array packed_W; + sha256_message_schedule_gadget(protoboard &pb, + const pb_variable_array &M, + const pb_variable_array &packed_W, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +class sha256_round_function_gadget : public gadget { +public: + pb_variable sigma0; + pb_variable sigma1; + std::shared_ptr > compute_sigma0; + std::shared_ptr > compute_sigma1; + pb_variable choice; + pb_variable majority; + std::shared_ptr > compute_choice; + std::shared_ptr > compute_majority; + pb_variable packed_d; + std::shared_ptr > pack_d; + pb_variable packed_h; + std::shared_ptr > pack_h; + pb_variable unreduced_new_a; + pb_variable unreduced_new_e; + std::shared_ptr > mod_reduce_new_a; + std::shared_ptr > mod_reduce_new_e; + pb_variable packed_new_a; + pb_variable packed_new_e; +public: + pb_linear_combination_array a; + pb_linear_combination_array b; + pb_linear_combination_array c; + pb_linear_combination_array d; + pb_linear_combination_array e; + pb_linear_combination_array f; + pb_linear_combination_array g; + pb_linear_combination_array h; + pb_variable W; + long K; + pb_linear_combination_array new_a; + pb_linear_combination_array new_e; + + sha256_round_function_gadget(protoboard &pb, + const pb_linear_combination_array &a, + const pb_linear_combination_array &b, + const pb_linear_combination_array &c, + const pb_linear_combination_array &d, + const pb_linear_combination_array &e, + const pb_linear_combination_array &f, + const pb_linear_combination_array &g, + const pb_linear_combination_array &h, + const pb_variable &W, + const long &K, + const pb_linear_combination_array &new_a, + const pb_linear_combination_array &new_e, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc" + +#endif // SHA256_COMPONENTS_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc new file mode 100644 index 0000000..e8f233a --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc @@ -0,0 +1,250 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for gadgets for the SHA256 message schedule and round function. + + See sha256_components.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SHA256_COMPONENTS_TCC_ +#define SHA256_COMPONENTS_TCC_ + +namespace libsnark { + +const unsigned long SHA256_K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +const unsigned long SHA256_H[8] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 +}; + +template +pb_linear_combination_array SHA256_default_IV(protoboard &pb) +{ + pb_linear_combination_array result; + result.reserve(SHA256_digest_size); + + for (size_t i = 0; i < SHA256_digest_size; ++i) + { + int iv_val = (SHA256_H[i / 32] >> (31-(i % 32))) & 1; + + pb_linear_combination iv_element; + iv_element.assign(pb, iv_val * ONE); + iv_element.evaluate(pb); + + result.emplace_back(iv_element); + } + + return result; +} + +template +sha256_message_schedule_gadget::sha256_message_schedule_gadget(protoboard &pb, + const pb_variable_array &M, + const pb_variable_array &packed_W, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + M(M), + packed_W(packed_W) +{ + W_bits.resize(64); + + pack_W.resize(16); + for (size_t i = 0; i < 16; ++i) + { + W_bits[i] = pb_variable_array(M.rbegin() + (15-i) * 32, M.rbegin() + (16-i) * 32); + pack_W[i].reset(new packing_gadget(pb, W_bits[i], packed_W[i], FMT(this->annotation_prefix, " pack_W_%zu", i))); + } + + /* NB: some of those will be un-allocated */ + sigma0.resize(64); + sigma1.resize(64); + compute_sigma0.resize(64); + compute_sigma1.resize(64); + unreduced_W.resize(64); + mod_reduce_W.resize(64); + + for (size_t i = 16; i < 64; ++i) + { + /* allocate result variables for sigma0/sigma1 invocations */ + sigma0[i].allocate(pb, FMT(this->annotation_prefix, " sigma0_%zu", i)); + sigma1[i].allocate(pb, FMT(this->annotation_prefix, " sigma1_%zu", i)); + + /* compute sigma0/sigma1 */ + compute_sigma0[i].reset(new small_sigma_gadget(pb, W_bits[i-15], sigma0[i], 7, 18, 3, FMT(this->annotation_prefix, " compute_sigma0_%zu", i))); + compute_sigma1[i].reset(new small_sigma_gadget(pb, W_bits[i-2], sigma1[i], 17, 19, 10, FMT(this->annotation_prefix, " compute_sigma1_%zu", i))); + + /* unreduced_W = sigma0(W_{i-15}) + sigma1(W_{i-2}) + W_{i-7} + W_{i-16} before modulo 2^32 */ + unreduced_W[i].allocate(pb, FMT(this->annotation_prefix, "unreduced_W_%zu", i)); + + /* allocate the bit representation of packed_W[i] */ + W_bits[i].allocate(pb, 32, FMT(this->annotation_prefix, " W_bits_%zu", i)); + + /* and finally reduce this into packed and bit representations */ + mod_reduce_W[i].reset(new lastbits_gadget(pb, unreduced_W[i], 32+2, packed_W[i], W_bits[i], FMT(this->annotation_prefix, " mod_reduce_W_%zu", i))); + } +} + +template +void sha256_message_schedule_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < 16; ++i) + { + pack_W[i]->generate_r1cs_constraints(false); // do not enforce bitness here; caller be aware. + } + + for (size_t i = 16; i < 64; ++i) + { + compute_sigma0[i]->generate_r1cs_constraints(); + compute_sigma1[i]->generate_r1cs_constraints(); + + this->pb.add_r1cs_constraint(r1cs_constraint(1, + sigma0[i] + sigma1[i] + packed_W[i-16] + packed_W[i-7], + unreduced_W[i]), + FMT(this->annotation_prefix, " unreduced_W_%zu", i)); + + mod_reduce_W[i]->generate_r1cs_constraints(); + } +} + +template +void sha256_message_schedule_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < 16; ++i) + { + pack_W[i]->generate_r1cs_witness_from_bits(); + } + + for (size_t i = 16; i < 64; ++i) + { + compute_sigma0[i]->generate_r1cs_witness(); + compute_sigma1[i]->generate_r1cs_witness(); + + this->pb.val(unreduced_W[i]) = this->pb.val(sigma0[i]) + this->pb.val(sigma1[i]) + this->pb.val(packed_W[i-16]) + this->pb.val(packed_W[i-7]); + mod_reduce_W[i]->generate_r1cs_witness(); + } +} + +template +sha256_round_function_gadget::sha256_round_function_gadget(protoboard &pb, + const pb_linear_combination_array &a, + const pb_linear_combination_array &b, + const pb_linear_combination_array &c, + const pb_linear_combination_array &d, + const pb_linear_combination_array &e, + const pb_linear_combination_array &f, + const pb_linear_combination_array &g, + const pb_linear_combination_array &h, + const pb_variable &W, + const long &K, + const pb_linear_combination_array &new_a, + const pb_linear_combination_array &new_e, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + a(a), + b(b), + c(c), + d(d), + e(e), + f(f), + g(g), + h(h), + W(W), + K(K), + new_a(new_a), + new_e(new_e) +{ + /* compute sigma0 and sigma1 */ + sigma0.allocate(pb, FMT(this->annotation_prefix, " sigma0")); + sigma1.allocate(pb, FMT(this->annotation_prefix, " sigma1")); + compute_sigma0.reset(new big_sigma_gadget(pb, a, sigma0, 2, 13, 22, FMT(this->annotation_prefix, " compute_sigma0"))); + compute_sigma1.reset(new big_sigma_gadget(pb, e, sigma1, 6, 11, 25, FMT(this->annotation_prefix, " compute_sigma1"))); + + /* compute choice */ + choice.allocate(pb, FMT(this->annotation_prefix, " choice")); + compute_choice.reset(new choice_gadget(pb, e, f, g, choice, FMT(this->annotation_prefix, " compute_choice"))); + + /* compute majority */ + majority.allocate(pb, FMT(this->annotation_prefix, " majority")); + compute_majority.reset(new majority_gadget(pb, a, b, c, majority, FMT(this->annotation_prefix, " compute_majority"))); + + /* pack d */ + packed_d.allocate(pb, FMT(this->annotation_prefix, " packed_d")); + pack_d.reset(new packing_gadget(pb, d, packed_d, FMT(this->annotation_prefix, " pack_d"))); + + /* pack h */ + packed_h.allocate(pb, FMT(this->annotation_prefix, " packed_h")); + pack_h.reset(new packing_gadget(pb, h, packed_h, FMT(this->annotation_prefix, " pack_h"))); + + /* compute the actual results for the round */ + unreduced_new_a.allocate(pb, FMT(this->annotation_prefix, " unreduced_new_a")); + unreduced_new_e.allocate(pb, FMT(this->annotation_prefix, " unreduced_new_e")); + + packed_new_a.allocate(pb, FMT(this->annotation_prefix, " packed_new_a")); + packed_new_e.allocate(pb, FMT(this->annotation_prefix, " packed_new_e")); + + mod_reduce_new_a.reset(new lastbits_gadget(pb, unreduced_new_a, 32+3, packed_new_a, new_a, FMT(this->annotation_prefix, " mod_reduce_new_a"))); + mod_reduce_new_e.reset(new lastbits_gadget(pb, unreduced_new_e, 32+3, packed_new_e, new_e, FMT(this->annotation_prefix, " mod_reduce_new_e"))); +} + +template +void sha256_round_function_gadget::generate_r1cs_constraints() +{ + compute_sigma0->generate_r1cs_constraints(); + compute_sigma1->generate_r1cs_constraints(); + + compute_choice->generate_r1cs_constraints(); + compute_majority->generate_r1cs_constraints(); + + pack_d->generate_r1cs_constraints(false); + pack_h->generate_r1cs_constraints(false); + + this->pb.add_r1cs_constraint(r1cs_constraint(1, + packed_h + sigma1 + choice + K + W + sigma0 + majority, + unreduced_new_a), + FMT(this->annotation_prefix, " unreduced_new_a")); + + this->pb.add_r1cs_constraint(r1cs_constraint(1, + packed_d + packed_h + sigma1 + choice + K + W, + unreduced_new_e), + FMT(this->annotation_prefix, " unreduced_new_e")); + + mod_reduce_new_a->generate_r1cs_constraints(); + mod_reduce_new_e->generate_r1cs_constraints(); +} + +template +void sha256_round_function_gadget::generate_r1cs_witness() +{ + compute_sigma0->generate_r1cs_witness(); + compute_sigma1->generate_r1cs_witness(); + + compute_choice->generate_r1cs_witness(); + compute_majority->generate_r1cs_witness(); + + pack_d->generate_r1cs_witness_from_bits(); + pack_h->generate_r1cs_witness_from_bits(); + + this->pb.val(unreduced_new_a) = this->pb.val(packed_h) + this->pb.val(sigma1) + this->pb.val(choice) + FieldT(K) + this->pb.val(W) + this->pb.val(sigma0) + this->pb.val(majority); + this->pb.val(unreduced_new_e) = this->pb.val(packed_d) + this->pb.val(packed_h) + this->pb.val(sigma1) + this->pb.val(choice) + FieldT(K) + this->pb.val(W); + + mod_reduce_new_a->generate_r1cs_witness(); + mod_reduce_new_e->generate_r1cs_witness(); +} + +} // libsnark + +#endif // SHA256_COMPONENTS_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp new file mode 100644 index 0000000..8cb6365 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp @@ -0,0 +1,98 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for top-level SHA256 gadgets. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SHA256_GADGET_HPP_ +#define SHA256_GADGET_HPP_ + +#include "common/data_structures/merkle_tree.hpp" +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" +#include "gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp" + +namespace libsnark { + +/** + * Gadget for the SHA256 compression function. + */ +template +class sha256_compression_function_gadget : public gadget { +public: + std::vector > round_a; + std::vector > round_b; + std::vector > round_c; + std::vector > round_d; + std::vector > round_e; + std::vector > round_f; + std::vector > round_g; + std::vector > round_h; + + pb_variable_array packed_W; + std::shared_ptr > message_schedule; + std::vector > round_functions; + + pb_variable_array unreduced_output; + pb_variable_array reduced_output; + std::vector > reduce_output; +public: + pb_linear_combination_array prev_output; + pb_variable_array new_block; + digest_variable output; + + sha256_compression_function_gadget(protoboard &pb, + const pb_linear_combination_array &prev_output, + const pb_variable_array &new_block, + const digest_variable &output, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget for the SHA256 compression function, viewed as a 2-to-1 hash + * function, and using the same initialization vector as in SHA256 + * specification. Thus, any collision for + * sha256_two_to_one_hash_gadget trivially extends to a collision for + * full SHA256 (by appending the same padding). + */ +template +class sha256_two_to_one_hash_gadget : public gadget { +public: + typedef bit_vector hash_value_type; + typedef merkle_authentication_path merkle_authentication_path_type; + + std::shared_ptr > f; + + sha256_two_to_one_hash_gadget(protoboard &pb, + const digest_variable &left, + const digest_variable &right, + const digest_variable &output, + const std::string &annotation_prefix); + sha256_two_to_one_hash_gadget(protoboard &pb, + const size_t block_length, + const block_variable &input_block, + const digest_variable &output, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(const bool ensure_output_bitness=true); // TODO: ignored for now + void generate_r1cs_witness(); + + static size_t get_block_len(); + static size_t get_digest_len(); + static bit_vector get_hash(const bit_vector &input); + + static size_t expected_constraints(const bool ensure_output_bitness=true); // TODO: ignored for now +}; + +} // libsnark + +#include "gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc" + +#endif // SHA256_GADGET_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc new file mode 100644 index 0000000..fc7ac98 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc @@ -0,0 +1,230 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for top-level SHA256 gadgets. + + See sha256_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SHA256_GADGET_TCC_ +#define SHA256_GADGET_TCC_ + +namespace libsnark { + +template +sha256_compression_function_gadget::sha256_compression_function_gadget(protoboard &pb, + const pb_linear_combination_array &prev_output, + const pb_variable_array &new_block, + const digest_variable &output, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + prev_output(prev_output), + new_block(new_block), + output(output) +{ + /* message schedule and inputs for it */ + packed_W.allocate(pb, 64, FMT(this->annotation_prefix, " packed_W")); + message_schedule.reset(new sha256_message_schedule_gadget(pb, new_block, packed_W, FMT(this->annotation_prefix, " message_schedule"))); + + /* initalize */ + round_a.push_back(pb_linear_combination_array(prev_output.rbegin() + 7*32, prev_output.rbegin() + 8*32)); + round_b.push_back(pb_linear_combination_array(prev_output.rbegin() + 6*32, prev_output.rbegin() + 7*32)); + round_c.push_back(pb_linear_combination_array(prev_output.rbegin() + 5*32, prev_output.rbegin() + 6*32)); + round_d.push_back(pb_linear_combination_array(prev_output.rbegin() + 4*32, prev_output.rbegin() + 5*32)); + round_e.push_back(pb_linear_combination_array(prev_output.rbegin() + 3*32, prev_output.rbegin() + 4*32)); + round_f.push_back(pb_linear_combination_array(prev_output.rbegin() + 2*32, prev_output.rbegin() + 3*32)); + round_g.push_back(pb_linear_combination_array(prev_output.rbegin() + 1*32, prev_output.rbegin() + 2*32)); + round_h.push_back(pb_linear_combination_array(prev_output.rbegin() + 0*32, prev_output.rbegin() + 1*32)); + + /* do the rounds */ + for (size_t i = 0; i < 64; ++i) + { + round_h.push_back(round_g[i]); + round_g.push_back(round_f[i]); + round_f.push_back(round_e[i]); + round_d.push_back(round_c[i]); + round_c.push_back(round_b[i]); + round_b.push_back(round_a[i]); + + pb_variable_array new_round_a_variables; + new_round_a_variables.allocate(pb, 32, FMT(this->annotation_prefix, " new_round_a_variables_%zu", i+1)); + round_a.emplace_back(new_round_a_variables); + + pb_variable_array new_round_e_variables; + new_round_e_variables.allocate(pb, 32, FMT(this->annotation_prefix, " new_round_e_variables_%zu", i+1)); + round_e.emplace_back(new_round_e_variables); + + round_functions.push_back(sha256_round_function_gadget(pb, + round_a[i], round_b[i], round_c[i], round_d[i], + round_e[i], round_f[i], round_g[i], round_h[i], + packed_W[i], SHA256_K[i], round_a[i+1], round_e[i+1], + FMT(this->annotation_prefix, " round_functions_%zu", i))); + } + + /* finalize */ + unreduced_output.allocate(pb, 8, FMT(this->annotation_prefix, " unreduced_output")); + reduced_output.allocate(pb, 8, FMT(this->annotation_prefix, " reduced_output")); + for (size_t i = 0; i < 8; ++i) + { + reduce_output.push_back(lastbits_gadget(pb, + unreduced_output[i], + 32+1, + reduced_output[i], + pb_variable_array(output.bits.rbegin() + (7-i) * 32, output.bits.rbegin() + (8-i) * 32), + FMT(this->annotation_prefix, " reduce_output_%zu", i))); + } +} + +template +void sha256_compression_function_gadget::generate_r1cs_constraints() +{ + message_schedule->generate_r1cs_constraints(); + for (size_t i = 0; i < 64; ++i) + { + round_functions[i].generate_r1cs_constraints(); + } + + for (size_t i = 0; i < 4; ++i) + { + this->pb.add_r1cs_constraint(r1cs_constraint(1, + round_functions[3-i].packed_d + round_functions[63-i].packed_new_a, + unreduced_output[i]), + FMT(this->annotation_prefix, " unreduced_output_%zu", i)); + + this->pb.add_r1cs_constraint(r1cs_constraint(1, + round_functions[3-i].packed_h + round_functions[63-i].packed_new_e, + unreduced_output[4+i]), + FMT(this->annotation_prefix, " unreduced_output_%zu", 4+i)); + } + + for (size_t i = 0; i < 8; ++i) + { + reduce_output[i].generate_r1cs_constraints(); + } +} + +template +void sha256_compression_function_gadget::generate_r1cs_witness() +{ + message_schedule->generate_r1cs_witness(); + +#ifdef DEBUG + printf("Input:\n"); + for (size_t j = 0; j < 16; ++j) + { + printf("%lx ", this->pb.val(packed_W[j]).as_ulong()); + } + printf("\n"); +#endif + + for (size_t i = 0; i < 64; ++i) + { + round_functions[i].generate_r1cs_witness(); + } + + for (size_t i = 0; i < 4; ++i) + { + this->pb.val(unreduced_output[i]) = this->pb.val(round_functions[3-i].packed_d) + this->pb.val(round_functions[63-i].packed_new_a); + this->pb.val(unreduced_output[4+i]) = this->pb.val(round_functions[3-i].packed_h) + this->pb.val(round_functions[63-i].packed_new_e); + } + + for (size_t i = 0; i < 8; ++i) + { + reduce_output[i].generate_r1cs_witness(); + } + +#ifdef DEBUG + printf("Output:\n"); + for (size_t j = 0; j < 8; ++j) + { + printf("%lx ", this->pb.val(reduced_output[j]).as_ulong()); + } + printf("\n"); +#endif +} + +template +sha256_two_to_one_hash_gadget::sha256_two_to_one_hash_gadget(protoboard &pb, + const digest_variable &left, + const digest_variable &right, + const digest_variable &output, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + /* concatenate block = left || right */ + pb_variable_array block; + block.insert(block.end(), left.bits.begin(), left.bits.end()); + block.insert(block.end(), right.bits.begin(), right.bits.end()); + + /* compute the hash itself */ + f.reset(new sha256_compression_function_gadget(pb, SHA256_default_IV(pb), block, output, FMT(this->annotation_prefix, " f"))); +} + +template +sha256_two_to_one_hash_gadget::sha256_two_to_one_hash_gadget(protoboard &pb, + const size_t block_length, + const block_variable &input_block, + const digest_variable &output, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + assert(block_length == SHA256_block_size); + assert(input_block.bits.size() == block_length); + f.reset(new sha256_compression_function_gadget(pb, SHA256_default_IV(pb), input_block.bits, output, FMT(this->annotation_prefix, " f"))); +} + +template +void sha256_two_to_one_hash_gadget::generate_r1cs_constraints(const bool ensure_output_bitness) +{ + UNUSED(ensure_output_bitness); + f->generate_r1cs_constraints(); +} + +template +void sha256_two_to_one_hash_gadget::generate_r1cs_witness() +{ + f->generate_r1cs_witness(); +} + +template +size_t sha256_two_to_one_hash_gadget::get_block_len() +{ + return SHA256_block_size; +} + +template +size_t sha256_two_to_one_hash_gadget::get_digest_len() +{ + return SHA256_digest_size; +} + +template +bit_vector sha256_two_to_one_hash_gadget::get_hash(const bit_vector &input) +{ + protoboard pb; + + block_variable input_variable(pb, SHA256_block_size, "input"); + digest_variable output_variable(pb, SHA256_digest_size, "output"); + sha256_two_to_one_hash_gadget f(pb, SHA256_block_size, input_variable, output_variable, "f"); + + input_variable.generate_r1cs_witness(input); + f.generate_r1cs_witness(); + + return output_variable.get_digest(); +} + +template +size_t sha256_two_to_one_hash_gadget::expected_constraints(const bool ensure_output_bitness) +{ + UNUSED(ensure_output_bitness); + return 27280; /* hardcoded for now */ +} + +} // libsnark + +#endif // SHA256_GADGET_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/tests/generate_sha256_gadget_tests.py b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/tests/generate_sha256_gadget_tests.py new file mode 100644 index 0000000..452317f --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/tests/generate_sha256_gadget_tests.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +## +# @author This file is part of libsnark, developed by SCIPR Lab +# and contributors (see AUTHORS). +# @copyright MIT license (see LICENSE file) + +import random +import pypy_sha256 # PyPy's implementation of SHA256 compression function; see copyright and authorship notice within. + +BLOCK_LEN = 512 +BLOCK_BYTES = BLOCK_LEN // 8 +HASH_LEN = 256 +HASH_BYTES = HASH_LEN // 8 + +def gen_random_bytes(n): + return [random.randint(0, 255) for i in xrange(n)] + +def words_to_bytes(arr): + return sum(([x >> 24, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff] for x in arr), []) + +def bytes_to_words(arr): + l = len(arr) + assert l % 4 == 0 + return [(arr[i*4 + 3] << 24) + (arr[i*4+2] << 16) + (arr[i*4+1] << 8) + arr[i*4] for i in xrange(l//4)] + +def cpp_val(s, log_radix=32): + if log_radix == 8: + hexfmt = '0x%02x' + elif log_radix == 32: + hexfmt = '0x%08x' + s = bytes_to_words(s) + else: + raise + return 'int_list_to_bits({%s}, %d)' % (', '.join(hexfmt % x for x in s), log_radix) + +def H_bytes(x): + assert len(x) == BLOCK_BYTES + state = pypy_sha256.sha_init() + state['data'] = words_to_bytes(bytes_to_words(x)) + pypy_sha256.sha_transform(state) + return words_to_bytes(bytes_to_words(words_to_bytes(state['digest']))) + +def generate_sha256_gadget_tests(): + left = gen_random_bytes(HASH_BYTES) + right = gen_random_bytes(HASH_BYTES) + hash = H_bytes(left + right) + + print "const bit_vector left_bv = %s;" % cpp_val(left) + print "const bit_vector right_bv = %s;" % cpp_val(right) + print "const bit_vector hash_bv = %s;" % cpp_val(hash) + +if __name__ == '__main__': + random.seed(0) # for reproducibility + generate_sha256_gadget_tests() + diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/tests/pypy_sha256.py b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/tests/pypy_sha256.py new file mode 100644 index 0000000..496989c --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/tests/pypy_sha256.py @@ -0,0 +1,263 @@ +#!/usr/bin/env python +# +# SHA256 compression function implementation below is a verbatim copy of PyPy's implementation from +# https://bitbucket.org/pypy/pypy/raw/f1f064b3faf1e012f7a9a9ab08f18074637ebe8a/lib_pypy/_sha256.py . +# +# It is licensed under the MIT license and copyright PyPy Copyright holders 2003-2015 +# See https://bitbucket.org/pypy/pypy/src/tip/LICENSE for the full copyright notice. +# + +SHA_BLOCKSIZE = 64 +SHA_DIGESTSIZE = 32 + + +def new_shaobject(): + return { + 'digest': [0]*8, + 'count_lo': 0, + 'count_hi': 0, + 'data': [0]* SHA_BLOCKSIZE, + 'local': 0, + 'digestsize': 0 + } + +ROR = lambda x, y: (((x & 0xffffffff) >> (y & 31)) | (x << (32 - (y & 31)))) & 0xffffffff +Ch = lambda x, y, z: (z ^ (x & (y ^ z))) +Maj = lambda x, y, z: (((x | y) & z) | (x & y)) +S = lambda x, n: ROR(x, n) +R = lambda x, n: (x & 0xffffffff) >> n +Sigma0 = lambda x: (S(x, 2) ^ S(x, 13) ^ S(x, 22)) +Sigma1 = lambda x: (S(x, 6) ^ S(x, 11) ^ S(x, 25)) +Gamma0 = lambda x: (S(x, 7) ^ S(x, 18) ^ R(x, 3)) +Gamma1 = lambda x: (S(x, 17) ^ S(x, 19) ^ R(x, 10)) + +def sha_transform(sha_info): + W = [] + + d = sha_info['data'] + for i in range(0,16): + W.append( (d[4*i]<<24) + (d[4*i+1]<<16) + (d[4*i+2]<<8) + d[4*i+3]) + + for i in range(16,64): + W.append( (Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]) & 0xffffffff ) + + ss = sha_info['digest'][:] + + def RND(a,b,c,d,e,f,g,h,i,ki): + t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; + t1 = Sigma0(a) + Maj(a, b, c); + d += t0; + h = t0 + t1; + return d & 0xffffffff, h & 0xffffffff + + ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],0,0x428a2f98); + ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],1,0x71374491); + ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],2,0xb5c0fbcf); + ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],3,0xe9b5dba5); + ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],4,0x3956c25b); + ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],5,0x59f111f1); + ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],6,0x923f82a4); + ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],7,0xab1c5ed5); + ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],8,0xd807aa98); + ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],9,0x12835b01); + ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],10,0x243185be); + ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],11,0x550c7dc3); + ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],12,0x72be5d74); + ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],13,0x80deb1fe); + ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],14,0x9bdc06a7); + ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],15,0xc19bf174); + ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],16,0xe49b69c1); + ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],17,0xefbe4786); + ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],18,0x0fc19dc6); + ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],19,0x240ca1cc); + ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],20,0x2de92c6f); + ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],21,0x4a7484aa); + ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],22,0x5cb0a9dc); + ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],23,0x76f988da); + ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],24,0x983e5152); + ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],25,0xa831c66d); + ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],26,0xb00327c8); + ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],27,0xbf597fc7); + ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],28,0xc6e00bf3); + ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],29,0xd5a79147); + ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],30,0x06ca6351); + ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],31,0x14292967); + ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],32,0x27b70a85); + ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],33,0x2e1b2138); + ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],34,0x4d2c6dfc); + ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],35,0x53380d13); + ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],36,0x650a7354); + ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],37,0x766a0abb); + ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],38,0x81c2c92e); + ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],39,0x92722c85); + ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],40,0xa2bfe8a1); + ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],41,0xa81a664b); + ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],42,0xc24b8b70); + ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],43,0xc76c51a3); + ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],44,0xd192e819); + ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],45,0xd6990624); + ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],46,0xf40e3585); + ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],47,0x106aa070); + ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],48,0x19a4c116); + ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],49,0x1e376c08); + ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],50,0x2748774c); + ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],51,0x34b0bcb5); + ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],52,0x391c0cb3); + ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],53,0x4ed8aa4a); + ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],54,0x5b9cca4f); + ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],55,0x682e6ff3); + ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],56,0x748f82ee); + ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],57,0x78a5636f); + ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],58,0x84c87814); + ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],59,0x8cc70208); + ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],60,0x90befffa); + ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],61,0xa4506ceb); + ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],62,0xbef9a3f7); + ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],63,0xc67178f2); + + dig = [] + for i, x in enumerate(sha_info['digest']): + dig.append( (x + ss[i]) & 0xffffffff ) + sha_info['digest'] = dig + +def sha_init(): + sha_info = new_shaobject() + sha_info['digest'] = [0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19] + sha_info['count_lo'] = 0 + sha_info['count_hi'] = 0 + sha_info['local'] = 0 + sha_info['digestsize'] = 32 + return sha_info + +def sha224_init(): + sha_info = new_shaobject() + sha_info['digest'] = [0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4] + sha_info['count_lo'] = 0 + sha_info['count_hi'] = 0 + sha_info['local'] = 0 + sha_info['digestsize'] = 28 + return sha_info + +def sha_update(sha_info, buffer): + if isinstance(buffer, str): + raise TypeError("Unicode strings must be encoded before hashing") + count = len(buffer) + buffer_idx = 0 + clo = (sha_info['count_lo'] + (count << 3)) & 0xffffffff + if clo < sha_info['count_lo']: + sha_info['count_hi'] += 1 + sha_info['count_lo'] = clo + + sha_info['count_hi'] += (count >> 29) + + if sha_info['local']: + i = SHA_BLOCKSIZE - sha_info['local'] + if i > count: + i = count + + # copy buffer + sha_info['data'][sha_info['local']:sha_info['local']+i] = buffer[buffer_idx:buffer_idx+i] + + count -= i + buffer_idx += i + + sha_info['local'] += i + if sha_info['local'] == SHA_BLOCKSIZE: + sha_transform(sha_info) + sha_info['local'] = 0 + else: + return + + while count >= SHA_BLOCKSIZE: + # copy buffer + sha_info['data'] = list(buffer[buffer_idx:buffer_idx + SHA_BLOCKSIZE]) + count -= SHA_BLOCKSIZE + buffer_idx += SHA_BLOCKSIZE + sha_transform(sha_info) + + + # copy buffer + pos = sha_info['local'] + sha_info['data'][pos:pos+count] = buffer[buffer_idx:buffer_idx + count] + sha_info['local'] = count + +def sha_final(sha_info): + lo_bit_count = sha_info['count_lo'] + hi_bit_count = sha_info['count_hi'] + count = (lo_bit_count >> 3) & 0x3f + sha_info['data'][count] = 0x80; + count += 1 + if count > SHA_BLOCKSIZE - 8: + # zero the bytes in data after the count + sha_info['data'] = sha_info['data'][:count] + ([0] * (SHA_BLOCKSIZE - count)) + sha_transform(sha_info) + # zero bytes in data + sha_info['data'] = [0] * SHA_BLOCKSIZE + else: + sha_info['data'] = sha_info['data'][:count] + ([0] * (SHA_BLOCKSIZE - count)) + + sha_info['data'][56] = (hi_bit_count >> 24) & 0xff + sha_info['data'][57] = (hi_bit_count >> 16) & 0xff + sha_info['data'][58] = (hi_bit_count >> 8) & 0xff + sha_info['data'][59] = (hi_bit_count >> 0) & 0xff + sha_info['data'][60] = (lo_bit_count >> 24) & 0xff + sha_info['data'][61] = (lo_bit_count >> 16) & 0xff + sha_info['data'][62] = (lo_bit_count >> 8) & 0xff + sha_info['data'][63] = (lo_bit_count >> 0) & 0xff + + sha_transform(sha_info) + + dig = [] + for i in sha_info['digest']: + dig.extend([ ((i>>24) & 0xff), ((i>>16) & 0xff), ((i>>8) & 0xff), (i & 0xff) ]) + return ''.join([chr(i) for i in dig]) + +class sha256(object): + digest_size = digestsize = SHA_DIGESTSIZE + block_size = SHA_BLOCKSIZE + + def __init__(self, s=None): + self._sha = sha_init() + if s: + sha_update(self._sha, s) + + def update(self, s): + sha_update(self._sha, s) + + def digest(self): + return sha_final(self._sha.copy())[:self._sha['digestsize']] + + def hexdigest(self): + return ''.join(['%.2x' % ord(i) for i in self.digest()]) + + def copy(self): + new = sha256.__new__(sha256) + new._sha = self._sha.copy() + return new + +class sha224(sha256): + digest_size = digestsize = 28 + + def __init__(self, s=None): + self._sha = sha224_init() + if s: + sha_update(self._sha, s) + + def copy(self): + new = sha224.__new__(sha224) + new._sha = self._sha.copy() + return new + +def test(): + a_str = "just a test string" + + assert 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' == sha256().hexdigest() + assert 'd7b553c6f09ac85d142415f857c5310f3bbbe7cdd787cce4b985acedd585266f' == sha256(a_str).hexdigest() + assert '8113ebf33c97daa9998762aacafe750c7cefc2b2f173c90c59663a57fe626f21' == sha256(a_str*7).hexdigest() + + s = sha256(a_str) + s.update(a_str) + assert '03d9963e05a094593190b6fc794cb1a3e1ac7d7883f0b5855268afeccc70d461' == s.hexdigest() + +if __name__ == "__main__": + test() diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp new file mode 100644 index 0000000..471928f --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp @@ -0,0 +1,46 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "common/default_types/ec_pp.hpp" +#include "common/utils.hpp" +#include "common/profiling.hpp" +#include "gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp" + +using namespace libsnark; + +template +void test_two_to_one() +{ + protoboard pb; + + digest_variable left(pb, SHA256_digest_size, "left"); + digest_variable right(pb, SHA256_digest_size, "right"); + digest_variable output(pb, SHA256_digest_size, "output"); + + sha256_two_to_one_hash_gadget f(pb, left, right, output, "f"); + f.generate_r1cs_constraints(); + printf("Number of constraints for sha256_two_to_one_hash_gadget: %zu\n", pb.num_constraints()); + + const bit_vector left_bv = int_list_to_bits({0x426bc2d8, 0x4dc86782, 0x81e8957a, 0x409ec148, 0xe6cffbe8, 0xafe6ba4f, 0x9c6f1978, 0xdd7af7e9}, 32); + const bit_vector right_bv = int_list_to_bits({0x038cce42, 0xabd366b8, 0x3ede7e00, 0x9130de53, 0x72cdf73d, 0xee825114, 0x8cb48d1b, 0x9af68ad0}, 32); + const bit_vector hash_bv = int_list_to_bits({0xeffd0b7f, 0x1ccba116, 0x2ee816f7, 0x31c62b48, 0x59305141, 0x990e5c0a, 0xce40d33d, 0x0b1167d1}, 32); + + left.generate_r1cs_witness(left_bv); + right.generate_r1cs_witness(right_bv); + + f.generate_r1cs_witness(); + output.generate_r1cs_witness(hash_bv); + + assert(pb.is_satisfied()); +} + +int main(void) +{ + start_profiling(); + default_ec_pp::init_public_params(); + test_two_to_one >(); +} diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp new file mode 100644 index 0000000..0efa7cf --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp @@ -0,0 +1,38 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MERKLE_AUTHENTICATION_PATH_VARIABLE_HPP_ +#define MERKLE_AUTHENTICATION_PATH_VARIABLE_HPP_ + +#include "common/data_structures/merkle_tree.hpp" +#include "gadgetlib1/gadget.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" + +namespace libsnark { + +template +class merkle_authentication_path_variable : public gadget { +public: + + const size_t tree_depth; + std::vector > left_digests; + std::vector > right_digests; + + merkle_authentication_path_variable(protoboard &pb, + const size_t tree_depth, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(const size_t address, const merkle_authentication_path &path); + merkle_authentication_path get_authentication_path(const size_t address) const; +}; + +} // libsnark + +#include "gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc" + +#endif // MERKLE_AUTHENTICATION_PATH_VARIABLE_HPP diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc new file mode 100644 index 0000000..d773051 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc @@ -0,0 +1,76 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MERKLE_AUTHENTICATION_PATH_VARIABLE_TCC_ +#define MERKLE_AUTHENTICATION_PATH_VARIABLE_TCC_ + +namespace libsnark { + +template +merkle_authentication_path_variable::merkle_authentication_path_variable(protoboard &pb, + const size_t tree_depth, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + tree_depth(tree_depth) +{ + for (size_t i = 0; i < tree_depth; ++i) + { + left_digests.emplace_back(digest_variable(pb, HashT::get_digest_len(), FMT(annotation_prefix, " left_digests_%zu", i))); + right_digests.emplace_back(digest_variable(pb, HashT::get_digest_len(), FMT(annotation_prefix, " right_digests_%zu", i))); + } +} + +template +void merkle_authentication_path_variable::generate_r1cs_constraints() +{ + for (size_t i = 0; i < tree_depth; ++i) + { + left_digests[i].generate_r1cs_constraints(); + right_digests[i].generate_r1cs_constraints(); + } +} + +template +void merkle_authentication_path_variable::generate_r1cs_witness(const size_t address, const merkle_authentication_path &path) +{ + assert(path.size() == tree_depth); + + for (size_t i = 0; i < tree_depth; ++i) + { + if (address & (1ul << (tree_depth-1-i))) + { + left_digests[i].generate_r1cs_witness(path[i]); + } + else + { + right_digests[i].generate_r1cs_witness(path[i]); + } + } +} + +template +merkle_authentication_path merkle_authentication_path_variable::get_authentication_path(const size_t address) const +{ + merkle_authentication_path result; + for (size_t i = 0; i < tree_depth; ++i) + { + if (address & (1ul << (tree_depth-1-i))) + { + result.emplace_back(left_digests[i].get_digest()); + } + else + { + result.emplace_back(right_digests[i].get_digest()); + } + } + + return result; +} + +} // libsnark + +#endif // MERKLE_AUTHENTICATION_PATH_VARIABLE_TCC diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp new file mode 100644 index 0000000..2663774 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp @@ -0,0 +1,74 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the Merkle tree check read gadget. + + The gadget checks the following: given a root R, address A, value V, and + authentication path P, check that P is a valid authentication path for the + value V as the A-th leaf in a Merkle tree with root R. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MERKLE_TREE_CHECK_READ_GADGET_HPP_ +#define MERKLE_TREE_CHECK_READ_GADGET_HPP_ + +#include "common/data_structures/merkle_tree.hpp" +#include "gadgetlib1/gadget.hpp" +#include "gadgetlib1/gadgets/hashes/crh_gadget.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" +#include "gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp" +#include "gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp" + +namespace libsnark { + +template +class merkle_tree_check_read_gadget : public gadget { +private: + + std::vector hashers; + std::vector > hasher_inputs; + std::vector > propagators; + std::vector > internal_output; + + std::shared_ptr > computed_root; + std::shared_ptr > check_root; + +public: + + const size_t digest_size; + const size_t tree_depth; + pb_linear_combination_array address_bits; + digest_variable leaf; + digest_variable root; + merkle_authentication_path_variable path; + pb_linear_combination read_successful; + + merkle_tree_check_read_gadget(protoboard &pb, + const size_t tree_depth, + const pb_linear_combination_array &address_bits, + const digest_variable &leaf_digest, + const digest_variable &root_digest, + const merkle_authentication_path_variable &path, + const pb_linear_combination &read_successful, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); + + static size_t root_size_in_bits(); + /* for debugging purposes */ + static size_t expected_constraints(const size_t tree_depth); +}; + +template +void test_merkle_tree_check_read_gadget(); + +} // libsnark + +#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc" + +#endif // MERKLE_TREE_CHECK_READ_GADGET_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc new file mode 100644 index 0000000..6002a58 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc @@ -0,0 +1,196 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the Merkle tree check read. + + See merkle_tree_check_read_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MERKLE_TREE_CHECK_READ_GADGET_TCC_ +#define MERKLE_TREE_CHECK_READ_GADGET_TCC_ + +namespace libsnark { + +template +merkle_tree_check_read_gadget::merkle_tree_check_read_gadget(protoboard &pb, + const size_t tree_depth, + const pb_linear_combination_array &address_bits, + const digest_variable &leaf, + const digest_variable &root, + const merkle_authentication_path_variable &path, + const pb_linear_combination &read_successful, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + digest_size(HashT::get_digest_len()), + tree_depth(tree_depth), + address_bits(address_bits), + leaf(leaf), + root(root), + path(path), + read_successful(read_successful) +{ + /* + The tricky part here is ordering. For Merkle tree + authentication paths, path[0] corresponds to one layer below + the root (and path[tree_depth-1] corresponds to the layer + containing the leaf), while address_bits has the reverse order: + address_bits[0] is LSB, and corresponds to layer containing the + leaf, and address_bits[tree_depth-1] is MSB, and corresponds to + the subtree directly under the root. + */ + assert(tree_depth > 0); + assert(tree_depth == address_bits.size()); + + for (size_t i = 0; i < tree_depth-1; ++i) + { + internal_output.emplace_back(digest_variable(pb, digest_size, FMT(this->annotation_prefix, " internal_output_%zu", i))); + } + + computed_root.reset(new digest_variable(pb, digest_size, FMT(this->annotation_prefix, " computed_root"))); + + for (size_t i = 0; i < tree_depth; ++i) + { + block_variable inp(pb, path.left_digests[i], path.right_digests[i], FMT(this->annotation_prefix, " inp_%zu", i)); + hasher_inputs.emplace_back(inp); + hashers.emplace_back(HashT(pb, 2*digest_size, inp, (i == 0 ? *computed_root : internal_output[i-1]), + FMT(this->annotation_prefix, " load_hashers_%zu", i))); + } + + for (size_t i = 0; i < tree_depth; ++i) + { + /* + The propagators take a computed hash value (or leaf in the + base case) and propagate it one layer up, either in the left + or the right slot of authentication_path_variable. + */ + propagators.emplace_back(digest_selector_gadget(pb, digest_size, i < tree_depth - 1 ? internal_output[i] : leaf, + address_bits[tree_depth-1-i], path.left_digests[i], path.right_digests[i], + FMT(this->annotation_prefix, " digest_selector_%zu", i))); + } + + check_root.reset(new bit_vector_copy_gadget(pb, computed_root->bits, root.bits, read_successful, FieldT::capacity(), FMT(annotation_prefix, " check_root"))); +} + +template +void merkle_tree_check_read_gadget::generate_r1cs_constraints() +{ + /* ensure correct hash computations */ + for (size_t i = 0; i < tree_depth; ++i) + { + // Note that we check root outside and have enforced booleanity of path.left_digests/path.right_digests outside in path.generate_r1cs_constraints + hashers[i].generate_r1cs_constraints(false); + } + + /* ensure consistency of path.left_digests/path.right_digests with internal_output */ + for (size_t i = 0; i < tree_depth; ++i) + { + propagators[i].generate_r1cs_constraints(); + } + + check_root->generate_r1cs_constraints(false, false); +} + +template +void merkle_tree_check_read_gadget::generate_r1cs_witness() +{ + /* do the hash computations bottom-up */ + for (int i = tree_depth-1; i >= 0; --i) + { + /* propagate previous input */ + propagators[i].generate_r1cs_witness(); + + /* compute hash */ + hashers[i].generate_r1cs_witness(); + } + + check_root->generate_r1cs_witness(); +} + +template +size_t merkle_tree_check_read_gadget::root_size_in_bits() +{ + return HashT::get_digest_len(); +} + +template +size_t merkle_tree_check_read_gadget::expected_constraints(const size_t tree_depth) +{ + /* NB: this includes path constraints */ + const size_t hasher_constraints = tree_depth * HashT::expected_constraints(false); + const size_t propagator_constraints = tree_depth * HashT::get_digest_len(); + const size_t authentication_path_constraints = 2 * tree_depth * HashT::get_digest_len(); + const size_t check_root_constraints = 3 * div_ceil(HashT::get_digest_len(), FieldT::capacity()); + + return hasher_constraints + propagator_constraints + authentication_path_constraints + check_root_constraints; +} + +template +void test_merkle_tree_check_read_gadget() +{ + /* prepare test */ + const size_t digest_len = HashT::get_digest_len(); + const size_t tree_depth = 16; + std::vector path(tree_depth); + + bit_vector prev_hash(digest_len); + std::generate(prev_hash.begin(), prev_hash.end(), [&]() { return std::rand() % 2; }); + bit_vector leaf = prev_hash; + + bit_vector address_bits; + + size_t address = 0; + for (long level = tree_depth-1; level >= 0; --level) + { + const bool computed_is_right = (std::rand() % 2); + address |= (computed_is_right ? 1ul << (tree_depth-1-level) : 0); + address_bits.push_back(computed_is_right); + bit_vector other(digest_len); + std::generate(other.begin(), other.end(), [&]() { return std::rand() % 2; }); + + bit_vector block = prev_hash; + block.insert(computed_is_right ? block.begin() : block.end(), other.begin(), other.end()); + bit_vector h = HashT::get_hash(block); + + path[level] = other; + + prev_hash = h; + } + bit_vector root = prev_hash; + + /* execute test */ + protoboard pb; + pb_variable_array address_bits_va; + address_bits_va.allocate(pb, tree_depth, "address_bits"); + digest_variable leaf_digest(pb, digest_len, "input_block"); + digest_variable root_digest(pb, digest_len, "output_digest"); + merkle_authentication_path_variable path_var(pb, tree_depth, "path_var"); + merkle_tree_check_read_gadget ml(pb, tree_depth, address_bits_va, leaf_digest, root_digest, path_var, ONE, "ml"); + + path_var.generate_r1cs_constraints(); + ml.generate_r1cs_constraints(); + + address_bits_va.fill_with_bits(pb, address_bits); + assert(address_bits_va.get_field_element_from_bits(pb).as_ulong() == address); + leaf_digest.generate_r1cs_witness(leaf); + path_var.generate_r1cs_witness(address, path); + ml.generate_r1cs_witness(); + + /* make sure that read checker didn't accidentally overwrite anything */ + address_bits_va.fill_with_bits(pb, address_bits); + leaf_digest.generate_r1cs_witness(leaf); + root_digest.generate_r1cs_witness(root); + assert(pb.is_satisfied()); + + const size_t num_constraints = pb.num_constraints(); + const size_t expected_constraints = merkle_tree_check_read_gadget::expected_constraints(tree_depth); + assert(num_constraints == expected_constraints); +} + +} // libsnark + +#endif // MERKLE_TREE_CHECK_READ_GADGET_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp new file mode 100644 index 0000000..2d6840d --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp @@ -0,0 +1,91 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the Merkle tree check read gadget. + + The gadget checks the following: given two roots R1 and R2, address A, two + values V1 and V2, and authentication path P, check that + - P is a valid authentication path for the value V1 as the A-th leaf in a Merkle tree with root R1, and + - P is a valid authentication path for the value V2 as the A-th leaf in a Merkle tree with root R2. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MERKLE_TREE_CHECK_UPDATE_GADGET_HPP_ +#define MERKLE_TREE_CHECK_UPDATE_GADGET_HPP_ + +#include "common/data_structures/merkle_tree.hpp" +#include "gadgetlib1/gadget.hpp" +#include "gadgetlib1/gadgets/hashes/crh_gadget.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" +#include "gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp" +#include "gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp" + +namespace libsnark { + +template +class merkle_tree_check_update_gadget : public gadget { +private: + + std::vector prev_hashers; + std::vector > prev_hasher_inputs; + std::vector > prev_propagators; + std::vector > prev_internal_output; + + std::vector next_hashers; + std::vector > next_hasher_inputs; + std::vector > next_propagators; + std::vector > next_internal_output; + + std::shared_ptr > computed_next_root; + std::shared_ptr > check_next_root; + +public: + + const size_t digest_size; + const size_t tree_depth; + + pb_variable_array address_bits; + digest_variable prev_leaf_digest; + digest_variable prev_root_digest; + merkle_authentication_path_variable prev_path; + digest_variable next_leaf_digest; + digest_variable next_root_digest; + merkle_authentication_path_variable next_path; + pb_linear_combination update_successful; + + /* Note that while it is necessary to generate R1CS constraints + for prev_path, it is not necessary to do so for next_path. See + comment in the implementation of generate_r1cs_constraints() */ + + merkle_tree_check_update_gadget(protoboard &pb, + const size_t tree_depth, + const pb_variable_array &address_bits, + const digest_variable &prev_leaf_digest, + const digest_variable &prev_root_digest, + const merkle_authentication_path_variable &prev_path, + const digest_variable &next_leaf_digest, + const digest_variable &next_root_digest, + const merkle_authentication_path_variable &next_path, + const pb_linear_combination &update_successful, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); + + static size_t root_size_in_bits(); + /* for debugging purposes */ + static size_t expected_constraints(const size_t tree_depth); +}; + +template +void test_merkle_tree_check_update_gadget(); + +} // libsnark + +#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc" + +#endif // MERKLE_TREE_CHECK_UPDATE_GADGET_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc new file mode 100644 index 0000000..1ac08ed --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc @@ -0,0 +1,265 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the Merkle tree check update gadget. + + See merkle_tree_check_update_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MERKLE_TREE_CHECK_UPDATE_GADGET_TCC_ +#define MERKLE_TREE_CHECK_UPDATE_GADGET_TCC_ + +namespace libsnark { + +template +merkle_tree_check_update_gadget::merkle_tree_check_update_gadget(protoboard &pb, + const size_t tree_depth, + const pb_variable_array &address_bits, + const digest_variable &prev_leaf_digest, + const digest_variable &prev_root_digest, + const merkle_authentication_path_variable &prev_path, + const digest_variable &next_leaf_digest, + const digest_variable &next_root_digest, + const merkle_authentication_path_variable &next_path, + const pb_linear_combination &update_successful, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + digest_size(HashT::get_digest_len()), + tree_depth(tree_depth), + address_bits(address_bits), + prev_leaf_digest(prev_leaf_digest), + prev_root_digest(prev_root_digest), + prev_path(prev_path), + next_leaf_digest(next_leaf_digest), + next_root_digest(next_root_digest), + next_path(next_path), + update_successful(update_successful) +{ + assert(tree_depth > 0); + assert(tree_depth == address_bits.size()); + + for (size_t i = 0; i < tree_depth-1; ++i) + { + prev_internal_output.emplace_back(digest_variable(pb, digest_size, FMT(this->annotation_prefix, " prev_internal_output_%zu", i))); + next_internal_output.emplace_back(digest_variable(pb, digest_size, FMT(this->annotation_prefix, " next_internal_output_%zu", i))); + } + + computed_next_root.reset(new digest_variable(pb, digest_size, FMT(this->annotation_prefix, " computed_root"))); + + for (size_t i = 0; i < tree_depth; ++i) + { + block_variable prev_inp(pb, prev_path.left_digests[i], prev_path.right_digests[i], FMT(this->annotation_prefix, " prev_inp_%zu", i)); + prev_hasher_inputs.emplace_back(prev_inp); + prev_hashers.emplace_back(HashT(pb, 2*digest_size, prev_inp, (i == 0 ? prev_root_digest : prev_internal_output[i-1]), + FMT(this->annotation_prefix, " prev_hashers_%zu", i))); + + block_variable next_inp(pb, next_path.left_digests[i], next_path.right_digests[i], FMT(this->annotation_prefix, " next_inp_%zu", i)); + next_hasher_inputs.emplace_back(next_inp); + next_hashers.emplace_back(HashT(pb, 2*digest_size, next_inp, (i == 0 ? *computed_next_root : next_internal_output[i-1]), + FMT(this->annotation_prefix, " next_hashers_%zu", i))); + } + + for (size_t i = 0; i < tree_depth; ++i) + { + prev_propagators.emplace_back(digest_selector_gadget(pb, digest_size, i < tree_depth -1 ? prev_internal_output[i] : prev_leaf_digest, + address_bits[tree_depth-1-i], prev_path.left_digests[i], prev_path.right_digests[i], + FMT(this->annotation_prefix, " prev_propagators_%zu", i))); + next_propagators.emplace_back(digest_selector_gadget(pb, digest_size, i < tree_depth -1 ? next_internal_output[i] : next_leaf_digest, + address_bits[tree_depth-1-i], next_path.left_digests[i], next_path.right_digests[i], + FMT(this->annotation_prefix, " next_propagators_%zu", i))); + } + + check_next_root.reset(new bit_vector_copy_gadget(pb, computed_next_root->bits, next_root_digest.bits, update_successful, FieldT::capacity(), FMT(annotation_prefix, " check_next_root"))); +} + +template +void merkle_tree_check_update_gadget::generate_r1cs_constraints() +{ + /* ensure correct hash computations */ + for (size_t i = 0; i < tree_depth; ++i) + { + prev_hashers[i].generate_r1cs_constraints(false); // we check root outside and prev_left/prev_right above + next_hashers[i].generate_r1cs_constraints(true); // however we must check right side hashes + } + + /* ensure consistency of internal_left/internal_right with internal_output */ + for (size_t i = 0; i < tree_depth; ++i) + { + prev_propagators[i].generate_r1cs_constraints(); + next_propagators[i].generate_r1cs_constraints(); + } + + /* ensure that prev auxiliary input and next auxiliary input match */ + for (size_t i = 0; i < tree_depth; ++i) + { + for (size_t j = 0; j < digest_size; ++j) + { + /* + addr * (prev_left - next_left) + (1 - addr) * (prev_right - next_right) = 0 + addr * (prev_left - next_left - prev_right + next_right) = next_right - prev_right + */ + this->pb.add_r1cs_constraint(r1cs_constraint(address_bits[tree_depth-1-i], + prev_path.left_digests[i].bits[j] - next_path.left_digests[i].bits[j] - prev_path.right_digests[i].bits[j] + next_path.right_digests[i].bits[j], + next_path.right_digests[i].bits[j] - prev_path.right_digests[i].bits[j]), + FMT(this->annotation_prefix, " aux_check_%zu_%zu", i, j)); + } + } + + /* Note that while it is necessary to generate R1CS constraints + for prev_path, it is not necessary to do so for next_path. + + This holds, because { next_path.left_inputs[i], + next_path.right_inputs[i] } is a pair { hash_output, + auxiliary_input }. The bitness for hash_output is enforced + above by next_hashers[i].generate_r1cs_constraints. + + Because auxiliary input is the same for prev_path and next_path + (enforced above), we have that auxiliary_input part is also + constrained to be boolean, because prev_path is *all* + constrained to be all boolean. */ + + check_next_root->generate_r1cs_constraints(false, false); +} + +template +void merkle_tree_check_update_gadget::generate_r1cs_witness() +{ + /* do the hash computations bottom-up */ + for (int i = tree_depth-1; i >= 0; --i) + { + /* ensure consistency of prev_path and next_path */ + if (this->pb.val(address_bits[tree_depth-1-i]) == FieldT::one()) + { + next_path.left_digests[i].generate_r1cs_witness(prev_path.left_digests[i].get_digest()); + } + else + { + next_path.right_digests[i].generate_r1cs_witness(prev_path.right_digests[i].get_digest()); + } + + /* propagate previous input */ + prev_propagators[i].generate_r1cs_witness(); + next_propagators[i].generate_r1cs_witness(); + + /* compute hash */ + prev_hashers[i].generate_r1cs_witness(); + next_hashers[i].generate_r1cs_witness(); + } + + check_next_root->generate_r1cs_witness(); +} + +template +size_t merkle_tree_check_update_gadget::root_size_in_bits() +{ + return HashT::get_digest_len(); +} + +template +size_t merkle_tree_check_update_gadget::expected_constraints(const size_t tree_depth) +{ + /* NB: this includes path constraints */ + const size_t prev_hasher_constraints = tree_depth * HashT::expected_constraints(false); + const size_t next_hasher_constraints = tree_depth * HashT::expected_constraints(true); + const size_t prev_authentication_path_constraints = 2 * tree_depth * HashT::get_digest_len(); + const size_t prev_propagator_constraints = tree_depth * HashT::get_digest_len(); + const size_t next_propagator_constraints = tree_depth * HashT::get_digest_len(); + const size_t check_next_root_constraints = 3 * div_ceil(HashT::get_digest_len(), FieldT::capacity()); + const size_t aux_equality_constraints = tree_depth * HashT::get_digest_len(); + + return (prev_hasher_constraints + next_hasher_constraints + prev_authentication_path_constraints + + prev_propagator_constraints + next_propagator_constraints + check_next_root_constraints + + aux_equality_constraints); +} + +template +void test_merkle_tree_check_update_gadget() +{ + /* prepare test */ + const size_t digest_len = HashT::get_digest_len(); + + const size_t tree_depth = 16; + std::vector prev_path(tree_depth); + + bit_vector prev_load_hash(digest_len); + std::generate(prev_load_hash.begin(), prev_load_hash.end(), [&]() { return std::rand() % 2; }); + bit_vector prev_store_hash(digest_len); + std::generate(prev_store_hash.begin(), prev_store_hash.end(), [&]() { return std::rand() % 2; }); + + bit_vector loaded_leaf = prev_load_hash; + bit_vector stored_leaf = prev_store_hash; + + bit_vector address_bits; + + size_t address = 0; + for (long level = tree_depth-1; level >= 0; --level) + { + const bool computed_is_right = (std::rand() % 2); + address |= (computed_is_right ? 1ul << (tree_depth-1-level) : 0); + address_bits.push_back(computed_is_right); + bit_vector other(digest_len); + std::generate(other.begin(), other.end(), [&]() { return std::rand() % 2; }); + + bit_vector load_block = prev_load_hash; + load_block.insert(computed_is_right ? load_block.begin() : load_block.end(), other.begin(), other.end()); + bit_vector store_block = prev_store_hash; + store_block.insert(computed_is_right ? store_block.begin() : store_block.end(), other.begin(), other.end()); + + bit_vector load_h = HashT::get_hash(load_block); + bit_vector store_h = HashT::get_hash(store_block); + + prev_path[level] = other; + + prev_load_hash = load_h; + prev_store_hash = store_h; + } + + bit_vector load_root = prev_load_hash; + bit_vector store_root = prev_store_hash; + + /* execute the test */ + protoboard pb; + pb_variable_array address_bits_va; + address_bits_va.allocate(pb, tree_depth, "address_bits"); + digest_variable prev_leaf_digest(pb, digest_len, "prev_leaf_digest"); + digest_variable prev_root_digest(pb, digest_len, "prev_root_digest"); + merkle_authentication_path_variable prev_path_var(pb, tree_depth, "prev_path_var"); + digest_variable next_leaf_digest(pb, digest_len, "next_leaf_digest"); + digest_variable next_root_digest(pb, digest_len, "next_root_digest"); + merkle_authentication_path_variable next_path_var(pb, tree_depth, "next_path_var"); + merkle_tree_check_update_gadget mls(pb, tree_depth, address_bits_va, + prev_leaf_digest, prev_root_digest, prev_path_var, + next_leaf_digest, next_root_digest, next_path_var, ONE, "mls"); + + prev_path_var.generate_r1cs_constraints(); + mls.generate_r1cs_constraints(); + + address_bits_va.fill_with_bits(pb, address_bits); + assert(address_bits_va.get_field_element_from_bits(pb).as_ulong() == address); + prev_leaf_digest.generate_r1cs_witness(loaded_leaf); + prev_path_var.generate_r1cs_witness(address, prev_path); + next_leaf_digest.generate_r1cs_witness(stored_leaf); + address_bits_va.fill_with_bits(pb, address_bits); + mls.generate_r1cs_witness(); + + /* make sure that update check will check for the right things */ + prev_leaf_digest.generate_r1cs_witness(loaded_leaf); + next_leaf_digest.generate_r1cs_witness(stored_leaf); + prev_root_digest.generate_r1cs_witness(load_root); + next_root_digest.generate_r1cs_witness(store_root); + address_bits_va.fill_with_bits(pb, address_bits); + assert(pb.is_satisfied()); + + const size_t num_constraints = pb.num_constraints(); + const size_t expected_constraints = merkle_tree_check_update_gadget::expected_constraints(tree_depth); + assert(num_constraints == expected_constraints); +} + +} // libsnark + +#endif // MERKLE_TREE_CHECK_UPDATE_GADGET_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp b/privacy/zsl/zsl/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp new file mode 100644 index 0000000..8d52c57 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp @@ -0,0 +1,48 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifdef CURVE_BN128 +#include "algebra/curves/bn128/bn128_pp.hpp" +#endif +#include "algebra/curves/edwards/edwards_pp.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp" +#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp" +#include "gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp" + +using namespace libsnark; + +template +void test_all_merkle_tree_gadgets() +{ + typedef Fr FieldT; + test_merkle_tree_check_read_gadget >(); + test_merkle_tree_check_read_gadget >(); + + test_merkle_tree_check_update_gadget >(); + test_merkle_tree_check_update_gadget >(); +} + +int main(void) +{ + start_profiling(); + +#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled + bn128_pp::init_public_params(); + test_all_merkle_tree_gadgets(); +#endif + + edwards_pp::init_public_params(); + test_all_merkle_tree_gadgets(); + + mnt4_pp::init_public_params(); + test_all_merkle_tree_gadgets(); + + mnt6_pp::init_public_params(); + test_all_merkle_tree_gadgets(); +} diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/mnt_pairing_params.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/mnt_pairing_params.hpp new file mode 100644 index 0000000..1d6d30f --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/mnt_pairing_params.hpp @@ -0,0 +1,102 @@ +/** @file + ***************************************************************************** + + Declaration of specializations of pairing_selector to + - pairing_selector, and + - pairing_selector. + + See pairing_params.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT_PAIRING_PARAMS_HPP_ +#define MNT_PAIRING_PARAMS_HPP_ + +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +#include "gadgetlib1/gadgets/pairing/pairing_params.hpp" +#include "gadgetlib1/gadgets/fields/fp2_gadgets.hpp" +#include "gadgetlib1/gadgets/fields/fp4_gadgets.hpp" +#include "gadgetlib1/gadgets/fields/fp3_gadgets.hpp" +#include "gadgetlib1/gadgets/fields/fp6_gadgets.hpp" + +namespace libsnark { + +template +class mnt_e_over_e_miller_loop_gadget; + +template +class mnt_e_times_e_over_e_miller_loop_gadget; + +template +class mnt4_final_exp_gadget; + +template +class mnt6_final_exp_gadget; + +/** + * Specialization for MNT4. + */ +template<> +class pairing_selector { +public: + typedef Fr FieldT; + typedef Fqe FqeT; + typedef Fqk FqkT; + + typedef Fp3_variable Fqe_variable_type; + typedef Fp3_mul_gadget Fqe_mul_gadget_type; + typedef Fp3_mul_by_lc_gadget Fqe_mul_by_lc_gadget_type; + typedef Fp3_sqr_gadget Fqe_sqr_gadget_type; + + typedef Fp6_variable Fqk_variable_type; + typedef Fp6_mul_gadget Fqk_mul_gadget_type; + typedef Fp6_mul_by_2345_gadget Fqk_special_mul_gadget_type; + typedef Fp6_sqr_gadget Fqk_sqr_gadget_type; + + typedef mnt6_pp other_curve_type; + + typedef mnt_e_over_e_miller_loop_gadget e_over_e_miller_loop_gadget_type; + typedef mnt_e_times_e_over_e_miller_loop_gadget e_times_e_over_e_miller_loop_gadget_type; + typedef mnt4_final_exp_gadget final_exp_gadget_type; + + static const constexpr bigint &pairing_loop_count = mnt6_ate_loop_count; +}; + +/** + * Specialization for MNT6. + */ +template<> +class pairing_selector { +public: + typedef Fr FieldT; + + typedef Fqe FqeT; + typedef Fqk FqkT; + + typedef Fp2_variable Fqe_variable_type; + typedef Fp2_mul_gadget Fqe_mul_gadget_type; + typedef Fp2_mul_by_lc_gadget Fqe_mul_by_lc_gadget_type; + typedef Fp2_sqr_gadget Fqe_sqr_gadget_type; + + typedef Fp4_variable Fqk_variable_type; + typedef Fp4_mul_gadget Fqk_mul_gadget_type; + typedef Fp4_mul_gadget Fqk_special_mul_gadget_type; + typedef Fp4_sqr_gadget Fqk_sqr_gadget_type; + + typedef mnt4_pp other_curve_type; + + typedef mnt_e_over_e_miller_loop_gadget e_over_e_miller_loop_gadget_type; + typedef mnt_e_times_e_over_e_miller_loop_gadget e_times_e_over_e_miller_loop_gadget_type; + typedef mnt6_final_exp_gadget final_exp_gadget_type; + + static const constexpr bigint &pairing_loop_count = mnt4_ate_loop_count; +}; + +} // libsnark + +#endif // MNT_PAIRING_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/pairing_checks.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/pairing_checks.hpp new file mode 100644 index 0000000..872a14d --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/pairing_checks.hpp @@ -0,0 +1,94 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for pairing-check gadgets. + + Given that e(.,.) denotes a pairing, + - the gadget "check_e_equals_e_gadget" checks the equation "e(P1,Q1)=e(P2,Q2)"; and + - the gadget "check_e_equals_ee_gadget" checks the equation "e(P1,Q1)=e(P2,Q2)*e(P3,Q3)". + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PAIRING_CHECKS_HPP_ +#define PAIRING_CHECKS_HPP_ + +#include +#include "gadgetlib1/gadgets/pairing/pairing_params.hpp" +#include "gadgetlib1/gadgets/pairing/weierstrass_miller_loop.hpp" +#include "gadgetlib1/gadgets/pairing/weierstrass_final_exponentiation.hpp" + +namespace libsnark { + +template +class check_e_equals_e_gadget : public gadget > { +public: + + typedef Fr FieldT; + + std::shared_ptr > ratio; + std::shared_ptr > compute_ratio; + std::shared_ptr > check_finexp; + + G1_precomputation lhs_G1; + G2_precomputation lhs_G2; + G1_precomputation rhs_G1; + G2_precomputation rhs_G2; + + pb_variable result; + + check_e_equals_e_gadget(protoboard &pb, + const G1_precomputation &lhs_G1, + const G2_precomputation &lhs_G2, + const G1_precomputation &rhs_G1, + const G2_precomputation &rhs_G2, + const pb_variable &result, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + + void generate_r1cs_witness(); +}; + +template +class check_e_equals_ee_gadget : public gadget > { +public: + + typedef Fr FieldT; + + std::shared_ptr > ratio; + std::shared_ptr > compute_ratio; + std::shared_ptr > check_finexp; + + G1_precomputation lhs_G1; + G2_precomputation lhs_G2; + G1_precomputation rhs1_G1; + G2_precomputation rhs1_G2; + G1_precomputation rhs2_G1; + G2_precomputation rhs2_G2; + + pb_variable result; + + check_e_equals_ee_gadget(protoboard &pb, + const G1_precomputation &lhs_G1, + const G2_precomputation &lhs_G2, + const G1_precomputation &rhs1_G1, + const G2_precomputation &rhs1_G2, + const G1_precomputation &rhs2_G1, + const G2_precomputation &rhs2_G2, + const pb_variable &result, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/pairing/pairing_checks.tcc" + +#endif // PAIRING_CHECKS_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/pairing_checks.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/pairing_checks.tcc new file mode 100644 index 0000000..65aa4a7 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/pairing_checks.tcc @@ -0,0 +1,93 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for pairing-check gadgets. + + See pairing_checks.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PAIRING_CHECKS_TCC_ +#define PAIRING_CHECKS_TCC_ + +namespace libsnark { + +template +check_e_equals_e_gadget::check_e_equals_e_gadget(protoboard &pb, + const G1_precomputation &lhs_G1, + const G2_precomputation &lhs_G2, + const G1_precomputation &rhs_G1, + const G2_precomputation &rhs_G2, + const pb_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + lhs_G1(lhs_G1), + lhs_G2(lhs_G2), + rhs_G1(rhs_G1), + rhs_G2(rhs_G2), + result(result) +{ + ratio.reset(new Fqk_variable(pb, FMT(annotation_prefix, " ratio"))); + compute_ratio.reset(new e_over_e_miller_loop_gadget(pb, lhs_G1, lhs_G2, rhs_G1, rhs_G2, *ratio, FMT(annotation_prefix, " compute_ratio"))); + check_finexp.reset(new final_exp_gadget(pb, *ratio, result, FMT(annotation_prefix, " check_finexp"))); +} + +template +void check_e_equals_e_gadget::generate_r1cs_constraints() +{ + compute_ratio->generate_r1cs_constraints(); + check_finexp->generate_r1cs_constraints(); +} + +template +void check_e_equals_e_gadget::generate_r1cs_witness() +{ + compute_ratio->generate_r1cs_witness(); + check_finexp->generate_r1cs_witness(); +} + +template +check_e_equals_ee_gadget::check_e_equals_ee_gadget(protoboard &pb, + const G1_precomputation &lhs_G1, + const G2_precomputation &lhs_G2, + const G1_precomputation &rhs1_G1, + const G2_precomputation &rhs1_G2, + const G1_precomputation &rhs2_G1, + const G2_precomputation &rhs2_G2, + const pb_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + lhs_G1(lhs_G1), + lhs_G2(lhs_G2), + rhs1_G1(rhs1_G1), + rhs1_G2(rhs1_G2), + rhs2_G1(rhs2_G1), + rhs2_G2(rhs2_G2), + result(result) +{ + ratio.reset(new Fqk_variable(pb, FMT(annotation_prefix, " ratio"))); + compute_ratio.reset(new e_times_e_over_e_miller_loop_gadget(pb, rhs1_G1, rhs1_G2, rhs2_G1, rhs2_G2, lhs_G1, lhs_G2, *ratio, FMT(annotation_prefix, " compute_ratio"))); + check_finexp.reset(new final_exp_gadget(pb, *ratio, result, FMT(annotation_prefix, " check_finexp"))); +} + +template +void check_e_equals_ee_gadget::generate_r1cs_constraints() +{ + compute_ratio->generate_r1cs_constraints(); + check_finexp->generate_r1cs_constraints(); +} + +template +void check_e_equals_ee_gadget::generate_r1cs_witness() +{ + compute_ratio->generate_r1cs_witness(); + check_finexp->generate_r1cs_witness(); +} + +} // libsnark + +#endif // PAIRING_CHECKS_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/pairing_params.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/pairing_params.hpp new file mode 100644 index 0000000..5338c72 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/pairing_params.hpp @@ -0,0 +1,116 @@ +/** @file + ***************************************************************************** + + Declaration of selector for the pairing gadget. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PAIRING_PARAMS_HPP_ +#define PAIRING_PARAMS_HPP_ + +namespace libsnark { + +/** + * The interfaces of pairing gadgets are templatized via the parameter + * ec_ppT. When used, the interfaces must be invoked with + * a particular parameter choice; let 'my_ec_pp' denote this choice. + * + * Moreover, one must provide a template specialization for the class + * pairing_selector (below), containing typedefs for the typenames + * - FieldT + * - FqeT + * - FqkT + * - Fqe_variable_type; + * - Fqe_mul_gadget_type + * - Fqe_mul_by_lc_gadget_type + * - Fqe_sqr_gadget_type + * - Fqk_variable_type + * - Fqk_mul_gadget_type + * - Fqk_special_mul_gadget_type + * - Fqk_sqr_gadget_type + * - other_curve_type + * - e_over_e_miller_loop_gadget_type + * - e_times_e_over_e_miller_loop_gadget_type + * - final_exp_gadget_type + * and also containing a static constant + * - const constexpr bigint pairing_loop_count + * + * For example, if you want to use the types my_Field, my_Fqe, etc, + * then you would do as follows. First declare a new type: + * + * class my_ec_pp; + * + * Second, specialize pairing_selector for the + * case ec_ppT = my_ec_pp, using the above types: + * + * template<> + * class pairing_selector { + * typedef my_Field FieldT; + * typedef my_Fqe FqeT; + * typedef my_Fqk FqkT; + * typedef my_Fqe_variable_type Fqe_variable_type; + * typedef my_Fqe_mul_gadget_type Fqe_mul_gadget_type; + * typedef my_Fqe_mul_by_lc_gadget_type Fqe_mul_by_lc_gadget_type; + * typedef my_Fqe_sqr_gadget_type Fqe_sqr_gadget_type; + * typedef my_Fqk_variable_type Fqk_variable_type; + * typedef my_Fqk_mul_gadget_type Fqk_mul_gadget_type; + * typedef my_Fqk_special_mul_gadget_type Fqk_special_mul_gadget_type; + * typedef my_Fqk_sqr_gadget_type Fqk_sqr_gadget_type; + * typedef my_other_curve_type other_curve_type; + * typedef my_e_over_e_miller_loop_gadget_type e_over_e_miller_loop_gadget_type; + * typedef my_e_times_e_over_e_miller_loop_gadget_type e_times_e_over_e_miller_loop_gadget_type; + * typedef my_final_exp_gadget_type final_exp_gadget_type; + * static const constexpr bigint<...> &pairing_loop_count = ...; + * }; + * + * Having done the above, my_ec_pp can be used as a template parameter. + * + * See mnt_pairing_params.hpp for examples for the case of fixing + * ec_ppT to "MNT4" and "MNT6". + * + */ +template +class pairing_selector; + +/** + * Below are various template aliases (used for convenience). + */ + +template +using FqkT = typename pairing_selector::FqkT; // TODO: better name when stable + +template +using Fqe_variable = typename pairing_selector::Fqe_variable_type; +template +using Fqe_mul_gadget = typename pairing_selector::Fqe_mul_gadget_type; +template +using Fqe_mul_by_lc_gadget = typename pairing_selector::Fqe_mul_by_lc_gadget_type; +template +using Fqe_sqr_gadget = typename pairing_selector::Fqe_sqr_gadget_type; + +template +using Fqk_variable = typename pairing_selector::Fqk_variable_type; +template +using Fqk_mul_gadget = typename pairing_selector::Fqk_mul_gadget_type; +template +using Fqk_special_mul_gadget = typename pairing_selector::Fqk_special_mul_gadget_type; +template +using Fqk_sqr_gadget = typename pairing_selector::Fqk_sqr_gadget_type; + +template +using other_curve = typename pairing_selector::other_curve_type; + +template +using e_over_e_miller_loop_gadget = typename pairing_selector::e_over_e_miller_loop_gadget_type; +template +using e_times_e_over_e_miller_loop_gadget = typename pairing_selector::e_times_e_over_e_miller_loop_gadget_type; +template +using final_exp_gadget = typename pairing_selector::final_exp_gadget_type; + +} // libsnark + +#endif // PAIRING_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/weierstrass_final_exponentiation.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/weierstrass_final_exponentiation.hpp new file mode 100644 index 0000000..c88432e --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/weierstrass_final_exponentiation.hpp @@ -0,0 +1,110 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for final exponentiation gadgets. + + The gadgets verify final exponentiation for Weiersrass curves with embedding + degrees 4 and 6. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WEIERSTRASS_FINAL_EXPONENTIATION_HPP_ +#define WEIERSTRASS_FINAL_EXPONENTIATION_HPP_ + +#include +#include "gadgetlib1/gadgets/pairing/mnt_pairing_params.hpp" +#include "gadgetlib1/gadgets/fields/exponentiation_gadget.hpp" + +namespace libsnark { + +/** + * Gadget for final exponentiation with embedding degree 4. + */ +template +class mnt4_final_exp_gadget : public gadget > { +public: + typedef Fr FieldT; + + Fqk_variable el; + std::shared_ptr > one; + std::shared_ptr > el_inv; + std::shared_ptr > el_q_3; + std::shared_ptr > el_q_3_minus_1; + std::shared_ptr > alpha; + std::shared_ptr > beta; + std::shared_ptr > beta_q; + std::shared_ptr > el_inv_q_3; + std::shared_ptr > el_inv_q_3_minus_1; + std::shared_ptr > inv_alpha; + std::shared_ptr > inv_beta; + std::shared_ptr > w1; + std::shared_ptr > w0; + std::shared_ptr > result; + + std::shared_ptr > compute_el_inv; + std::shared_ptr > compute_el_q_3_minus_1; + std::shared_ptr > compute_beta; + std::shared_ptr > compute_el_inv_q_3_minus_1; + std::shared_ptr > compute_inv_beta; + + std::shared_ptr, Fp6_variable, Fp6_mul_gadget, Fp6_cyclotomic_sqr_gadget, mnt6_q_limbs> > compute_w1; + std::shared_ptr, Fp6_variable, Fp6_mul_gadget, Fp6_cyclotomic_sqr_gadget, mnt6_q_limbs> > compute_w0; + std::shared_ptr > compute_result; + + pb_variable result_is_one; + + mnt4_final_exp_gadget(protoboard &pb, + const Fqk_variable &el, + const pb_variable &result_is_one, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget for final exponentiation with embedding degree 6. + */ +template +class mnt6_final_exp_gadget : public gadget > { +public: + typedef Fr FieldT; + + Fqk_variable el; + std::shared_ptr > one; + std::shared_ptr > el_inv; + std::shared_ptr > el_q_2; + std::shared_ptr > el_q_2_minus_1; + std::shared_ptr > el_q_3_minus_q; + std::shared_ptr > el_inv_q_2; + std::shared_ptr > el_inv_q_2_minus_1; + std::shared_ptr > w1; + std::shared_ptr > w0; + std::shared_ptr > result; + + std::shared_ptr > compute_el_inv; + std::shared_ptr > compute_el_q_2_minus_1; + std::shared_ptr > compute_el_inv_q_2_minus_1; + + std::shared_ptr, Fp4_variable, Fp4_mul_gadget, Fp4_cyclotomic_sqr_gadget, mnt4_q_limbs> > compute_w1; + std::shared_ptr, Fp4_variable, Fp4_mul_gadget, Fp4_cyclotomic_sqr_gadget, mnt4_q_limbs> > compute_w0; + std::shared_ptr > compute_result; + + pb_variable result_is_one; + + mnt6_final_exp_gadget(protoboard &pb, + const Fqk_variable &el, + const pb_variable &result_is_one, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/pairing/weierstrass_final_exponentiation.tcc" + +#endif // WEIERSTRASS_FINAL_EXPONENTIATION_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/weierstrass_final_exponentiation.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/weierstrass_final_exponentiation.tcc new file mode 100644 index 0000000..3b0d141 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/weierstrass_final_exponentiation.tcc @@ -0,0 +1,184 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for final exponentiation gadgets. + + See weierstrass_final_exponentiation.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WEIERSTRASS_FINAL_EXPONENTIATION_TCC_ +#define WEIERSTRASS_FINAL_EXPONENTIATION_TCC_ + +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "gadgetlib1/gadgets/pairing/mnt_pairing_params.hpp" + +namespace libsnark { + +template +mnt4_final_exp_gadget::mnt4_final_exp_gadget(protoboard &pb, + const Fqk_variable &el, + const pb_variable &result_is_one, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + el(el), + result_is_one(result_is_one) +{ + one.reset(new Fqk_variable(pb, FMT(annotation_prefix, " one"))); + el_inv.reset(new Fqk_variable(pb, FMT(annotation_prefix, " el_inv"))); + el_q_3.reset(new Fqk_variable(el.Frobenius_map(3))); + el_q_3_minus_1.reset(new Fqk_variable(pb, FMT(annotation_prefix, " el_q_3_minus_1"))); + alpha.reset(new Fqk_variable(el_q_3_minus_1->Frobenius_map(1))); + beta.reset(new Fqk_variable(pb, FMT(annotation_prefix, " beta"))); + beta_q.reset(new Fqk_variable(beta->Frobenius_map(1))); + + el_inv_q_3.reset(new Fqk_variable(el_inv->Frobenius_map(3))); + el_inv_q_3_minus_1.reset(new Fqk_variable(pb, FMT(annotation_prefix, " el_inv_q_3_minus_1"))); + inv_alpha.reset(new Fqk_variable(el_inv_q_3_minus_1->Frobenius_map(1))); + inv_beta.reset(new Fqk_variable(pb, FMT(annotation_prefix, " inv_beta"))); + w1.reset(new Fqk_variable(pb, FMT(annotation_prefix, " w1"))); + w0.reset(new Fqk_variable(pb, FMT(annotation_prefix, " w0"))); + result.reset(new Fqk_variable(pb, FMT(annotation_prefix, " result"))); + + compute_el_inv.reset(new Fqk_mul_gadget(pb, el, *el_inv, *one, FMT(annotation_prefix, " compute_el_inv"))); + compute_el_q_3_minus_1.reset(new Fqk_mul_gadget(pb, *el_q_3, *el_inv, *el_q_3_minus_1, FMT(annotation_prefix, " compute_el_q_3_minus_1"))); + compute_beta.reset(new Fqk_mul_gadget(pb, *alpha, *el_q_3_minus_1, *beta, FMT(annotation_prefix, " compute_beta"))); + + compute_el_inv_q_3_minus_1.reset(new Fqk_mul_gadget(pb, *el_inv_q_3, el, *el_inv_q_3_minus_1, FMT(annotation_prefix, " compute_el_inv__q_3_minus_1"))); + compute_inv_beta.reset(new Fqk_mul_gadget(pb, *inv_alpha, *el_inv_q_3_minus_1, *inv_beta, FMT(annotation_prefix, " compute_inv_beta"))); + + compute_w1.reset(new exponentiation_gadget, Fp6_variable, Fp6_mul_gadget, Fp6_cyclotomic_sqr_gadget, mnt6_q_limbs>( + pb, *beta_q, mnt6_final_exponent_last_chunk_w1, *w1, FMT(annotation_prefix, " compute_w1"))); + + compute_w0.reset(new exponentiation_gadget, Fp6_variable, Fp6_mul_gadget, Fp6_cyclotomic_sqr_gadget, mnt6_q_limbs>( + pb, (mnt6_final_exponent_last_chunk_is_w0_neg ? *inv_beta : *beta), mnt6_final_exponent_last_chunk_abs_of_w0, *w0, FMT(annotation_prefix, " compute_w0"))); + + compute_result.reset(new Fqk_mul_gadget(pb, *w1, *w0, *result, FMT(annotation_prefix, " compute_result"))); +} + +template +void mnt4_final_exp_gadget::generate_r1cs_constraints() +{ + one->generate_r1cs_equals_const_constraints(Fqk >::one()); + + compute_el_inv->generate_r1cs_constraints(); + compute_el_q_3_minus_1->generate_r1cs_constraints(); + compute_beta->generate_r1cs_constraints(); + + compute_el_inv_q_3_minus_1->generate_r1cs_constraints(); + compute_inv_beta->generate_r1cs_constraints(); + + compute_w0->generate_r1cs_constraints(); + compute_w1->generate_r1cs_constraints(); + compute_result->generate_r1cs_constraints(); + + generate_boolean_r1cs_constraint(this->pb, result_is_one, FMT(this->annotation_prefix, " result_is_one")); + this->pb.add_r1cs_constraint(r1cs_constraint(result_is_one, 1 - result->c0.c0, 0), " check c0.c0"); + this->pb.add_r1cs_constraint(r1cs_constraint(result_is_one, result->c0.c1, 0), " check c0.c1"); + this->pb.add_r1cs_constraint(r1cs_constraint(result_is_one, result->c0.c2, 0), " check c0.c2"); + this->pb.add_r1cs_constraint(r1cs_constraint(result_is_one, result->c1.c0, 0), " check c1.c0"); + this->pb.add_r1cs_constraint(r1cs_constraint(result_is_one, result->c1.c1, 0), " check c1.c1"); + this->pb.add_r1cs_constraint(r1cs_constraint(result_is_one, result->c1.c2, 0), " check c1.c2"); +} + +template +void mnt4_final_exp_gadget::generate_r1cs_witness() +{ + one->generate_r1cs_witness(Fqk >::one()); + el_inv->generate_r1cs_witness(el.get_element().inverse()); + + compute_el_inv->generate_r1cs_witness(); + el_q_3->evaluate(); + compute_el_q_3_minus_1->generate_r1cs_witness(); + alpha->evaluate(); + compute_beta->generate_r1cs_witness(); + beta_q->evaluate(); + + el_inv_q_3->evaluate(); + compute_el_inv_q_3_minus_1->generate_r1cs_witness(); + inv_alpha->evaluate(); + compute_inv_beta->generate_r1cs_witness(); + + compute_w0->generate_r1cs_witness(); + compute_w1->generate_r1cs_witness(); + compute_result->generate_r1cs_witness(); + + this->pb.val(result_is_one) = (result->get_element() == one->get_element() ? FieldT::one() : FieldT::zero()); +} + +template +mnt6_final_exp_gadget::mnt6_final_exp_gadget(protoboard &pb, + const Fqk_variable &el, + const pb_variable &result_is_one, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + el(el), + result_is_one(result_is_one) +{ + one.reset(new Fqk_variable(pb, FMT(annotation_prefix, " one"))); + el_inv.reset(new Fqk_variable(pb, FMT(annotation_prefix, " el_inv"))); + el_q_2.reset(new Fqk_variable(el.Frobenius_map(2))); + el_q_2_minus_1.reset(new Fqk_variable(pb, FMT(annotation_prefix, " el_q_2_minus_1"))); + el_q_3_minus_q.reset(new Fqk_variable(el_q_2_minus_1->Frobenius_map(1))); + el_inv_q_2.reset(new Fqk_variable(el_inv->Frobenius_map(2))); + el_inv_q_2_minus_1.reset(new Fqk_variable(pb, FMT(annotation_prefix, " el_inv_q_2_minus_1"))); + w1.reset(new Fqk_variable(pb, FMT(annotation_prefix, " w1"))); + w0.reset(new Fqk_variable(pb, FMT(annotation_prefix, " w0"))); + result.reset(new Fqk_variable(pb, FMT(annotation_prefix, " result"))); + + compute_el_inv.reset(new Fqk_mul_gadget(pb, el, *el_inv, *one, FMT(annotation_prefix, " compute_el_inv"))); + compute_el_q_2_minus_1.reset(new Fqk_mul_gadget(pb, *el_q_2, *el_inv, *el_q_2_minus_1, FMT(annotation_prefix, " compute_el_q_2_minus_1"))); + compute_el_inv_q_2_minus_1.reset(new Fqk_mul_gadget(pb, *el_inv_q_2, el, *el_inv_q_2_minus_1, FMT(annotation_prefix, " compute_el_inv_q_2_minus_1"))); + + compute_w1.reset(new exponentiation_gadget, Fp4_variable, Fp4_mul_gadget, Fp4_cyclotomic_sqr_gadget, mnt4_q_limbs>( + pb, *el_q_3_minus_q, mnt4_final_exponent_last_chunk_w1, *w1, FMT(annotation_prefix, " compute_w1"))); + compute_w0.reset(new exponentiation_gadget, Fp4_variable, Fp4_mul_gadget, Fp4_cyclotomic_sqr_gadget, mnt4_q_limbs>( + pb, (mnt4_final_exponent_last_chunk_is_w0_neg ? *el_inv_q_2_minus_1 : *el_q_2_minus_1), mnt4_final_exponent_last_chunk_abs_of_w0, *w0, FMT(annotation_prefix, " compute_w0"))); + compute_result.reset(new Fqk_mul_gadget(pb, *w1, *w0, *result, FMT(annotation_prefix, " compute_result"))); +} + +template +void mnt6_final_exp_gadget::generate_r1cs_constraints() +{ + one->generate_r1cs_equals_const_constraints(Fqk >::one()); + + compute_el_inv->generate_r1cs_constraints(); + compute_el_q_2_minus_1->generate_r1cs_constraints(); + compute_el_inv_q_2_minus_1->generate_r1cs_constraints(); + compute_w1->generate_r1cs_constraints(); + compute_w0->generate_r1cs_constraints(); + compute_result->generate_r1cs_constraints(); + + generate_boolean_r1cs_constraint(this->pb, result_is_one, FMT(this->annotation_prefix, " result_is_one")); + this->pb.add_r1cs_constraint(r1cs_constraint(result_is_one, 1 - result->c0.c0, 0), " check c0.c0"); + this->pb.add_r1cs_constraint(r1cs_constraint(result_is_one, result->c0.c1, 0), " check c0.c1"); + this->pb.add_r1cs_constraint(r1cs_constraint(result_is_one, result->c1.c0, 0), " check c1.c0"); + this->pb.add_r1cs_constraint(r1cs_constraint(result_is_one, result->c1.c1, 0), " check c1.c0"); +} + +template +void mnt6_final_exp_gadget::generate_r1cs_witness() +{ + one->generate_r1cs_witness(Fqk >::one()); + el_inv->generate_r1cs_witness(el.get_element().inverse()); + + compute_el_inv->generate_r1cs_witness(); + el_q_2->evaluate(); + compute_el_q_2_minus_1->generate_r1cs_witness(); + el_q_3_minus_q->evaluate(); + el_inv_q_2->evaluate(); + compute_el_inv_q_2_minus_1->generate_r1cs_witness(); + compute_w1->generate_r1cs_witness(); + compute_w0->generate_r1cs_witness(); + compute_result->generate_r1cs_witness(); + + this->pb.val(result_is_one) = (result->get_element() == one->get_element() ? FieldT::one() : FieldT::zero()); +} + +} // libsnark + +#endif // WEIERSTRASS_FINAL_EXPONENTIATION_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/weierstrass_miller_loop.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/weierstrass_miller_loop.hpp new file mode 100644 index 0000000..c2915b3 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/weierstrass_miller_loop.hpp @@ -0,0 +1,256 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for gadgets for Miller loops. + + The gadgets verify computations of (single or multiple simultaneous) Miller loops. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WEIERSTRASS_MILLER_LOOP_HPP_ +#define WEIERSTRASS_MILLER_LOOP_HPP_ + +#include +#include "gadgetlib1/gadgets/pairing/pairing_params.hpp" +#include "gadgetlib1/gadgets/pairing/weierstrass_precomputation.hpp" + +namespace libsnark { + +/** + * Gadget for doubling step in the Miller loop. + * + * Technical note: + * + * mnt_Fqk g_RR_at_P = mnt_Fqk(prec_P.PY_twist_squared, + * -prec_P.PX * c.gamma_twist + c.gamma_X - c.old_RY); + * + *(later in Miller loop: f = f.squared() * g_RR_at_P) + * + * Note the slight interface change: this gadget allocates g_RR_at_P inside itself (!) + */ +template +class mnt_miller_loop_dbl_line_eval : public gadget > { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + G1_precomputation prec_P; + precompute_G2_gadget_coeffs c; + std::shared_ptr > &g_RR_at_P; // reference from outside + + std::shared_ptr > gamma_twist; + std::shared_ptr > g_RR_at_P_c1; + std::shared_ptr > compute_g_RR_at_P_c1; + + mnt_miller_loop_dbl_line_eval(protoboard &pb, + const G1_precomputation &prec_P, + const precompute_G2_gadget_coeffs &c, + std::shared_ptr > &g_RR_at_P, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget for addition step in the Miller loop. + * + * Technical note: + * + * mnt_Fqk g_RQ_at_P = mnt_Fqk(prec_P.PY_twist_squared, + * -prec_P.PX * c.gamma_twist + c.gamma_X - prec_Q.QY); + * + * (later in Miller loop: f = f * g_RQ_at_P) + * + * Note the slight interface change: this gadget will allocate g_RQ_at_P inside itself (!) + */ +template +class mnt_miller_loop_add_line_eval : public gadget > { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + bool invert_Q; + G1_precomputation prec_P; + precompute_G2_gadget_coeffs c; + G2_variable Q; + std::shared_ptr > &g_RQ_at_P; // reference from outside + + std::shared_ptr > gamma_twist; + std::shared_ptr > g_RQ_at_P_c1; + std::shared_ptr > compute_g_RQ_at_P_c1; + + mnt_miller_loop_add_line_eval(protoboard &pb, + const bool invert_Q, + const G1_precomputation &prec_P, + const precompute_G2_gadget_coeffs &c, + const G2_variable &Q, + std::shared_ptr > &g_RQ_at_P, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget for verifying a single Miller loop. + */ +template +class mnt_miller_loop_gadget : public gadget > { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + std::vector > > g_RR_at_Ps; + std::vector > > g_RQ_at_Ps; + std::vector > > fs; + + std::vector > > addition_steps; + std::vector > > doubling_steps; + + std::vector > > dbl_muls; + std::vector > > dbl_sqrs; + std::vector > > add_muls; + + size_t f_count; + size_t add_count; + size_t dbl_count; + + G1_precomputation prec_P; + G2_precomputation prec_Q; + Fqk_variable result; + + mnt_miller_loop_gadget(protoboard &pb, + const G1_precomputation &prec_P, + const G2_precomputation &prec_Q, + const Fqk_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_mnt_miller_loop(const std::string &annotation); + +/** + * Gadget for verifying a double Miller loop (where the second is inverted). + */ +template +class mnt_e_over_e_miller_loop_gadget : public gadget > { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + std::vector > > g_RR_at_P1s; + std::vector > > g_RQ_at_P1s; + std::vector > > g_RR_at_P2s; + std::vector > > g_RQ_at_P2s; + std::vector > > fs; + + std::vector > > addition_steps1; + std::vector > > doubling_steps1; + std::vector > > addition_steps2; + std::vector > > doubling_steps2; + + std::vector > > dbl_sqrs; + std::vector > > dbl_muls1; + std::vector > > add_muls1; + std::vector > > dbl_muls2; + std::vector > > add_muls2; + + size_t f_count; + size_t add_count; + size_t dbl_count; + + G1_precomputation prec_P1; + G2_precomputation prec_Q1; + G1_precomputation prec_P2; + G2_precomputation prec_Q2; + Fqk_variable result; + + mnt_e_over_e_miller_loop_gadget(protoboard &pb, + const G1_precomputation &prec_P1, + const G2_precomputation &prec_Q1, + const G1_precomputation &prec_P2, + const G2_precomputation &prec_Q2, + const Fqk_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_mnt_e_over_e_miller_loop(const std::string &annotation); + +/** + * Gadget for verifying a triple Miller loop (where the third is inverted). + */ +template +class mnt_e_times_e_over_e_miller_loop_gadget : public gadget > { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + std::vector > > g_RR_at_P1s; + std::vector > > g_RQ_at_P1s; + std::vector > > g_RR_at_P2s; + std::vector > > g_RQ_at_P2s; + std::vector > > g_RR_at_P3s; + std::vector > > g_RQ_at_P3s; + std::vector > > fs; + + std::vector > > addition_steps1; + std::vector > > doubling_steps1; + std::vector > > addition_steps2; + std::vector > > doubling_steps2; + std::vector > > addition_steps3; + std::vector > > doubling_steps3; + + std::vector > > dbl_sqrs; + std::vector > > dbl_muls1; + std::vector > > add_muls1; + std::vector > > dbl_muls2; + std::vector > > add_muls2; + std::vector > > dbl_muls3; + std::vector > > add_muls3; + + size_t f_count; + size_t add_count; + size_t dbl_count; + + G1_precomputation prec_P1; + G2_precomputation prec_Q1; + G1_precomputation prec_P2; + G2_precomputation prec_Q2; + G1_precomputation prec_P3; + G2_precomputation prec_Q3; + Fqk_variable result; + + mnt_e_times_e_over_e_miller_loop_gadget(protoboard &pb, + const G1_precomputation &prec_P1, + const G2_precomputation &prec_Q1, + const G1_precomputation &prec_P2, + const G2_precomputation &prec_Q2, + const G1_precomputation &prec_P3, + const G2_precomputation &prec_Q3, + const Fqk_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_mnt_e_times_e_over_e_miller_loop(const std::string &annotation); + +} // libsnark + +#include "gadgetlib1/gadgets/pairing/weierstrass_miller_loop.tcc" + +#endif // WEIERSTRASS_MILLER_LOOP_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/weierstrass_miller_loop.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/weierstrass_miller_loop.tcc new file mode 100644 index 0000000..45afab3 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/weierstrass_miller_loop.tcc @@ -0,0 +1,900 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for gadgets for Miller loops. + + See weierstrass_miller_loop.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WEIERSTRASS_MILLER_LOOP_TCC_ +#define WEIERSTRASS_MILLER_LOOP_TCC_ + +#include "algebra/scalar_multiplication/wnaf.hpp" +#include "gadgetlib1/constraint_profiling.hpp" +#include "gadgetlib1/gadgets/basic_gadgets.hpp" + +namespace libsnark { + +/* + performs + + mnt_Fqk g_RR_at_P = mnt_Fqk(prec_P.PY_twist_squared, + -prec_P.PX * c.gamma_twist + c.gamma_X - c.old_RY); + + (later in Miller loop: f = f.squared() * g_RR_at_P) +*/ + +/* Note the slight interface change: this gadget will allocate g_RR_at_P inside itself (!) */ +template +mnt_miller_loop_dbl_line_eval::mnt_miller_loop_dbl_line_eval(protoboard &pb, + const G1_precomputation &prec_P, + const precompute_G2_gadget_coeffs &c, + std::shared_ptr > &g_RR_at_P, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), prec_P(prec_P), c(c), g_RR_at_P(g_RR_at_P) +{ + gamma_twist.reset(new Fqe_variable(c.gamma->mul_by_X())); + // prec_P.PX * c.gamma_twist = c.gamma_X - c.old_RY - g_RR_at_P_c1 + if (gamma_twist->is_constant()) + { + gamma_twist->evaluate(); + const FqeT gamma_twist_const = gamma_twist->get_element(); + g_RR_at_P_c1.reset(new Fqe_variable(Fqe_variable(this->pb, -gamma_twist_const, prec_P.P->X, FMT(annotation_prefix, " tmp")) + + *(c.gamma_X) + *(c.RY) * (-FieldT::one()))); + } + else if (prec_P.P->X.is_constant()) + { + prec_P.P->X.evaluate(pb); + const FieldT P_X_const = prec_P.P->X.constant_term(); + g_RR_at_P_c1.reset(new Fqe_variable(*gamma_twist * (-P_X_const) + *(c.gamma_X) + *(c.RY) * (-FieldT::one()))); + } + else + { + g_RR_at_P_c1.reset(new Fqe_variable(pb, FMT(annotation_prefix, " g_RR_at_P_c1"))); + compute_g_RR_at_P_c1.reset(new Fqe_mul_by_lc_gadget(pb, *gamma_twist, prec_P.P->X, + *(c.gamma_X) + *(c.RY) * (-FieldT::one()) + (*g_RR_at_P_c1) * (-FieldT::one()), + FMT(annotation_prefix, " compute_g_RR_at_P_c1"))); + } + g_RR_at_P.reset(new Fqk_variable(pb, *(prec_P.PY_twist_squared), *g_RR_at_P_c1, FMT(annotation_prefix, " g_RR_at_P"))); +} + +template +void mnt_miller_loop_dbl_line_eval::generate_r1cs_constraints() +{ + if (!gamma_twist->is_constant() && !prec_P.P->X.is_constant()) + { + compute_g_RR_at_P_c1->generate_r1cs_constraints(); + } +} + +template +void mnt_miller_loop_dbl_line_eval::generate_r1cs_witness() +{ + gamma_twist->evaluate(); + const FqeT gamma_twist_val = gamma_twist->get_element(); + const FieldT PX_val = this->pb.lc_val(prec_P.P->X); + const FqeT gamma_X_val = c.gamma_X->get_element(); + const FqeT RY_val = c.RY->get_element(); + const FqeT g_RR_at_P_c1_val = -PX_val * gamma_twist_val + gamma_X_val - RY_val; + g_RR_at_P_c1->generate_r1cs_witness(g_RR_at_P_c1_val); + + if (!gamma_twist->is_constant() && !prec_P.P->X.is_constant()) + { + compute_g_RR_at_P_c1->generate_r1cs_witness(); + } + g_RR_at_P->evaluate(); +} + +/* + performs + mnt_Fqk g_RQ_at_P = mnt_Fqk(prec_P.PY_twist_squared, + -prec_P.PX * c.gamma_twist + c.gamma_X - prec_Q.QY); + + (later in Miller loop: f = f * g_RQ_at_P) + + If invert_Q is set to true: use -QY in place of QY everywhere above. +*/ + +/* Note the slight interface change: this gadget will allocate g_RQ_at_P inside itself (!) */ +template +mnt_miller_loop_add_line_eval::mnt_miller_loop_add_line_eval(protoboard &pb, + const bool invert_Q, + const G1_precomputation &prec_P, + const precompute_G2_gadget_coeffs &c, + const G2_variable &Q, + std::shared_ptr > &g_RQ_at_P, + const std::string &annotation_prefix) : +gadget(pb, annotation_prefix), invert_Q(invert_Q), prec_P(prec_P), c(c), Q(Q), g_RQ_at_P(g_RQ_at_P) +{ + gamma_twist.reset(new Fqe_variable(c.gamma->mul_by_X())); + // prec_P.PX * c.gamma_twist = c.gamma_X - prec_Q.QY - g_RQ_at_P_c1 + if (gamma_twist->is_constant()) + { + gamma_twist->evaluate(); + const FqeT gamma_twist_const = gamma_twist->get_element(); + g_RQ_at_P_c1.reset(new Fqe_variable(Fqe_variable(this->pb, -gamma_twist_const, prec_P.P->X, FMT(annotation_prefix, " tmp")) + + *(c.gamma_X) + *(Q.Y) * (!invert_Q ? -FieldT::one() : FieldT::one()))); + } + else if (prec_P.P->X.is_constant()) + { + prec_P.P->X.evaluate(pb); + const FieldT P_X_const = prec_P.P->X.constant_term(); + g_RQ_at_P_c1.reset(new Fqe_variable(*gamma_twist * (-P_X_const) + *(c.gamma_X) + *(Q.Y) * (!invert_Q ? -FieldT::one() : FieldT::one()))); + } + else + { + g_RQ_at_P_c1.reset(new Fqe_variable(pb, FMT(annotation_prefix, " g_RQ_at_Q_c1"))); + compute_g_RQ_at_P_c1.reset(new Fqe_mul_by_lc_gadget(pb, *gamma_twist, prec_P.P->X, + *(c.gamma_X) + *(Q.Y) * (!invert_Q ? -FieldT::one() : FieldT::one()) + (*g_RQ_at_P_c1) * (-FieldT::one()), + FMT(annotation_prefix, " compute_g_RQ_at_P_c1"))); + } + g_RQ_at_P.reset(new Fqk_variable(pb, *(prec_P.PY_twist_squared), *g_RQ_at_P_c1, FMT(annotation_prefix, " g_RQ_at_P"))); +} + +template +void mnt_miller_loop_add_line_eval::generate_r1cs_constraints() +{ + if (!gamma_twist->is_constant() && !prec_P.P->X.is_constant()) + { + compute_g_RQ_at_P_c1->generate_r1cs_constraints(); + } +} + +template +void mnt_miller_loop_add_line_eval::generate_r1cs_witness() +{ + gamma_twist->evaluate(); + const FqeT gamma_twist_val = gamma_twist->get_element(); + const FieldT PX_val = this->pb.lc_val(prec_P.P->X); + const FqeT gamma_X_val = c.gamma_X->get_element(); + const FqeT QY_val = Q.Y->get_element(); + const FqeT g_RQ_at_P_c1_val = -PX_val * gamma_twist_val + gamma_X_val + (!invert_Q ? -QY_val : QY_val); + g_RQ_at_P_c1->generate_r1cs_witness(g_RQ_at_P_c1_val); + + if (!gamma_twist->is_constant() && !prec_P.P->X.is_constant()) + { + compute_g_RQ_at_P_c1->generate_r1cs_witness(); + } + g_RQ_at_P->evaluate(); +} + +template +mnt_miller_loop_gadget::mnt_miller_loop_gadget(protoboard &pb, + const G1_precomputation &prec_P, + const G2_precomputation &prec_Q, + const Fqk_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), prec_P(prec_P), prec_Q(prec_Q), result(result) +{ + const auto &loop_count = pairing_selector::pairing_loop_count; + + f_count = add_count = dbl_count = 0; + + bool found_nonzero = false; + std::vector NAF = find_wnaf(1, loop_count); + for (long i = NAF.size()-1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + ++dbl_count; + f_count += 2; + + if (NAF[i] != 0) + { + ++add_count; + f_count += 1; + } + } + + fs.resize(f_count); + doubling_steps.resize(dbl_count); + addition_steps.resize(add_count); + g_RR_at_Ps.resize(dbl_count); + g_RQ_at_Ps.resize(add_count); + + for (size_t i = 0; i < f_count; ++i) + { + fs[i].reset(new Fqk_variable(pb, FMT(annotation_prefix, " fs_%zu", i))); + } + + dbl_sqrs.resize(dbl_count); + dbl_muls.resize(dbl_count); + add_muls.resize(add_count); + + size_t add_id = 0; + size_t dbl_id = 0; + size_t f_id = 0; + size_t prec_id = 0; + + found_nonzero = false; + for (long i = NAF.size()-1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + doubling_steps[dbl_id].reset(new mnt_miller_loop_dbl_line_eval(pb, + prec_P, *prec_Q.coeffs[prec_id], + g_RR_at_Ps[dbl_id], + FMT(annotation_prefix, " doubling_steps_%zu", dbl_id))); + ++prec_id; + dbl_sqrs[dbl_id].reset(new Fqk_sqr_gadget(pb, *fs[f_id], *fs[f_id+1], FMT(annotation_prefix, " dbl_sqrs_%zu", dbl_id))); + ++f_id; + dbl_muls[dbl_id].reset(new Fqk_special_mul_gadget(pb, *fs[f_id], *g_RR_at_Ps[dbl_id], (f_id + 1 == f_count ? result : *fs[f_id+1]), FMT(annotation_prefix, " dbl_muls_%zu", dbl_id))); + ++f_id; + ++dbl_id; + + if (NAF[i] != 0) + { + addition_steps[add_id].reset(new mnt_miller_loop_add_line_eval(pb, + NAF[i] < 0, + prec_P, *prec_Q.coeffs[prec_id], *prec_Q.Q, + g_RQ_at_Ps[add_id], + FMT(annotation_prefix, " addition_steps_%zu", add_id))); + ++prec_id; + add_muls[add_id].reset(new Fqk_special_mul_gadget(pb, *fs[f_id], *g_RQ_at_Ps[add_id], (f_id + 1 == f_count ? result : *fs[f_id+1]), FMT(annotation_prefix, " add_muls_%zu", add_id))); + ++f_id; + ++add_id; + } + } +} + +template +void mnt_miller_loop_gadget::generate_r1cs_constraints() +{ + fs[0]->generate_r1cs_equals_const_constraints(FqkT::one()); + + for (size_t i = 0; i < dbl_count; ++i) + { + doubling_steps[i]->generate_r1cs_constraints(); + dbl_sqrs[i]->generate_r1cs_constraints(); + dbl_muls[i]->generate_r1cs_constraints(); + } + + for (size_t i = 0; i < add_count; ++i) + { + addition_steps[i]->generate_r1cs_constraints(); + add_muls[i]->generate_r1cs_constraints(); + } +} + +template +void mnt_miller_loop_gadget::generate_r1cs_witness() +{ + fs[0]->generate_r1cs_witness(FqkT::one()); + + size_t add_id = 0; + size_t dbl_id = 0; + + const auto &loop_count = pairing_selector::pairing_loop_count; + + bool found_nonzero = false; + std::vector NAF = find_wnaf(1, loop_count); + for (long i = NAF.size()-1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + doubling_steps[dbl_id]->generate_r1cs_witness(); + dbl_sqrs[dbl_id]->generate_r1cs_witness(); + dbl_muls[dbl_id]->generate_r1cs_witness(); + ++dbl_id; + + if (NAF[i] != 0) + { + addition_steps[add_id]->generate_r1cs_witness(); + add_muls[add_id]->generate_r1cs_witness(); + ++add_id; + } + } +} + +template +void test_mnt_miller_loop(const std::string &annotation) +{ + protoboard > pb; + G1 > P_val = Fr >::random_element() * G1 >::one(); + G2 > Q_val = Fr >::random_element() * G2 >::one(); + + G1_variable P(pb, "P"); + G2_variable Q(pb, "Q"); + + G1_precomputation prec_P; + G2_precomputation prec_Q; + + precompute_G1_gadget compute_prec_P(pb, P, prec_P, "prec_P"); + precompute_G2_gadget compute_prec_Q(pb, Q, prec_Q, "prec_Q"); + + Fqk_variable result(pb, "result"); + mnt_miller_loop_gadget miller(pb, prec_P, prec_Q, result, "miller"); + + PROFILE_CONSTRAINTS(pb, "precompute P") + { + compute_prec_P.generate_r1cs_constraints(); + } + PROFILE_CONSTRAINTS(pb, "precompute Q") + { + compute_prec_Q.generate_r1cs_constraints(); + } + PROFILE_CONSTRAINTS(pb, "Miller loop") + { + miller.generate_r1cs_constraints(); + } + PRINT_CONSTRAINT_PROFILING(); + + P.generate_r1cs_witness(P_val); + compute_prec_P.generate_r1cs_witness(); + Q.generate_r1cs_witness(Q_val); + compute_prec_Q.generate_r1cs_witness(); + miller.generate_r1cs_witness(); + assert(pb.is_satisfied()); + + affine_ate_G1_precomp > native_prec_P = other_curve::affine_ate_precompute_G1(P_val); + affine_ate_G2_precomp > native_prec_Q = other_curve::affine_ate_precompute_G2(Q_val); + Fqk > native_result = other_curve::affine_ate_miller_loop(native_prec_P, native_prec_Q); + + assert(result.get_element() == native_result); + printf("number of constraints for Miller loop (Fr is %s) = %zu\n", annotation.c_str(), pb.num_constraints()); +} + +template +mnt_e_over_e_miller_loop_gadget::mnt_e_over_e_miller_loop_gadget(protoboard &pb, + const G1_precomputation &prec_P1, + const G2_precomputation &prec_Q1, + const G1_precomputation &prec_P2, + const G2_precomputation &prec_Q2, + const Fqk_variable &result, + const std::string &annotation_prefix) : +gadget(pb, annotation_prefix), prec_P1(prec_P1), prec_Q1(prec_Q1), prec_P2(prec_P2), prec_Q2(prec_Q2), result(result) +{ + const auto &loop_count = pairing_selector::pairing_loop_count; + + f_count = add_count = dbl_count = 0; + + bool found_nonzero = false; + std::vector NAF = find_wnaf(1, loop_count); + for (long i = NAF.size()-1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + ++dbl_count; + f_count += 3; + + if (NAF[i] != 0) + { + ++add_count; + f_count += 2; + } + } + + fs.resize(f_count); + doubling_steps1.resize(dbl_count); + addition_steps1.resize(add_count); + doubling_steps2.resize(dbl_count); + addition_steps2.resize(add_count); + g_RR_at_P1s.resize(dbl_count); + g_RQ_at_P1s.resize(add_count); + g_RR_at_P2s.resize(dbl_count); + g_RQ_at_P2s.resize(add_count); + + for (size_t i = 0; i < f_count; ++i) + { + fs[i].reset(new Fqk_variable(pb, FMT(annotation_prefix, " fs_%zu", i))); + } + + dbl_sqrs.resize(dbl_count); + dbl_muls1.resize(dbl_count); + add_muls1.resize(add_count); + dbl_muls2.resize(dbl_count); + add_muls2.resize(add_count); + + size_t add_id = 0; + size_t dbl_id = 0; + size_t f_id = 0; + size_t prec_id = 0; + + found_nonzero = false; + for (long i = NAF.size()-1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + doubling_steps1[dbl_id].reset(new mnt_miller_loop_dbl_line_eval(pb, + prec_P1, *prec_Q1.coeffs[prec_id], + g_RR_at_P1s[dbl_id], + FMT(annotation_prefix, " doubling_steps1_%zu", dbl_id))); + doubling_steps2[dbl_id].reset(new mnt_miller_loop_dbl_line_eval(pb, + prec_P2, *prec_Q2.coeffs[prec_id], + g_RR_at_P2s[dbl_id], + FMT(annotation_prefix, " doubling_steps2_%zu", dbl_id))); + ++prec_id; + + dbl_sqrs[dbl_id].reset(new Fqk_sqr_gadget(pb, *fs[f_id], *fs[f_id+1], FMT(annotation_prefix, " dbl_sqrs_%zu", dbl_id))); + ++f_id; + dbl_muls1[dbl_id].reset(new Fqk_special_mul_gadget(pb, *fs[f_id], *g_RR_at_P1s[dbl_id], *fs[f_id+1], FMT(annotation_prefix, " dbl_mul1s_%zu", dbl_id))); + ++f_id; + dbl_muls2[dbl_id].reset(new Fqk_special_mul_gadget(pb, (f_id + 1 == f_count ? result : *fs[f_id+1]), *g_RR_at_P2s[dbl_id], *fs[f_id], FMT(annotation_prefix, " dbl_mul2s_%zu", dbl_id))); + ++f_id; + ++dbl_id; + + if (NAF[i] != 0) + { + addition_steps1[add_id].reset(new mnt_miller_loop_add_line_eval(pb, + NAF[i] < 0, + prec_P1, *prec_Q1.coeffs[prec_id], *prec_Q1.Q, + g_RQ_at_P1s[add_id], + FMT(annotation_prefix, " addition_steps1_%zu", add_id))); + addition_steps2[add_id].reset(new mnt_miller_loop_add_line_eval(pb, + NAF[i] < 0, + prec_P2, *prec_Q2.coeffs[prec_id], *prec_Q2.Q, + g_RQ_at_P2s[add_id], + FMT(annotation_prefix, " addition_steps2_%zu", add_id))); + ++prec_id; + add_muls1[add_id].reset(new Fqk_special_mul_gadget(pb, *fs[f_id], *g_RQ_at_P1s[add_id], *fs[f_id+1], FMT(annotation_prefix, " add_mul1s_%zu", add_id))); + ++f_id; + add_muls2[add_id].reset(new Fqk_special_mul_gadget(pb, (f_id + 1 == f_count ? result : *fs[f_id+1]), *g_RQ_at_P2s[add_id], *fs[f_id], FMT(annotation_prefix, " add_mul2s_%zu", add_id))); + ++f_id; + ++add_id; + } + } +} + +template +void mnt_e_over_e_miller_loop_gadget::generate_r1cs_constraints() +{ + fs[0]->generate_r1cs_equals_const_constraints(FqkT::one()); + + for (size_t i = 0; i < dbl_count; ++i) + { + doubling_steps1[i]->generate_r1cs_constraints(); + doubling_steps2[i]->generate_r1cs_constraints(); + dbl_sqrs[i]->generate_r1cs_constraints(); + dbl_muls1[i]->generate_r1cs_constraints(); + dbl_muls2[i]->generate_r1cs_constraints(); + } + + for (size_t i = 0; i < add_count; ++i) + { + addition_steps1[i]->generate_r1cs_constraints(); + addition_steps2[i]->generate_r1cs_constraints(); + add_muls1[i]->generate_r1cs_constraints(); + add_muls2[i]->generate_r1cs_constraints(); + } +} + +template +void mnt_e_over_e_miller_loop_gadget::generate_r1cs_witness() +{ + fs[0]->generate_r1cs_witness(FqkT::one()); + + size_t add_id = 0; + size_t dbl_id = 0; + size_t f_id = 0; + + const auto &loop_count = pairing_selector::pairing_loop_count; + + bool found_nonzero = false; + std::vector NAF = find_wnaf(1, loop_count); + for (long i = NAF.size()-1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + doubling_steps1[dbl_id]->generate_r1cs_witness(); + doubling_steps2[dbl_id]->generate_r1cs_witness(); + dbl_sqrs[dbl_id]->generate_r1cs_witness(); + ++f_id; + dbl_muls1[dbl_id]->generate_r1cs_witness(); + ++f_id; + (f_id+1 == f_count ? result : *fs[f_id+1]).generate_r1cs_witness(fs[f_id]->get_element() * g_RR_at_P2s[dbl_id]->get_element().inverse()); + dbl_muls2[dbl_id]->generate_r1cs_witness(); + ++f_id; + ++dbl_id; + + if (NAF[i] != 0) + { + addition_steps1[add_id]->generate_r1cs_witness(); + addition_steps2[add_id]->generate_r1cs_witness(); + add_muls1[add_id]->generate_r1cs_witness(); + ++f_id; + (f_id+1 == f_count ? result : *fs[f_id+1]).generate_r1cs_witness(fs[f_id]->get_element() * g_RQ_at_P2s[add_id]->get_element().inverse()); + add_muls2[add_id]->generate_r1cs_witness(); + ++f_id; + ++add_id; + } + } +} + +template +void test_mnt_e_over_e_miller_loop(const std::string &annotation) +{ + protoboard > pb; + G1 > P1_val = Fr >::random_element() * G1 >::one(); + G2 > Q1_val = Fr >::random_element() * G2 >::one(); + + G1 > P2_val = Fr >::random_element() * G1 >::one(); + G2 > Q2_val = Fr >::random_element() * G2 >::one(); + + G1_variable P1(pb, "P1"); + G2_variable Q1(pb, "Q1"); + G1_variable P2(pb, "P2"); + G2_variable Q2(pb, "Q2"); + + G1_precomputation prec_P1; + precompute_G1_gadget compute_prec_P1(pb, P1, prec_P1, "compute_prec_P1"); + G1_precomputation prec_P2; + precompute_G1_gadget compute_prec_P2(pb, P2, prec_P2, "compute_prec_P2"); + G2_precomputation prec_Q1; + precompute_G2_gadget compute_prec_Q1(pb, Q1, prec_Q1, "compute_prec_Q1"); + G2_precomputation prec_Q2; + precompute_G2_gadget compute_prec_Q2(pb, Q2, prec_Q2, "compute_prec_Q2"); + + Fqk_variable result(pb, "result"); + mnt_e_over_e_miller_loop_gadget miller(pb, prec_P1, prec_Q1, prec_P2, prec_Q2, result, "miller"); + + PROFILE_CONSTRAINTS(pb, "precompute P") + { + compute_prec_P1.generate_r1cs_constraints(); + compute_prec_P2.generate_r1cs_constraints(); + } + PROFILE_CONSTRAINTS(pb, "precompute Q") + { + compute_prec_Q1.generate_r1cs_constraints(); + compute_prec_Q2.generate_r1cs_constraints(); + } + PROFILE_CONSTRAINTS(pb, "Miller loop") + { + miller.generate_r1cs_constraints(); + } + PRINT_CONSTRAINT_PROFILING(); + + P1.generate_r1cs_witness(P1_val); + compute_prec_P1.generate_r1cs_witness(); + Q1.generate_r1cs_witness(Q1_val); + compute_prec_Q1.generate_r1cs_witness(); + P2.generate_r1cs_witness(P2_val); + compute_prec_P2.generate_r1cs_witness(); + Q2.generate_r1cs_witness(Q2_val); + compute_prec_Q2.generate_r1cs_witness(); + miller.generate_r1cs_witness(); + assert(pb.is_satisfied()); + + affine_ate_G1_precomp > native_prec_P1 = other_curve::affine_ate_precompute_G1(P1_val); + affine_ate_G2_precomp > native_prec_Q1 = other_curve::affine_ate_precompute_G2(Q1_val); + affine_ate_G1_precomp > native_prec_P2 = other_curve::affine_ate_precompute_G1(P2_val); + affine_ate_G2_precomp > native_prec_Q2 = other_curve::affine_ate_precompute_G2(Q2_val); + Fqk > native_result = (other_curve::affine_ate_miller_loop(native_prec_P1, native_prec_Q1) * + other_curve::affine_ate_miller_loop(native_prec_P2, native_prec_Q2).inverse()); + + assert(result.get_element() == native_result); + printf("number of constraints for e over e Miller loop (Fr is %s) = %zu\n", annotation.c_str(), pb.num_constraints()); +} + +template +mnt_e_times_e_over_e_miller_loop_gadget::mnt_e_times_e_over_e_miller_loop_gadget(protoboard &pb, + const G1_precomputation &prec_P1, + const G2_precomputation &prec_Q1, + const G1_precomputation &prec_P2, + const G2_precomputation &prec_Q2, + const G1_precomputation &prec_P3, + const G2_precomputation &prec_Q3, + const Fqk_variable &result, + const std::string &annotation_prefix) : +gadget(pb, annotation_prefix), prec_P1(prec_P1), prec_Q1(prec_Q1), prec_P2(prec_P2), prec_Q2(prec_Q2), prec_P3(prec_P3), prec_Q3(prec_Q3), result(result) +{ + const auto &loop_count = pairing_selector::pairing_loop_count; + + f_count = add_count = dbl_count = 0; + + bool found_nonzero = false; + std::vector NAF = find_wnaf(1, loop_count); + for (long i = NAF.size()-1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + ++dbl_count; + f_count += 4; + + if (NAF[i] != 0) + { + ++add_count; + f_count += 3; + } + } + + fs.resize(f_count); + doubling_steps1.resize(dbl_count); + addition_steps1.resize(add_count); + doubling_steps2.resize(dbl_count); + addition_steps2.resize(add_count); + doubling_steps3.resize(dbl_count); + addition_steps3.resize(add_count); + g_RR_at_P1s.resize(dbl_count); + g_RQ_at_P1s.resize(add_count); + g_RR_at_P2s.resize(dbl_count); + g_RQ_at_P2s.resize(add_count); + g_RR_at_P3s.resize(dbl_count); + g_RQ_at_P3s.resize(add_count); + + for (size_t i = 0; i < f_count; ++i) + { + fs[i].reset(new Fqk_variable(pb, FMT(annotation_prefix, " fs_%zu", i))); + } + + dbl_sqrs.resize(dbl_count); + dbl_muls1.resize(dbl_count); + add_muls1.resize(add_count); + dbl_muls2.resize(dbl_count); + add_muls2.resize(add_count); + dbl_muls3.resize(dbl_count); + add_muls3.resize(add_count); + + size_t add_id = 0; + size_t dbl_id = 0; + size_t f_id = 0; + size_t prec_id = 0; + + found_nonzero = false; + for (long i = NAF.size()-1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + doubling_steps1[dbl_id].reset(new mnt_miller_loop_dbl_line_eval(pb, + prec_P1, *prec_Q1.coeffs[prec_id], + g_RR_at_P1s[dbl_id], + FMT(annotation_prefix, " doubling_steps1_%zu", dbl_id))); + doubling_steps2[dbl_id].reset(new mnt_miller_loop_dbl_line_eval(pb, + prec_P2, *prec_Q2.coeffs[prec_id], + g_RR_at_P2s[dbl_id], + FMT(annotation_prefix, " doubling_steps2_%zu", dbl_id))); + doubling_steps3[dbl_id].reset(new mnt_miller_loop_dbl_line_eval(pb, + prec_P3, *prec_Q3.coeffs[prec_id], + g_RR_at_P3s[dbl_id], + FMT(annotation_prefix, " doubling_steps3_%zu", dbl_id))); + ++prec_id; + + dbl_sqrs[dbl_id].reset(new Fqk_sqr_gadget(pb, *fs[f_id], *fs[f_id+1], FMT(annotation_prefix, " dbl_sqrs_%zu", dbl_id))); + ++f_id; + dbl_muls1[dbl_id].reset(new Fqk_special_mul_gadget(pb, *fs[f_id], *g_RR_at_P1s[dbl_id], *fs[f_id+1], FMT(annotation_prefix, " dbl_muls1_%zu", dbl_id))); + ++f_id; + dbl_muls2[dbl_id].reset(new Fqk_special_mul_gadget(pb, *fs[f_id], *g_RR_at_P2s[dbl_id], *fs[f_id+1], FMT(annotation_prefix, " dbl_muls2_%zu", dbl_id))); + ++f_id; + dbl_muls3[dbl_id].reset(new Fqk_special_mul_gadget(pb, (f_id + 1 == f_count ? result : *fs[f_id+1]), *g_RR_at_P3s[dbl_id], *fs[f_id], FMT(annotation_prefix, " dbl_muls3_%zu", dbl_id))); + ++f_id; + ++dbl_id; + + if (NAF[i] != 0) + { + addition_steps1[add_id].reset(new mnt_miller_loop_add_line_eval(pb, + NAF[i] < 0, + prec_P1, *prec_Q1.coeffs[prec_id], *prec_Q1.Q, + g_RQ_at_P1s[add_id], + FMT(annotation_prefix, " addition_steps1_%zu", add_id))); + addition_steps2[add_id].reset(new mnt_miller_loop_add_line_eval(pb, + NAF[i] < 0, + prec_P2, *prec_Q2.coeffs[prec_id], *prec_Q2.Q, + g_RQ_at_P2s[add_id], + FMT(annotation_prefix, " addition_steps2_%zu", add_id))); + addition_steps3[add_id].reset(new mnt_miller_loop_add_line_eval(pb, + NAF[i] < 0, + prec_P3, *prec_Q3.coeffs[prec_id], *prec_Q3.Q, + g_RQ_at_P3s[add_id], + FMT(annotation_prefix, " addition_steps3_%zu", add_id))); + ++prec_id; + add_muls1[add_id].reset(new Fqk_special_mul_gadget(pb, *fs[f_id], *g_RQ_at_P1s[add_id], *fs[f_id+1], FMT(annotation_prefix, " add_muls1_%zu", add_id))); + ++f_id; + add_muls2[add_id].reset(new Fqk_special_mul_gadget(pb, *fs[f_id], *g_RQ_at_P2s[add_id], *fs[f_id+1], FMT(annotation_prefix, " add_muls2_%zu", add_id))); + ++f_id; + add_muls3[add_id].reset(new Fqk_special_mul_gadget(pb, (f_id + 1 == f_count ? result : *fs[f_id+1]), *g_RQ_at_P3s[add_id], *fs[f_id], FMT(annotation_prefix, " add_muls3_%zu", add_id))); + ++f_id; + ++add_id; + } + } +} + +template +void mnt_e_times_e_over_e_miller_loop_gadget::generate_r1cs_constraints() +{ + fs[0]->generate_r1cs_equals_const_constraints(FqkT::one()); + + for (size_t i = 0; i < dbl_count; ++i) + { + doubling_steps1[i]->generate_r1cs_constraints(); + doubling_steps2[i]->generate_r1cs_constraints(); + doubling_steps3[i]->generate_r1cs_constraints(); + dbl_sqrs[i]->generate_r1cs_constraints(); + dbl_muls1[i]->generate_r1cs_constraints(); + dbl_muls2[i]->generate_r1cs_constraints(); + dbl_muls3[i]->generate_r1cs_constraints(); + } + + for (size_t i = 0; i < add_count; ++i) + { + addition_steps1[i]->generate_r1cs_constraints(); + addition_steps2[i]->generate_r1cs_constraints(); + addition_steps3[i]->generate_r1cs_constraints(); + add_muls1[i]->generate_r1cs_constraints(); + add_muls2[i]->generate_r1cs_constraints(); + add_muls3[i]->generate_r1cs_constraints(); + } +} + +template +void mnt_e_times_e_over_e_miller_loop_gadget::generate_r1cs_witness() +{ + fs[0]->generate_r1cs_witness(FqkT::one()); + + size_t add_id = 0; + size_t dbl_id = 0; + size_t f_id = 0; + + const auto &loop_count = pairing_selector::pairing_loop_count; + + bool found_nonzero = false; + std::vector NAF = find_wnaf(1, loop_count); + for (long i = NAF.size()-1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + doubling_steps1[dbl_id]->generate_r1cs_witness(); + doubling_steps2[dbl_id]->generate_r1cs_witness(); + doubling_steps3[dbl_id]->generate_r1cs_witness(); + dbl_sqrs[dbl_id]->generate_r1cs_witness(); + ++f_id; + dbl_muls1[dbl_id]->generate_r1cs_witness(); + ++f_id; + dbl_muls2[dbl_id]->generate_r1cs_witness(); + ++f_id; + (f_id+1 == f_count ? result : *fs[f_id+1]).generate_r1cs_witness(fs[f_id]->get_element() * g_RR_at_P3s[dbl_id]->get_element().inverse()); + dbl_muls3[dbl_id]->generate_r1cs_witness(); + ++f_id; + ++dbl_id; + + if (NAF[i] != 0) + { + addition_steps1[add_id]->generate_r1cs_witness(); + addition_steps2[add_id]->generate_r1cs_witness(); + addition_steps3[add_id]->generate_r1cs_witness(); + add_muls1[add_id]->generate_r1cs_witness(); + ++f_id; + add_muls2[add_id]->generate_r1cs_witness(); + ++f_id; + (f_id+1 == f_count ? result : *fs[f_id+1]).generate_r1cs_witness(fs[f_id]->get_element() * g_RQ_at_P3s[add_id]->get_element().inverse()); + add_muls3[add_id]->generate_r1cs_witness(); + ++f_id; + ++add_id; + } + } +} + +template +void test_mnt_e_times_e_over_e_miller_loop(const std::string &annotation) +{ + protoboard > pb; + G1 > P1_val = Fr >::random_element() * G1 >::one(); + G2 > Q1_val = Fr >::random_element() * G2 >::one(); + + G1 > P2_val = Fr >::random_element() * G1 >::one(); + G2 > Q2_val = Fr >::random_element() * G2 >::one(); + + G1 > P3_val = Fr >::random_element() * G1 >::one(); + G2 > Q3_val = Fr >::random_element() * G2 >::one(); + + G1_variable P1(pb, "P1"); + G2_variable Q1(pb, "Q1"); + G1_variable P2(pb, "P2"); + G2_variable Q2(pb, "Q2"); + G1_variable P3(pb, "P3"); + G2_variable Q3(pb, "Q3"); + + G1_precomputation prec_P1; + precompute_G1_gadget compute_prec_P1(pb, P1, prec_P1, "compute_prec_P1"); + G1_precomputation prec_P2; + precompute_G1_gadget compute_prec_P2(pb, P2, prec_P2, "compute_prec_P2"); + G1_precomputation prec_P3; + precompute_G1_gadget compute_prec_P3(pb, P3, prec_P3, "compute_prec_P3"); + G2_precomputation prec_Q1; + precompute_G2_gadget compute_prec_Q1(pb, Q1, prec_Q1, "compute_prec_Q1"); + G2_precomputation prec_Q2; + precompute_G2_gadget compute_prec_Q2(pb, Q2, prec_Q2, "compute_prec_Q2"); + G2_precomputation prec_Q3; + precompute_G2_gadget compute_prec_Q3(pb, Q3, prec_Q3, "compute_prec_Q3"); + + Fqk_variable result(pb, "result"); + mnt_e_times_e_over_e_miller_loop_gadget miller(pb, prec_P1, prec_Q1, prec_P2, prec_Q2, prec_P3, prec_Q3, result, "miller"); + + PROFILE_CONSTRAINTS(pb, "precompute P") + { + compute_prec_P1.generate_r1cs_constraints(); + compute_prec_P2.generate_r1cs_constraints(); + compute_prec_P3.generate_r1cs_constraints(); + } + PROFILE_CONSTRAINTS(pb, "precompute Q") + { + compute_prec_Q1.generate_r1cs_constraints(); + compute_prec_Q2.generate_r1cs_constraints(); + compute_prec_Q3.generate_r1cs_constraints(); + } + PROFILE_CONSTRAINTS(pb, "Miller loop") + { + miller.generate_r1cs_constraints(); + } + PRINT_CONSTRAINT_PROFILING(); + + P1.generate_r1cs_witness(P1_val); + compute_prec_P1.generate_r1cs_witness(); + Q1.generate_r1cs_witness(Q1_val); + compute_prec_Q1.generate_r1cs_witness(); + P2.generate_r1cs_witness(P2_val); + compute_prec_P2.generate_r1cs_witness(); + Q2.generate_r1cs_witness(Q2_val); + compute_prec_Q2.generate_r1cs_witness(); + P3.generate_r1cs_witness(P3_val); + compute_prec_P3.generate_r1cs_witness(); + Q3.generate_r1cs_witness(Q3_val); + compute_prec_Q3.generate_r1cs_witness(); + miller.generate_r1cs_witness(); + assert(pb.is_satisfied()); + + affine_ate_G1_precomp > native_prec_P1 = other_curve::affine_ate_precompute_G1(P1_val); + affine_ate_G2_precomp > native_prec_Q1 = other_curve::affine_ate_precompute_G2(Q1_val); + affine_ate_G1_precomp > native_prec_P2 = other_curve::affine_ate_precompute_G1(P2_val); + affine_ate_G2_precomp > native_prec_Q2 = other_curve::affine_ate_precompute_G2(Q2_val); + affine_ate_G1_precomp > native_prec_P3 = other_curve::affine_ate_precompute_G1(P3_val); + affine_ate_G2_precomp > native_prec_Q3 = other_curve::affine_ate_precompute_G2(Q3_val); + Fqk > native_result = (other_curve::affine_ate_miller_loop(native_prec_P1, native_prec_Q1) * + other_curve::affine_ate_miller_loop(native_prec_P2, native_prec_Q2) * + other_curve::affine_ate_miller_loop(native_prec_P3, native_prec_Q3).inverse()); + + assert(result.get_element() == native_result); + printf("number of constraints for e times e over e Miller loop (Fr is %s) = %zu\n", annotation.c_str(), pb.num_constraints()); +} + +} // libsnark + +#endif // WEIERSTRASS_MILLER_LOOP_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/weierstrass_precomputation.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/weierstrass_precomputation.hpp new file mode 100644 index 0000000..14c9dbb --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/weierstrass_precomputation.hpp @@ -0,0 +1,280 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for pairing precomputation gadgets. + + The gadgets verify correct precomputation of values for the G1 and G2 variables. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WEIERSTRASS_PRECOMPUTATION_HPP_ +#define WEIERSTRASS_PRECOMPUTATION_HPP_ + +#include +#include "gadgetlib1/gadgets/curves/weierstrass_g1_gadget.hpp" +#include "gadgetlib1/gadgets/curves/weierstrass_g2_gadget.hpp" +#include "gadgetlib1/gadgets/pairing/pairing_params.hpp" + +namespace libsnark { + +/**************************** G1 Precomputation ******************************/ + +/** + * Not a gadget. It only holds values. + */ +template +class G1_precomputation { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + std::shared_ptr > P; + std::shared_ptr > PY_twist_squared; + + G1_precomputation(); + G1_precomputation(protoboard &pb, + const G1 > &P, + const std::string &annotation_prefix); +}; + +/** + * Gadget that verifies correct precomputation of the G1 variable. + */ +template +class precompute_G1_gadget : public gadget > { +public: + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + G1_precomputation &precomp; // must be a reference. + + /* two possible pre-computations one for mnt4 and one for mnt6 */ + template + precompute_G1_gadget(protoboard &pb, + const G1_variable &P, + G1_precomputation &precomp, // will allocate this inside + const std::string &annotation_prefix, + const typename std::enable_if >::extension_degree() == 4, FieldT>::type& = FieldT()) : + gadget(pb, annotation_prefix), + precomp(precomp) + { + pb_linear_combination c0, c1; + c0.assign(pb, P.Y * ((mnt4_twist).squared().c0)); + c1.assign(pb, P.Y * ((mnt4_twist).squared().c1)); + + precomp.P.reset(new G1_variable(P)); + precomp.PY_twist_squared.reset(new Fqe_variable(pb, c0, c1, FMT(annotation_prefix, " PY_twist_squared"))); + } + + template + precompute_G1_gadget(protoboard &pb, + const G1_variable &P, + G1_precomputation &precomp, // will allocate this inside + const std::string &annotation_prefix, + const typename std::enable_if >::extension_degree() == 6, FieldT>::type& = FieldT()) : + gadget(pb, annotation_prefix), + precomp(precomp) + { + pb_linear_combination c0, c1, c2; + c0.assign(pb, P.Y * ((mnt6_twist).squared().c0)); + c1.assign(pb, P.Y * ((mnt6_twist).squared().c1)); + c2.assign(pb, P.Y * ((mnt6_twist).squared().c2)); + + precomp.P.reset(new G1_variable(P)); + precomp.PY_twist_squared.reset(new Fqe_variable(pb, c0, c1, c2, FMT(annotation_prefix, " PY_twist_squared"))); + } + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_G1_variable_precomp(const std::string &annotation); + + +/**************************** G2 Precomputation ******************************/ + +/** + * Not a gadget. It only holds values. + */ +template +class precompute_G2_gadget_coeffs { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + std::shared_ptr > RX; + std::shared_ptr > RY; + std::shared_ptr > gamma; + std::shared_ptr > gamma_X; + + precompute_G2_gadget_coeffs(); + precompute_G2_gadget_coeffs(protoboard &pb, + const std::string &annotation_prefix); + precompute_G2_gadget_coeffs(protoboard &pb, + const G2_variable &Q, + const std::string &annotation_prefix); +}; + +/** + * Not a gadget. It only holds values. + */ +template +class G2_precomputation { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + std::shared_ptr > Q; + + std::vector > > coeffs; + + G2_precomputation(); + G2_precomputation(protoboard &pb, + const G2 > &Q_val, + const std::string &annotation_prefix); +}; + +/** + * Technical note: + * + * QX and QY -- X and Y coordinates of Q + * + * initialization: + * coeffs[0].RX = QX + * coeffs[0].RY = QY + * + * G2_precompute_doubling_step relates coeffs[i] and coeffs[i+1] as follows + * + * coeffs[i] + * gamma = (3 * RX^2 + twist_coeff_a) * (2*RY).inverse() + * gamma_X = gamma * RX + * + * coeffs[i+1] + * RX = prev_gamma^2 - (2*prev_RX) + * RY = prev_gamma * (prev_RX - RX) - prev_RY + */ +template +class precompute_G2_gadget_doubling_step : public gadget > { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + precompute_G2_gadget_coeffs cur; + precompute_G2_gadget_coeffs next; + + std::shared_ptr > RXsquared; + std::shared_ptr > compute_RXsquared; + std::shared_ptr > three_RXsquared_plus_a; + std::shared_ptr > two_RY; + std::shared_ptr > compute_gamma; + std::shared_ptr > compute_gamma_X; + + std::shared_ptr > next_RX_plus_two_RX; + std::shared_ptr > compute_next_RX; + + std::shared_ptr > RX_minus_next_RX; + std::shared_ptr > RY_plus_next_RY; + std::shared_ptr > compute_next_RY; + + precompute_G2_gadget_doubling_step(protoboard &pb, + const precompute_G2_gadget_coeffs &cur, + const precompute_G2_gadget_coeffs &next, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Technical note: + * + * G2_precompute_addition_step relates coeffs[i] and coeffs[i+1] as follows + * + * coeffs[i] + * gamma = (RY - QY) * (RX - QX).inverse() + * gamma_X = gamma * QX + * + * coeffs[i+1] + * RX = prev_gamma^2 + (prev_RX + QX) + * RY = prev_gamma * (prev_RX - RX) - prev_RY + * + * (where prev_ in [i+1] refer to things from [i]) + * + * If invert_Q is set to true: use -QY in place of QY everywhere above. + */ +template +class precompute_G2_gadget_addition_step : public gadget > { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + bool invert_Q; + precompute_G2_gadget_coeffs cur; + precompute_G2_gadget_coeffs next; + G2_variable Q; + + std::shared_ptr > RY_minus_QY; + std::shared_ptr > RX_minus_QX; + std::shared_ptr > compute_gamma; + std::shared_ptr > compute_gamma_X; + + std::shared_ptr > next_RX_plus_RX_plus_QX; + std::shared_ptr > compute_next_RX; + + std::shared_ptr > RX_minus_next_RX; + std::shared_ptr > RY_plus_next_RY; + std::shared_ptr > compute_next_RY; + + precompute_G2_gadget_addition_step(protoboard &pb, + const bool invert_Q, + const precompute_G2_gadget_coeffs &cur, + const precompute_G2_gadget_coeffs &next, + const G2_variable &Q, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that verifies correct precomputation of the G2 variable. + */ +template +class precompute_G2_gadget : public gadget > { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + std::vector > > addition_steps; + std::vector > > doubling_steps; + + size_t add_count; + size_t dbl_count; + + G2_precomputation &precomp; // important to have a reference here + + precompute_G2_gadget(protoboard &pb, + const G2_variable &Q, + G2_precomputation &precomp, // will allocate this inside + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_G2_variable_precomp(const std::string &annotation); + +} // libsnark + +#include "gadgetlib1/gadgets/pairing/weierstrass_precomputation.tcc" + +#endif // WEIERSTRASS_PRECOMPUTATION_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/weierstrass_precomputation.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/weierstrass_precomputation.tcc new file mode 100644 index 0000000..9cd1126 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/pairing/weierstrass_precomputation.tcc @@ -0,0 +1,444 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for pairing precomputation gadgets. + + See weierstrass_precomputation.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WEIERSTRASS_PRECOMPUTATION_TCC_ +#define WEIERSTRASS_PRECOMPUTATION_TCC_ + +#include +#include "gadgetlib1/gadgets/pairing/mnt_pairing_params.hpp" + +namespace libsnark { + +template +G1_precomputation::G1_precomputation() +{ + // will be filled in precompute_G1_gadget, so do nothing here +} + +template +G1_precomputation::G1_precomputation(protoboard &pb, + const G1 > &P_val, + const std::string &annotation_prefix) +{ + G1 > P_val_copy = P_val; + P_val_copy.to_affine_coordinates(); + P.reset(new G1_variable(pb, P_val_copy, FMT(annotation_prefix, " P"))); + PY_twist_squared.reset(new Fqe_variable(pb, P_val_copy.Y() * G2 >::twist.squared(), " PY_twist_squared")); +} + +template +void precompute_G1_gadget::generate_r1cs_constraints() +{ + /* the same for neither ppT = mnt4 nor ppT = mnt6 */ +} + +template +void precompute_G1_gadget::generate_r1cs_witness() +{ + precomp.PY_twist_squared->evaluate(); /* the same for both ppT = mnt4 and ppT = mnt6 */ +} + +template +void test_G1_variable_precomp(const std::string &annotation) +{ + protoboard > pb; + G1 > g_val = Fr >::random_element() * G1 >::one(); + + G1_variable g(pb, "g"); + G1_precomputation precomp; + precompute_G1_gadget do_precomp(pb, g, precomp, "do_precomp"); + do_precomp.generate_r1cs_constraints(); + + g.generate_r1cs_witness(g_val); + do_precomp.generate_r1cs_witness(); + assert(pb.is_satisfied()); + + G1_precomputation const_precomp(pb, g_val, "const_precomp"); + + affine_ate_G1_precomp > native_precomp = other_curve::affine_ate_precompute_G1(g_val); + assert(precomp.PY_twist_squared->get_element() == native_precomp.PY_twist_squared); + assert(const_precomp.PY_twist_squared->get_element() == native_precomp.PY_twist_squared); + + printf("number of constraints for G1 precomp (Fr is %s) = %zu\n", annotation.c_str(), pb.num_constraints()); +} + +template +G2_precomputation::G2_precomputation() +{ +} + +template +G2_precomputation::G2_precomputation(protoboard &pb, + const G2 > &Q_val, + const std::string &annotation_prefix) +{ + Q.reset(new G2_variable(pb, Q_val, FMT(annotation_prefix, " Q"))); + const affine_ate_G2_precomp > native_precomp = other_curve::affine_ate_precompute_G2(Q_val); + + coeffs.resize(native_precomp.coeffs.size() + 1); // the last precomp remains for convenient programming + for (size_t i = 0; i < native_precomp.coeffs.size(); ++i) + { + coeffs[i].reset(new precompute_G2_gadget_coeffs()); + coeffs[i]->RX.reset(new Fqe_variable(pb, native_precomp.coeffs[i].old_RX, FMT(annotation_prefix, " RX"))); + coeffs[i]->RY.reset(new Fqe_variable(pb, native_precomp.coeffs[i].old_RY, FMT(annotation_prefix, " RY"))); + coeffs[i]->gamma.reset(new Fqe_variable(pb, native_precomp.coeffs[i].gamma, FMT(annotation_prefix, " gamma"))); + coeffs[i]->gamma_X.reset(new Fqe_variable(pb, native_precomp.coeffs[i].gamma_X, FMT(annotation_prefix, " gamma_X"))); + } +} + +template +precompute_G2_gadget_coeffs::precompute_G2_gadget_coeffs() +{ + // we will be filled in precomputed case of precompute_G2_gadget, so do nothing here +} + +template +precompute_G2_gadget_coeffs::precompute_G2_gadget_coeffs(protoboard &pb, + const std::string &annotation_prefix) +{ + RX.reset(new Fqe_variable(pb, FMT(annotation_prefix, " RX"))); + RY.reset(new Fqe_variable(pb, FMT(annotation_prefix, " RY"))); + gamma.reset(new Fqe_variable(pb, FMT(annotation_prefix, " gamma"))); + gamma_X.reset(new Fqe_variable(pb, FMT(annotation_prefix, " gamma_X"))); +} + +template +precompute_G2_gadget_coeffs::precompute_G2_gadget_coeffs(protoboard &pb, + const G2_variable &Q, + const std::string &annotation_prefix) +{ + RX.reset(new Fqe_variable(*(Q.X))); + RY.reset(new Fqe_variable(*(Q.Y))); + gamma.reset(new Fqe_variable(pb, FMT(annotation_prefix, " gamma"))); + gamma_X.reset(new Fqe_variable(pb, FMT(annotation_prefix, " gamma_X"))); +} + +/* + QX and QY -- X and Y coordinates of Q + + initialization: + coeffs[0].RX = QX + coeffs[0].RY = QY + + G2_precompute_doubling_step relates coeffs[i] and coeffs[i+1] as follows + + coeffs[i] + gamma = (3 * RX^2 + twist_coeff_a) * (2*RY).inverse() + gamma_X = gamma * RX + + coeffs[i+1] + RX = prev_gamma^2 - (2*prev_RX) + RY = prev_gamma * (prev_RX - RX) - prev_RY + */ + +template +precompute_G2_gadget_doubling_step::precompute_G2_gadget_doubling_step(protoboard &pb, + const precompute_G2_gadget_coeffs &cur, + const precompute_G2_gadget_coeffs &next, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + cur(cur), + next(next) +{ + RXsquared.reset(new Fqe_variable(pb, FMT(annotation_prefix, " RXsquared"))); + compute_RXsquared.reset(new Fqe_sqr_gadget(pb, *(cur.RX), *RXsquared, FMT(annotation_prefix, " compute_RXsquared"))); + three_RXsquared_plus_a.reset(new Fqe_variable((*RXsquared) * FieldT(3) + G2 >::coeff_a)); + two_RY.reset(new Fqe_variable(*(cur.RY) * FieldT(2))); + + compute_gamma.reset(new Fqe_mul_gadget(pb, *(cur.gamma), *two_RY, *three_RXsquared_plus_a, FMT(annotation_prefix, " compute_gamma"))); + compute_gamma_X.reset(new Fqe_mul_gadget(pb, *(cur.gamma), *(cur.RX), *(cur.gamma_X), FMT(annotation_prefix, " compute_gamma_X"))); + + next_RX_plus_two_RX.reset(new Fqe_variable(*(next.RX) + *(cur.RX) * FieldT(2))); + compute_next_RX.reset(new Fqe_sqr_gadget(pb, *(cur.gamma), *next_RX_plus_two_RX, FMT(annotation_prefix, " compute_next_RX"))); + + RX_minus_next_RX.reset(new Fqe_variable(*(cur.RX) + *(next.RX) * (-FieldT::one()))); + RY_plus_next_RY.reset(new Fqe_variable(*(cur.RY) + *(next.RY))); + compute_next_RY.reset(new Fqe_mul_gadget(pb, *(cur.gamma), *RX_minus_next_RX, *RY_plus_next_RY, FMT(annotation_prefix, " compute_next_RY"))); +} + +template +void precompute_G2_gadget_doubling_step::generate_r1cs_constraints() +{ + compute_RXsquared->generate_r1cs_constraints(); + compute_gamma->generate_r1cs_constraints(); + compute_gamma_X->generate_r1cs_constraints(); + compute_next_RX->generate_r1cs_constraints(); + compute_next_RY->generate_r1cs_constraints(); +} + +template +void precompute_G2_gadget_doubling_step::generate_r1cs_witness() +{ + compute_RXsquared->generate_r1cs_witness(); + two_RY->evaluate(); + three_RXsquared_plus_a->evaluate(); + + const FqeT three_RXsquared_plus_a_val = three_RXsquared_plus_a->get_element(); + const FqeT two_RY_val = two_RY->get_element(); + const FqeT gamma_val = three_RXsquared_plus_a_val * two_RY_val.inverse(); + cur.gamma->generate_r1cs_witness(gamma_val); + + compute_gamma->generate_r1cs_witness(); + compute_gamma_X->generate_r1cs_witness(); + + const FqeT RX_val = cur.RX->get_element(); + const FqeT RY_val = cur.RY->get_element(); + const FqeT next_RX_val = gamma_val.squared() - RX_val - RX_val; + const FqeT next_RY_val = gamma_val * (RX_val - next_RX_val) - RY_val; + + next.RX->generate_r1cs_witness(next_RX_val); + next.RY->generate_r1cs_witness(next_RY_val); + + RX_minus_next_RX->evaluate(); + RY_plus_next_RY->evaluate(); + + compute_next_RX->generate_r1cs_witness(); + compute_next_RY->generate_r1cs_witness(); +} + +/* + G2_precompute_addition_step relates coeffs[i] and coeffs[i+1] as follows + + coeffs[i] + gamma = (RY - QY) * (RX - QX).inverse() + gamma_X = gamma * QX + + coeffs[i+1] + RX = prev_gamma^2 - (prev_RX + QX) + RY = prev_gamma * (prev_RX - RX) - prev_RY + + (where prev_ in [i+1] refer to things from [i]) + + If invert_Q is set to true: use -QY in place of QY everywhere above. + */ +template +precompute_G2_gadget_addition_step::precompute_G2_gadget_addition_step(protoboard &pb, + const bool invert_Q, + const precompute_G2_gadget_coeffs &cur, + const precompute_G2_gadget_coeffs &next, + const G2_variable &Q, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + invert_Q(invert_Q), + cur(cur), + next(next), + Q(Q) +{ + RY_minus_QY.reset(new Fqe_variable(*(cur.RY) + *(Q.Y) * (!invert_Q ? -FieldT::one() : FieldT::one()))); + + RX_minus_QX.reset(new Fqe_variable(*(cur.RX) + *(Q.X) * (-FieldT::one()))); + compute_gamma.reset(new Fqe_mul_gadget(pb, *(cur.gamma), *RX_minus_QX, *RY_minus_QY, FMT(annotation_prefix, " compute_gamma"))); + compute_gamma_X.reset(new Fqe_mul_gadget(pb, *(cur.gamma), *(Q.X), *(cur.gamma_X), FMT(annotation_prefix, " compute_gamma_X"))); + + next_RX_plus_RX_plus_QX.reset(new Fqe_variable(*(next.RX) + *(cur.RX) + *(Q.X))); + compute_next_RX.reset(new Fqe_sqr_gadget(pb, *(cur.gamma), *next_RX_plus_RX_plus_QX, FMT(annotation_prefix, " compute_next_RX"))); + + RX_minus_next_RX.reset(new Fqe_variable(*(cur.RX) + *(next.RX) * (-FieldT::one()))); + RY_plus_next_RY.reset(new Fqe_variable(*(cur.RY) + *(next.RY))); + compute_next_RY.reset(new Fqe_mul_gadget(pb, *(cur.gamma), *RX_minus_next_RX, *RY_plus_next_RY, FMT(annotation_prefix, " compute_next_RY"))); +} + +template +void precompute_G2_gadget_addition_step::generate_r1cs_constraints() +{ + compute_gamma->generate_r1cs_constraints(); + compute_gamma_X->generate_r1cs_constraints(); + compute_next_RX->generate_r1cs_constraints(); + compute_next_RY->generate_r1cs_constraints(); +} + +template +void precompute_G2_gadget_addition_step::generate_r1cs_witness() +{ + RY_minus_QY->evaluate(); + RX_minus_QX->evaluate(); + + const FqeT RY_minus_QY_val = RY_minus_QY->get_element(); + const FqeT RX_minus_QX_val = RX_minus_QX->get_element(); + const FqeT gamma_val = RY_minus_QY_val * RX_minus_QX_val.inverse(); + cur.gamma->generate_r1cs_witness(gamma_val); + + compute_gamma->generate_r1cs_witness(); + compute_gamma_X->generate_r1cs_witness(); + + const FqeT RX_val = cur.RX->get_element(); + const FqeT RY_val = cur.RY->get_element(); + const FqeT QX_val = Q.X->get_element(); + const FqeT next_RX_val = gamma_val.squared() - RX_val - QX_val; + const FqeT next_RY_val = gamma_val * (RX_val - next_RX_val) - RY_val; + + next.RX->generate_r1cs_witness(next_RX_val); + next.RY->generate_r1cs_witness(next_RY_val); + + next_RX_plus_RX_plus_QX->evaluate(); + RX_minus_next_RX->evaluate(); + RY_plus_next_RY->evaluate(); + + compute_next_RX->generate_r1cs_witness(); + compute_next_RY->generate_r1cs_witness(); +} + +template +precompute_G2_gadget::precompute_G2_gadget(protoboard &pb, + const G2_variable &Q, + G2_precomputation &precomp, // will allocate this inside + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + precomp(precomp) +{ + precomp.Q.reset(new G2_variable(Q)); + + const auto &loop_count = pairing_selector::pairing_loop_count; + size_t coeff_count = 1; // the last RX/RY are unused in Miller loop, but will need to get allocated somehow + this->add_count = 0; + this->dbl_count = 0; + + bool found_nonzero = false; + std::vector NAF = find_wnaf(1, loop_count); + for (long i = NAF.size()-1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + ++dbl_count; + ++coeff_count; + + if (NAF[i] != 0) + { + ++add_count; + ++coeff_count; + } + } + + precomp.coeffs.resize(coeff_count); + addition_steps.resize(add_count); + doubling_steps.resize(dbl_count); + + precomp.coeffs[0].reset(new precompute_G2_gadget_coeffs(pb, Q, FMT(annotation_prefix, " coeffs_0"))); + for (size_t i = 1; i < coeff_count; ++i) + { + precomp.coeffs[i].reset(new precompute_G2_gadget_coeffs(pb, FMT(annotation_prefix, " coeffs_%zu", i))); + } + + size_t add_id = 0; + size_t dbl_id = 0; + size_t coeff_id = 0; + + found_nonzero = false; + for (long i = NAF.size()-1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + doubling_steps[dbl_id].reset(new precompute_G2_gadget_doubling_step(pb, *(precomp.coeffs[coeff_id]), *(precomp.coeffs[coeff_id+1]), + FMT(annotation_prefix, " doubling_steps_%zu", dbl_id))); + ++dbl_id; + ++coeff_id; + + if (NAF[i] != 0) + { + addition_steps[add_id].reset(new precompute_G2_gadget_addition_step(pb, NAF[i] < 0, *(precomp.coeffs[coeff_id]), *(precomp.coeffs[coeff_id+1]), Q, + FMT(annotation_prefix, " addition_steps_%zu", add_id))); + ++add_id; + ++coeff_id; + } + } +} + +template +void precompute_G2_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < dbl_count; ++i) + { + doubling_steps[i]->generate_r1cs_constraints(); + } + + for (size_t i = 0; i < add_count; ++i) + { + addition_steps[i]->generate_r1cs_constraints(); + } +} + +template +void precompute_G2_gadget::generate_r1cs_witness() +{ + precomp.coeffs[0]->RX->generate_r1cs_witness(precomp.Q->X->get_element()); + precomp.coeffs[0]->RY->generate_r1cs_witness(precomp.Q->Y->get_element()); + + const auto &loop_count = pairing_selector::pairing_loop_count; + + size_t add_id = 0; + size_t dbl_id = 0; + + bool found_nonzero = false; + std::vector NAF = find_wnaf(1, loop_count); + for (long i = NAF.size()-1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + doubling_steps[dbl_id]->generate_r1cs_witness(); + ++dbl_id; + + if (NAF[i] != 0) + { + addition_steps[add_id]->generate_r1cs_witness(); + ++add_id; + } + } +} + +template +void test_G2_variable_precomp(const std::string &annotation) +{ + protoboard > pb; + G2 > g_val = Fr >::random_element() * G2 >::one(); + + G2_variable g(pb, "g"); + G2_precomputation precomp; + precompute_G2_gadget do_precomp(pb, g, precomp, "do_precomp"); + do_precomp.generate_r1cs_constraints(); + + g.generate_r1cs_witness(g_val); + do_precomp.generate_r1cs_witness(); + assert(pb.is_satisfied()); + + affine_ate_G2_precomp > native_precomp = other_curve::affine_ate_precompute_G2(g_val); + + assert(precomp.coeffs.size() - 1 == native_precomp.coeffs.size()); // the last precomp is unused, but remains for convenient programming + for (size_t i = 0; i < native_precomp.coeffs.size(); ++i) + { + assert(precomp.coeffs[i]->RX->get_element() == native_precomp.coeffs[i].old_RX); + assert(precomp.coeffs[i]->RY->get_element() == native_precomp.coeffs[i].old_RY); + assert(precomp.coeffs[i]->gamma->get_element() == native_precomp.coeffs[i].gamma); + assert(precomp.coeffs[i]->gamma_X->get_element() == native_precomp.coeffs[i].gamma_X); + } + + printf("number of constraints for G2 precomp (Fr is %s) = %zu\n", annotation.c_str(), pb.num_constraints()); +} + +} // libsnark + +#endif // WEIERSTRASS_PRECOMPUTATION_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/routing/as_waksman_routing_gadget.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/routing/as_waksman_routing_gadget.hpp new file mode 100644 index 0000000..8fc606d --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/routing/as_waksman_routing_gadget.hpp @@ -0,0 +1,82 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the AS-Waksman routing gadget. + + The gadget verifies that the outputs are a permutation of the inputs, + by use of an AS-Waksman network. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef AS_WAKSMAN_ROUTING_GADGET_HPP_ +#define AS_WAKSMAN_ROUTING_GADGET_HPP_ + +#include "gadgetlib1/protoboard.hpp" +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "common/data_structures/integer_permutation.hpp" +#include "common/routing_algorithms/as_waksman_routing_algorithm.hpp" + +namespace libsnark { + +template +class as_waksman_routing_gadget : public gadget { +private: + /* + Indexing conventions: + + routed_packets[column_idx][packet_idx][subpacket_idx] + pack_inputs/unpack_outputs[packet_idx] + asw_switch_bits[column_idx][row_idx] + + Where column_idx ranges is in range 0 .. width and packet_idx is + in range 0 .. num_packets-1. + + Note that unlike in Bene\v{s} routing networks row_idx are + *not* necessarily consecutive; similarly for straight edges + routed_packets[column_idx][packet_idx] will *reuse* previously + allocated variables. + + */ + std::vector > > routed_packets; + std::vector > pack_inputs, unpack_outputs; + + /* + If #packets = 1 then we can route without explicit switch bits + (and save half the constraints); in this case asw_switch_bits will + be unused. + + For asw_switch_bits 0 corresponds to switch off (straight + connection), and 1 corresponds to switch on (crossed + connection). + */ + std::vector > > asw_switch_bits; + as_waksman_topology neighbors; +public: + const size_t num_packets; + const size_t num_columns; + const std::vector> routing_input_bits; + const std::vector> routing_output_bits; + + const size_t packet_size, num_subpackets; + + as_waksman_routing_gadget(protoboard &pb, + const size_t num_packets, + const std::vector> &routing_input_bits, + const std::vector> &routing_output_bits, + const std::string& annotation_prefix=""); + void generate_r1cs_constraints(); + void generate_r1cs_witness(const integer_permutation& permutation); +}; + +template +void test_as_waksman_routing_gadget(const size_t num_packets, const size_t packet_size); + +} // libsnark + +#include "gadgetlib1/gadgets/routing/as_waksman_routing_gadget.tcc" + +#endif // AS_WAKSMAN_ROUTING_GADGET_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/routing/as_waksman_routing_gadget.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/routing/as_waksman_routing_gadget.tcc new file mode 100644 index 0000000..74f386a --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/routing/as_waksman_routing_gadget.tcc @@ -0,0 +1,294 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the AS-Waksman routing gadget. + + See as_waksman_routing_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef AS_WAKSMAN_ROUTING_GADGET_TCC_ +#define AS_WAKSMAN_ROUTING_GADGET_TCC_ + +#include + +#include "common/routing_algorithms/as_waksman_routing_algorithm.hpp" +#include "common/profiling.hpp" + +namespace libsnark { + +template +as_waksman_routing_gadget::as_waksman_routing_gadget(protoboard &pb, + const size_t num_packets, + const std::vector > &routing_input_bits, + const std::vector > &routing_output_bits, + const std::string& annotation_prefix) : + gadget(pb, annotation_prefix), + num_packets(num_packets), + num_columns(as_waksman_num_columns(num_packets)), + routing_input_bits(routing_input_bits), + routing_output_bits(routing_output_bits), + packet_size(routing_input_bits[0].size()), + num_subpackets(div_ceil(packet_size, FieldT::capacity())) +{ + neighbors = generate_as_waksman_topology(num_packets); + routed_packets.resize(num_columns+1); + + /* Two pass allocation. First allocate LHS packets, then for every + switch either copy over the variables from previously allocated + to allocate target packets */ + routed_packets[0].resize(num_packets); + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + routed_packets[0][packet_idx].allocate(pb, num_subpackets, FMT(annotation_prefix, " routed_packets_0_%zu", packet_idx)); + } + + for (size_t column_idx = 0; column_idx < num_columns; ++column_idx) + { + routed_packets[column_idx+1].resize(num_packets); + + for (size_t row_idx = 0; row_idx < num_packets; ++row_idx) + { + if (neighbors[column_idx][row_idx].first == neighbors[column_idx][row_idx].second) + { + /* This is a straight edge, so just copy over the previously allocated subpackets */ + routed_packets[column_idx+1][neighbors[column_idx][row_idx].first] = routed_packets[column_idx][row_idx]; + } + else + { + const size_t straight_edge = neighbors[column_idx][row_idx].first; + const size_t cross_edge = neighbors[column_idx][row_idx].second; + routed_packets[column_idx+1][straight_edge].allocate(pb, num_subpackets, FMT(annotation_prefix, " routed_packets_%zu_%zu", column_idx+1, straight_edge)); + routed_packets[column_idx+1][cross_edge].allocate(pb, num_subpackets, FMT(annotation_prefix, " routed_packets_%zu_%zu", column_idx+1, cross_edge)); + ++row_idx; /* skip the next idx, as it to refers to the same packets */ + } + } + } + + /* create packing/unpacking gadgets */ + pack_inputs.reserve(num_packets); unpack_outputs.reserve(num_packets); + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + pack_inputs.emplace_back( + multipacking_gadget(pb, + pb_variable_array(routing_input_bits[packet_idx].begin(), routing_input_bits[packet_idx].end()), + routed_packets[0][packet_idx], + FieldT::capacity(), + FMT(this->annotation_prefix, " pack_inputs_%zu", packet_idx))); + unpack_outputs.emplace_back( + multipacking_gadget(pb, + pb_variable_array(routing_output_bits[packet_idx].begin(), routing_output_bits[packet_idx].end()), + routed_packets[num_columns][packet_idx], + FieldT::capacity(), + FMT(this->annotation_prefix, " unpack_outputs_%zu", packet_idx))); + } + + /* allocate switch bits */ + if (num_subpackets > 1) + { + asw_switch_bits.resize(num_columns); + + for (size_t column_idx = 0; column_idx < num_columns; ++column_idx) + { + for (size_t row_idx = 0; row_idx < num_packets; ++row_idx) + { + if (neighbors[column_idx][row_idx].first != neighbors[column_idx][row_idx].second) + { + asw_switch_bits[column_idx][row_idx].allocate(pb, FMT(annotation_prefix, " asw_switch_bits_%zu_%zu", column_idx, row_idx)); + ++row_idx; /* next row_idx corresponds to the same switch, so skip it */ + } + } + } + } +} + +template +void as_waksman_routing_gadget::generate_r1cs_constraints() +{ + /* packing/unpacking */ + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + pack_inputs[packet_idx].generate_r1cs_constraints(false); + unpack_outputs[packet_idx].generate_r1cs_constraints(true); + } + + /* actual routing constraints */ + for (size_t column_idx = 0; column_idx < num_columns; ++column_idx) + { + for (size_t row_idx = 0; row_idx < num_packets; ++row_idx) + { + if (neighbors[column_idx][row_idx].first == neighbors[column_idx][row_idx].second) + { + /* if there is no switch at this position, then just continue with next row_idx */ + continue; + } + + if (num_subpackets == 1) + { + /* easy case: require that + (cur-straight_edge)*(cur-cross_edge) = 0 for both + switch inputs */ + for (size_t switch_input : { row_idx, row_idx+1 }) + { + const size_t straight_edge = neighbors[column_idx][switch_input].first; + const size_t cross_edge = neighbors[column_idx][switch_input].second; + + this->pb.add_r1cs_constraint( + r1cs_constraint(routed_packets[column_idx][switch_input][0] - routed_packets[column_idx+1][straight_edge][0], + routed_packets[column_idx][switch_input][0] - routed_packets[column_idx+1][cross_edge][0], + 0), + FMT(this->annotation_prefix, " easy_route_%zu_%zu", column_idx, switch_input)); + } + } + else + { + /* require switching bit to be boolean */ + generate_boolean_r1cs_constraint(this->pb, asw_switch_bits[column_idx][row_idx], + FMT(this->annotation_prefix, " asw_switch_bits_%zu_%zu", column_idx, row_idx)); + + /* route forward according to the switch bit */ + for (size_t subpacket_idx = 0; subpacket_idx < num_subpackets; ++subpacket_idx) + { + /* + (1-switch_bit) * (cur-straight_edge) + switch_bit * (cur-cross_edge) = 0 + switch_bit * (cross_edge-straight_edge) = cur-straight_edge + */ + for (size_t switch_input : { row_idx, row_idx+1 }) + { + const size_t straight_edge = neighbors[column_idx][switch_input].first; + const size_t cross_edge = neighbors[column_idx][switch_input].second; + + this->pb.add_r1cs_constraint( + r1cs_constraint( + asw_switch_bits[column_idx][row_idx], + routed_packets[column_idx+1][cross_edge][subpacket_idx] - routed_packets[column_idx+1][straight_edge][subpacket_idx], + routed_packets[column_idx][switch_input][subpacket_idx] - routed_packets[column_idx+1][straight_edge][subpacket_idx]), + FMT(this->annotation_prefix, " route_forward_%zu_%zu_%zu", column_idx, switch_input, subpacket_idx)); + } + } + } + + /* we processed both switch inputs at once, so skip the next iteration */ + ++row_idx; + } + } +} + +template +void as_waksman_routing_gadget::generate_r1cs_witness(const integer_permutation& permutation) +{ + /* pack inputs */ + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + pack_inputs[packet_idx].generate_r1cs_witness_from_bits(); + } + + /* do the routing */ + as_waksman_routing routing = get_as_waksman_routing(permutation); + + for (size_t column_idx = 0; column_idx < num_columns; ++column_idx) + { + for (size_t row_idx = 0; row_idx < num_packets; ++row_idx) + { + if (neighbors[column_idx][row_idx].first == neighbors[column_idx][row_idx].second) + { + /* this is a straight edge, so just pass the values forward */ + const size_t next = neighbors[column_idx][row_idx].first; + + for (size_t subpacket_idx = 0; subpacket_idx < num_subpackets; ++subpacket_idx) + { + this->pb.val(routed_packets[column_idx+1][next][subpacket_idx]) = this->pb.val(routed_packets[column_idx][row_idx][subpacket_idx]); + } + } + else + { + if (num_subpackets > 1) + { + /* update the switch bit */ + this->pb.val(asw_switch_bits[column_idx][row_idx]) = FieldT(routing[column_idx][row_idx] ? 1 : 0); + } + + /* route according to the switch bit */ + const bool switch_val = routing[column_idx][row_idx]; + + for (size_t switch_input : { row_idx, row_idx+1 }) + { + const size_t straight_edge = neighbors[column_idx][switch_input].first; + const size_t cross_edge = neighbors[column_idx][switch_input].second; + + const size_t switched_edge = (switch_val ? cross_edge : straight_edge); + + for (size_t subpacket_idx = 0; subpacket_idx < num_subpackets; ++subpacket_idx) + { + this->pb.val(routed_packets[column_idx+1][switched_edge][subpacket_idx]) = this->pb.val(routed_packets[column_idx][switch_input][subpacket_idx]); + } + } + + /* we processed both switch inputs at once, so skip the next iteration */ + ++row_idx; + } + } + } + + /* unpack outputs */ + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + unpack_outputs[packet_idx].generate_r1cs_witness_from_packed(); + } +} + +template +void test_as_waksman_routing_gadget(const size_t num_packets, const size_t packet_size) +{ + printf("testing as_waksman_routing_gadget by routing %zu element vector of %zu bits (Fp fits all %zu bit integers)\n", num_packets, packet_size, FieldT::capacity()); + protoboard pb; + integer_permutation permutation(num_packets); + permutation.random_shuffle(); + print_time("generated permutation"); + + std::vector > randbits(num_packets), outbits(num_packets); + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + randbits[packet_idx].allocate(pb, packet_size, FMT("", "randbits_%zu", packet_idx)); + outbits[packet_idx].allocate(pb, packet_size, FMT("", "outbits_%zu", packet_idx)); + + for (size_t bit_idx = 0; bit_idx < packet_size; ++bit_idx) + { + pb.val(randbits[packet_idx][bit_idx]) = (rand() % 2) ? FieldT::one() : FieldT::zero(); + } + } + print_time("generated bits to be routed"); + + as_waksman_routing_gadget r(pb, num_packets, randbits, outbits, "main_routing_gadget"); + r.generate_r1cs_constraints(); + print_time("generated routing constraints"); + + r.generate_r1cs_witness(permutation); + print_time("generated routing assignment"); + + printf("positive test\n"); + assert(pb.is_satisfied()); + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + for (size_t bit_idx = 0; bit_idx < packet_size; ++bit_idx) + { + assert(pb.val(outbits[permutation.get(packet_idx)][bit_idx]) == pb.val(randbits[packet_idx][bit_idx])); + } + } + + printf("negative test\n"); + pb.val(pb_variable(10)) = FieldT(12345); + assert(!pb.is_satisfied()); + + printf("num_constraints = %zu, num_variables = %zu\n", + pb.num_constraints(), + pb.constraint_system.num_variables); +} + +} // libsnark + +#endif // AS_WAKSMAN_ROUTING_GADGET_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/routing/benes_routing_gadget.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/routing/benes_routing_gadget.hpp new file mode 100644 index 0000000..5d4edb4 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/routing/benes_routing_gadget.hpp @@ -0,0 +1,81 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the Benes routing gadget. + + The gadget verifies that the outputs are a permutation of the inputs, + by use of a Benes network. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BENES_ROUTING_GADGET_HPP_ +#define BENES_ROUTING_GADGET_HPP_ + +#include "common/data_structures/integer_permutation.hpp" +#include "common/routing_algorithms/benes_routing_algorithm.hpp" +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "gadgetlib1/protoboard.hpp" + +namespace libsnark { + +template +class benes_routing_gadget : public gadget { +private: + /* + Indexing conventions: + + routed_packets[column_idx][packet_idx][subpacket_idx] + pack_inputs/unpack_outputs[packet_idx] + benes_switch_bits[column_idx][row_idx] + + Where column_idx ranges is in range 0 .. 2*dimension + (2*dimension-1 for switch bits/topology) and packet_idx is in + range 0 .. num_packets-1. + */ + std::vector > > routed_packets; + std::vector > pack_inputs, unpack_outputs; + + /* + If #packets = 1 then we can route without explicit routing bits + (and save half the constraints); in this case benes_switch_bits will + be unused. + + For benes_switch_bits 0 corresponds to straight edge and 1 + corresponds to cross edge. + */ + std::vector> benes_switch_bits; + benes_topology neighbors; +public: + const size_t num_packets; + const size_t num_columns; + + const std::vector > routing_input_bits; + const std::vector > routing_output_bits; + size_t lines_to_unpack; + + const size_t packet_size, num_subpackets; + + benes_routing_gadget(protoboard &pb, + const size_t num_packets, + const std::vector> &routing_input_bits, + const std::vector> &routing_output_bits, + const size_t lines_to_unpack, + const std::string& annotation_prefix=""); + + void generate_r1cs_constraints(); + + void generate_r1cs_witness(const integer_permutation &permutation); +}; + +template +void test_benes_routing_gadget(const size_t num_packets, const size_t packet_size); + +} // libsnark + +#include "gadgetlib1/gadgets/routing/benes_routing_gadget.tcc" + +#endif // BENES_ROUTING_GADGET_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/routing/benes_routing_gadget.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/routing/benes_routing_gadget.tcc new file mode 100644 index 0000000..cde9492 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/routing/benes_routing_gadget.tcc @@ -0,0 +1,247 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the Benes routing gadget. + + See benes_routing_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BENES_ROUTING_GADGET_TCC_ +#define BENES_ROUTING_GADGET_TCC_ + +#include "common/profiling.hpp" + +#include + +namespace libsnark { + +template +benes_routing_gadget::benes_routing_gadget(protoboard &pb, + const size_t num_packets, + const std::vector > &routing_input_bits, + const std::vector > &routing_output_bits, + const size_t lines_to_unpack, + const std::string& annotation_prefix) : + gadget(pb, annotation_prefix), + num_packets(num_packets), + num_columns(benes_num_columns(num_packets)), + routing_input_bits(routing_input_bits), + routing_output_bits(routing_output_bits), + lines_to_unpack(lines_to_unpack), + packet_size(routing_input_bits[0].size()), + num_subpackets(div_ceil(packet_size, FieldT::capacity())) +{ + assert(lines_to_unpack <= routing_input_bits.size()); + assert(num_packets == 1ul<(pb, + pb_variable_array(routing_input_bits[packet_idx].begin(), routing_input_bits[packet_idx].end()), + routed_packets[0][packet_idx], + FieldT::capacity(), + FMT(this->annotation_prefix, " pack_inputs_%zu", packet_idx))); + if (packet_idx < lines_to_unpack) + { + unpack_outputs.emplace_back( + multipacking_gadget(pb, + pb_variable_array(routing_output_bits[packet_idx].begin(), routing_output_bits[packet_idx].end()), + routed_packets[num_columns][packet_idx], + FieldT::capacity(), + FMT(this->annotation_prefix, " unpack_outputs_%zu", packet_idx))); + } + } + + if (num_subpackets > 1) + { + benes_switch_bits.resize(num_columns); + for (size_t column_idx = 0; column_idx < num_columns; ++column_idx) + { + benes_switch_bits[column_idx].allocate(pb, num_packets, FMT(this->annotation_prefix, " benes_switch_bits_%zu", column_idx)); + } + } +} + +template +void benes_routing_gadget::generate_r1cs_constraints() +{ + /* packing/unpacking */ + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + pack_inputs[packet_idx].generate_r1cs_constraints(false); + if (packet_idx < lines_to_unpack) + { + unpack_outputs[packet_idx].generate_r1cs_constraints(true); + } + else + { + for (size_t subpacket_idx = 0; subpacket_idx < num_subpackets; ++subpacket_idx) + { + this->pb.add_r1cs_constraint( + r1cs_constraint(1, routed_packets[0][packet_idx][subpacket_idx], routed_packets[num_columns][packet_idx][subpacket_idx]), + FMT(this->annotation_prefix, " fix_line_%zu_subpacket_%zu", packet_idx, subpacket_idx)); + } + } + } + + /* actual routing constraints */ + for (size_t column_idx = 0; column_idx < num_columns; ++column_idx) + { + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + const size_t straight_edge = neighbors[column_idx][packet_idx].first; + const size_t cross_edge = neighbors[column_idx][packet_idx].second; + + if (num_subpackets == 1) + { + /* easy case: (cur-next)*(cur-cross) = 0 */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + routed_packets[column_idx][packet_idx][0] - routed_packets[column_idx+1][straight_edge][0], + routed_packets[column_idx][packet_idx][0] - routed_packets[column_idx+1][cross_edge][0], + 0), + FMT(this->annotation_prefix, " easy_route_%zu_%zu", column_idx, packet_idx)); + } + else + { + /* routing bit must be boolean */ + generate_boolean_r1cs_constraint(this->pb, benes_switch_bits[column_idx][packet_idx], + FMT(this->annotation_prefix, " routing_bit_%zu_%zu", column_idx, packet_idx)); + + /* route forward according to routing bits */ + for (size_t subpacket_idx = 0; subpacket_idx < num_subpackets; ++subpacket_idx) + { + /* + (1-switch_bit) * (cur-straight_edge) + switch_bit * (cur-cross_edge) = 0 + switch_bit * (cross_edge-straight_edge) = cur-straight_edge + */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + benes_switch_bits[column_idx][packet_idx], + routed_packets[column_idx+1][cross_edge][subpacket_idx] - routed_packets[column_idx+1][straight_edge][subpacket_idx], + routed_packets[column_idx][packet_idx][subpacket_idx] - routed_packets[column_idx+1][straight_edge][subpacket_idx]), + FMT(this->annotation_prefix, " route_forward_%zu_%zu_%zu", column_idx, packet_idx, subpacket_idx)); + } + } + } + } +} + +template +void benes_routing_gadget::generate_r1cs_witness(const integer_permutation& permutation) +{ + /* pack inputs */ + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + pack_inputs[packet_idx].generate_r1cs_witness_from_bits(); + } + + /* do the routing */ + const benes_routing routing = get_benes_routing(permutation); + + for (size_t column_idx = 0; column_idx < num_columns; ++column_idx) + { + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + const size_t straight_edge = neighbors[column_idx][packet_idx].first; + const size_t cross_edge = neighbors[column_idx][packet_idx].second; + + if (num_subpackets > 1) + { + this->pb.val(benes_switch_bits[column_idx][packet_idx]) = FieldT(routing[column_idx][packet_idx] ? 1 : 0); + } + + for (size_t subpacket_idx = 0; subpacket_idx < num_subpackets; ++subpacket_idx) + { + this->pb.val(routing[column_idx][packet_idx] ? + routed_packets[column_idx+1][cross_edge][subpacket_idx] : + routed_packets[column_idx+1][straight_edge][subpacket_idx]) = + this->pb.val(routed_packets[column_idx][packet_idx][subpacket_idx]); + } + } + } + + /* unpack outputs */ + for (size_t packet_idx = 0; packet_idx < lines_to_unpack; ++packet_idx) + { + unpack_outputs[packet_idx].generate_r1cs_witness_from_packed(); + } +} + +template +void test_benes_routing_gadget(const size_t num_packets, const size_t packet_size) +{ + const size_t dimension = log2(num_packets); + assert(num_packets == 1ul< pb; + integer_permutation permutation(num_packets); + permutation.random_shuffle(); + print_time("generated permutation"); + + std::vector > randbits(num_packets), outbits(num_packets); + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + randbits[packet_idx].allocate(pb, packet_size, FMT("", "randbits_%zu", packet_idx)); + outbits[packet_idx].allocate(pb, packet_size, FMT("", "outbits_%zu", packet_idx)); + + for (size_t bit_idx = 0; bit_idx < packet_size; ++bit_idx) + { + pb.val(randbits[packet_idx][bit_idx]) = (rand() % 2) ? FieldT::one() : FieldT::zero(); + } + } + print_time("generated bits to be routed"); + + benes_routing_gadget r(pb, num_packets, randbits, outbits, num_packets, "main_routing_gadget"); + r.generate_r1cs_constraints(); + print_time("generated routing constraints"); + + r.generate_r1cs_witness(permutation); + print_time("generated routing assignment"); + + printf("positive test\n"); + assert(pb.is_satisfied()); + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + for (size_t bit_idx = 0; bit_idx < packet_size; ++bit_idx) + { + assert(pb.val(outbits[permutation.get(packet_idx)][bit_idx]) == pb.val(randbits[packet_idx][bit_idx])); + } + } + + printf("negative test\n"); + pb.val(pb_variable(10)) = FieldT(12345); + assert(!pb.is_satisfied()); + + printf("num_constraints = %zu, num_variables = %zu\n", + pb.num_constraints(), + pb.constraint_system.num_variables); +} + +} // libsnark + +#endif // BENES_ROUTING_GADGET_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/routing/profiling/profile_routing_gadgets.cpp b/privacy/zsl/zsl/gadgetlib1/gadgets/routing/profiling/profile_routing_gadgets.cpp new file mode 100644 index 0000000..2ff21cf --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/routing/profiling/profile_routing_gadgets.cpp @@ -0,0 +1,107 @@ +/** @file + ***************************************************************************** + + Functions to profile the gadgetlib1 implementations of Benes and AS-Waksman routing networks. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include + +#include "common/default_types/ec_pp.hpp" +#include "common/profiling.hpp" +#include "gadgetlib1/gadgets/routing/benes_routing_gadget.hpp" +#include "gadgetlib1/gadgets/routing/as_waksman_routing_gadget.hpp" + +using namespace libsnark; + +template +void get_as_waksman_size(const size_t n, const size_t l, size_t &num_constraints, size_t &num_variables) +{ + protoboard pb; + + std::vector > randbits(n), outbits(n); + for (size_t y = 0; y < n; ++y) + { + randbits[y].allocate(pb, l, FMT("", "randbits_%zu", y)); + outbits[y].allocate(pb, l, FMT("", "outbits_%zu", y)); + } + + as_waksman_routing_gadget r(pb, n, randbits, outbits, "main_routing_gadget"); + r.generate_r1cs_constraints(); + + num_constraints = pb.num_constraints(); + num_variables = pb.num_variables(); +} + +template +void get_benes_size(const size_t n, const size_t l, size_t &num_constraints, size_t &num_variables) +{ + const size_t t = log2(n); + assert(n == 1ul< pb; + + std::vector > randbits(1ul< r(pb, n, randbits, outbits, n, "main_routing_gadget"); + r.generate_r1cs_constraints(); + + num_constraints = pb.num_constraints(); + num_variables = pb.num_variables(); +} + +template +void profile_routing_gadgets(const size_t l) +{ + printf("profiling number of constraints for powers-of-2\n"); + for (size_t n = 2; n <= 65; ++n) + { + size_t as_waksman_constr, as_waksman_vars; + get_as_waksman_size(n, l, as_waksman_constr, as_waksman_vars); + + const size_t rounded_n = 1ul<(rounded_n, l, benes_constr, benes_vars); + + printf("n = %zu (rounded = %zu), l = %zu, benes_constr = %zu, benes_vars = %zu, as_waksman_constr = %zu, as_waksman_vars = %zu, constr_ratio = %0.3f, var_ratio = %0.3f\n", + n, rounded_n, l, benes_constr, benes_vars, as_waksman_constr, as_waksman_vars, 1.*benes_constr/as_waksman_constr, 1.*benes_vars/as_waksman_vars); + } +} + +template +void profile_num_switches(const size_t l) +{ + printf("profiling number of switches in arbitrary size networks (and rounded-up for Benes)\n"); + for (size_t n = 2; n <= 65; ++n) + { + size_t as_waksman_constr, as_waksman_vars; + get_as_waksman_size(n, l, as_waksman_constr, as_waksman_vars); + + const size_t rounded_n = 1ul<(rounded_n, l, benes_constr, benes_vars); + + const size_t as_waksman_switches = (as_waksman_constr - n*(2+l))/2; + const size_t benes_switches = (benes_constr - rounded_n*(2+l))/2; + // const size_t benes_expected = log2(rounded_n)*rounded_n; // switch-Benes has (-rounded_n/2) term + printf("n = %zu (rounded_n = %zu), l = %zu, benes_switches = %zu, as_waksman_switches = %zu, ratio = %0.3f\n", + n, rounded_n, l, benes_switches, as_waksman_switches, 1.*benes_switches/as_waksman_switches); + } +} + +int main() +{ + start_profiling(); + default_ec_pp::init_public_params(); + profile_routing_gadgets >(32+16+3+2); + profile_num_switches >(1); +} diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/set_commitment/set_commitment_gadget.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/set_commitment/set_commitment_gadget.hpp new file mode 100644 index 0000000..faafa07 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/set_commitment/set_commitment_gadget.hpp @@ -0,0 +1,57 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef SET_COMMITMENT_GADGET_HPP_ +#define SET_COMMITMENT_GADGET_HPP_ + +#include "gadgetlib1/gadget.hpp" +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" +#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp" +#include "gadgetlib1/gadgets/set_commitment/set_membership_proof_variable.hpp" + +namespace libsnark { + +template +using set_commitment_variable = digest_variable; + +template +class set_commitment_gadget : public gadget { +private: + std::shared_ptr > element_block; + std::shared_ptr > element_digest; + std::shared_ptr hash_element; + std::shared_ptr > check_membership; + +public: + size_t tree_depth; + pb_variable_array element_bits; + set_commitment_variable root_digest; + set_membership_proof_variable proof; + pb_linear_combination check_successful; + + set_commitment_gadget(protoboard &pb, + const size_t max_entries, + const pb_variable_array &element_bits, + const set_commitment_variable &root_digest, + const set_membership_proof_variable &proof, + const pb_linear_combination &check_successful, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); + + static size_t root_size_in_bits(); +}; + +template +void test_set_commitment_gadget(); + +} // libsnark + +#include "gadgetlib1/gadgets/set_commitment/set_commitment_gadget.tcc" + +#endif // SET_COMMITMENT_GADGET_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/set_commitment/set_commitment_gadget.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/set_commitment/set_commitment_gadget.tcc new file mode 100644 index 0000000..97f8290 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/set_commitment/set_commitment_gadget.tcc @@ -0,0 +1,141 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef SET_COMMITMENT_GADGET_TCC_ +#define SET_COMMITMENT_GADGET_TCC_ + +#include "common/data_structures/set_commitment.hpp" + +namespace libsnark { + +template +set_commitment_gadget::set_commitment_gadget(protoboard &pb, + const size_t max_entries, + const pb_variable_array &element_bits, + const set_commitment_variable &root_digest, + const set_membership_proof_variable &proof, + const pb_linear_combination &check_successful, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), tree_depth(log2(max_entries)), element_bits(element_bits), + root_digest(root_digest), proof(proof), check_successful(check_successful) +{ + element_block.reset(new block_variable(pb, { element_bits }, FMT(annotation_prefix, " element_block"))); + + if (tree_depth == 0) + { + hash_element.reset(new HashT(pb, element_bits.size(), *element_block, root_digest, FMT(annotation_prefix, " hash_element"))); + } + else + { + element_digest.reset(new digest_variable(pb, HashT::get_digest_len(), + FMT(annotation_prefix, " element_digest"))); + hash_element.reset(new HashT(pb, element_bits.size(), *element_block, *element_digest, FMT(annotation_prefix, " hash_element"))); + check_membership.reset(new merkle_tree_check_read_gadget(pb, + tree_depth, + proof.address_bits, + *element_digest, + root_digest, + *proof.merkle_path, + check_successful, + FMT(annotation_prefix, " check_membership"))); + } +} + +template +void set_commitment_gadget::generate_r1cs_constraints() +{ + hash_element->generate_r1cs_constraints(); + + if (tree_depth > 0) + { + check_membership->generate_r1cs_constraints(); + } +} + +template +void set_commitment_gadget::generate_r1cs_witness() +{ + hash_element->generate_r1cs_witness(); + + if (tree_depth > 0) + { + check_membership->generate_r1cs_witness(); + } +} + +template +size_t set_commitment_gadget::root_size_in_bits() +{ + return merkle_tree_check_read_gadget::root_size_in_bits(); +} + +template +void test_set_commitment_gadget() +{ + const size_t digest_len = HashT::get_digest_len(); + const size_t max_set_size = 16; + const size_t value_size = (HashT::get_block_len() > 0 ? HashT::get_block_len() : 10); + + set_commitment_accumulator accumulator(max_set_size, value_size); + + std::vector set_elems; + for (size_t i = 0; i < max_set_size; ++i) + { + bit_vector elem(value_size); + std::generate(elem.begin(), elem.end(), [&]() { return std::rand() % 2; }); + set_elems.emplace_back(elem); + accumulator.add(elem); + assert(accumulator.is_in_set(elem)); + } + + protoboard pb; + pb_variable_array element_bits; + element_bits.allocate(pb, value_size, "element_bits"); + set_commitment_variable root_digest(pb, digest_len, "root_digest"); + + pb_variable check_succesful; + check_succesful.allocate(pb, "check_succesful"); + + set_membership_proof_variable proof(pb, max_set_size, "proof"); + + set_commitment_gadget sc(pb, max_set_size, element_bits, root_digest, proof, check_succesful, "sc"); + sc.generate_r1cs_constraints(); + + /* test all elements from set */ + for (size_t i = 0; i < max_set_size; ++i) + { + element_bits.fill_with_bits(pb, set_elems[i]); + pb.val(check_succesful) = FieldT::one(); + proof.generate_r1cs_witness(accumulator.get_membership_proof(set_elems[i])); + sc.generate_r1cs_witness(); + root_digest.generate_r1cs_witness(accumulator.get_commitment()); + assert(pb.is_satisfied()); + } + printf("membership tests OK\n"); + + /* test an element not in set */ + for (size_t i = 0; i < value_size; ++i) + { + pb.val(element_bits[i]) = FieldT(std::rand() % 2); + } + + pb.val(check_succesful) = FieldT::zero(); /* do not require the check result to be successful */ + proof.generate_r1cs_witness(accumulator.get_membership_proof(set_elems[0])); /* try it with invalid proof */ + sc.generate_r1cs_witness(); + root_digest.generate_r1cs_witness(accumulator.get_commitment()); + assert(pb.is_satisfied()); + + pb.val(check_succesful) = FieldT::one(); /* now require the check result to be succesful */ + proof.generate_r1cs_witness(accumulator.get_membership_proof(set_elems[0])); /* try it with invalid proof */ + sc.generate_r1cs_witness(); + root_digest.generate_r1cs_witness(accumulator.get_commitment()); + assert(!pb.is_satisfied()); /* the protoboard should be unsatisfied */ + printf("non-membership test OK\n"); +} + +} // libsnark + +#endif // SET_COMMITMENT_GADGET_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/set_commitment/set_membership_proof_variable.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/set_commitment/set_membership_proof_variable.hpp new file mode 100644 index 0000000..4aa9a02 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/set_commitment/set_membership_proof_variable.hpp @@ -0,0 +1,43 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SET_MEMBERSHIP_PROOF_VARIABLE_HPP_ +#define SET_MEMBERSHIP_PROOF_VARIABLE_HPP_ + +#include "common/data_structures/set_commitment.hpp" +#include "gadgetlib1/gadget.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" +#include "gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp" + +namespace libsnark { + +template +class set_membership_proof_variable : public gadget { +public: + pb_variable_array address_bits; + std::shared_ptr > merkle_path; + + const size_t max_entries; + const size_t tree_depth; + + set_membership_proof_variable(protoboard &pb, + const size_t max_entries, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(const set_membership_proof &proof); + + set_membership_proof get_membership_proof() const; + + static r1cs_variable_assignment as_r1cs_variable_assignment(const set_membership_proof &proof); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/set_commitment/set_membership_proof_variable.tcc" + +#endif // SET_MEMBERSHIP_PROOF_VARIABLE_HPP diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/set_commitment/set_membership_proof_variable.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/set_commitment/set_membership_proof_variable.tcc new file mode 100644 index 0000000..6a77550 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/set_commitment/set_membership_proof_variable.tcc @@ -0,0 +1,82 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SET_MEMBERSHIP_PROOF_VARIABLE_TCC_ +#define SET_MEMBERSHIP_PROOF_VARIABLE_TCC_ + +namespace libsnark { + +template +set_membership_proof_variable::set_membership_proof_variable(protoboard &pb, + const size_t max_entries, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + max_entries(max_entries), + tree_depth(log2(max_entries)) +{ + if (tree_depth > 0) + { + address_bits.allocate(pb, tree_depth, FMT(annotation_prefix, " address_bits")); + merkle_path.reset(new merkle_authentication_path_variable(pb, tree_depth, FMT(annotation_prefix, " merkle_path"))); + } +} + +template +void set_membership_proof_variable::generate_r1cs_constraints() +{ + if (tree_depth > 0) + { + for (size_t i = 0; i < tree_depth; ++i) + { + generate_boolean_r1cs_constraint(this->pb, address_bits[i], FMT(this->annotation_prefix, " address_bits")); + } + merkle_path->generate_r1cs_constraints(); + } +} + +template +void set_membership_proof_variable::generate_r1cs_witness(const set_membership_proof &proof) +{ + if (tree_depth > 0) + { + address_bits.fill_with_bits_of_field_element(this->pb, FieldT(proof.address)); + merkle_path->generate_r1cs_witness(proof.address, proof.merkle_path); + } +} + +template +set_membership_proof set_membership_proof_variable::get_membership_proof() const +{ + set_membership_proof result; + + if (tree_depth == 0) + { + result.address = 0; + } + else + { + result.address = address_bits.get_field_element_from_bits(this->pb).as_ulong(); + result.merkle_path = merkle_path->get_authentication_path(result.address); + } + + return result; +} + +template +r1cs_variable_assignment set_membership_proof_variable::as_r1cs_variable_assignment(const set_membership_proof &proof) +{ + protoboard pb; + const size_t max_entries = (1ul << (proof.merkle_path.size())); + set_membership_proof_variable proof_variable(pb, max_entries, "proof_variable"); + proof_variable.generate_r1cs_witness(proof); + + return pb.full_variable_assignment(); +} + +} // libsnark + +#endif // SET_MEMBERSHIP_PROOF_VARIABLE_TCC diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/set_commitment/tests/test_set_commitment_gadget.cpp b/privacy/zsl/zsl/gadgetlib1/gadgets/set_commitment/tests/test_set_commitment_gadget.cpp new file mode 100644 index 0000000..ef9f7ea --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/set_commitment/tests/test_set_commitment_gadget.cpp @@ -0,0 +1,44 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifdef CURVE_BN128 +#include "algebra/curves/bn128/bn128_pp.hpp" +#endif +#include "algebra/curves/edwards/edwards_pp.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +#include "gadgetlib1/gadgets/set_commitment/set_commitment_gadget.hpp" +#include "gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp" + +using namespace libsnark; + +template +void test_all_set_commitment_gadgets() +{ + typedef Fr FieldT; + test_set_commitment_gadget >(); + test_set_commitment_gadget >(); +} + +int main(void) +{ + start_profiling(); + +#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled + bn128_pp::init_public_params(); + test_all_set_commitment_gadgets(); +#endif + + edwards_pp::init_public_params(); + test_all_set_commitment_gadgets(); + + mnt4_pp::init_public_params(); + test_all_set_commitment_gadgets(); + + mnt6_pp::init_public_params(); + test_all_set_commitment_gadgets(); +} diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/verifiers/r1cs_ppzksnark_verifier_gadget.hpp b/privacy/zsl/zsl/gadgetlib1/gadgets/verifiers/r1cs_ppzksnark_verifier_gadget.hpp new file mode 100644 index 0000000..f92cb5b --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/verifiers/r1cs_ppzksnark_verifier_gadget.hpp @@ -0,0 +1,250 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the the R1CS ppzkSNARK verifier gadget. + + The gadget r1cs_ppzksnark_verifier_gadget verifiers correct computation of r1cs_ppzksnark_verifier_strong_IC. + The gadget is built from two main sub-gadgets: + - r1cs_ppzksnark_verifier_process_vk_gadget, which verifies correct computation of r1cs_ppzksnark_verifier_process_vk, and + - r1cs_ppzksnark_online_verifier_gadget, which verifies correct computation of r1cs_ppzksnark_online_verifier_strong_IC. + See r1cs_ppzksnark.hpp for description of the aforementioned functions. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_PPZKSNARK_VERIFIER_GADGET_HPP_ +#define R1CS_PPZKSNARK_VERIFIER_GADGET_HPP_ + +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "gadgetlib1/gadgets/curves/weierstrass_g1_gadget.hpp" +#include "gadgetlib1/gadgets/curves/weierstrass_g2_gadget.hpp" +#include "gadgetlib1/gadgets/pairing/pairing_checks.hpp" +#include "gadgetlib1/gadgets/pairing/pairing_params.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" + +namespace libsnark { + +template +class r1cs_ppzksnark_proof_variable : public gadget > { +public: + typedef Fr FieldT; + + std::shared_ptr > g_A_g; + std::shared_ptr > g_A_h; + std::shared_ptr > g_B_g; + std::shared_ptr > g_B_h; + std::shared_ptr > g_C_g; + std::shared_ptr > g_C_h; + std::shared_ptr > g_H; + std::shared_ptr > g_K; + + std::vector > > all_G1_vars; + std::vector > > all_G2_vars; + + std::vector > > all_G1_checkers; + std::shared_ptr > G2_checker; + + pb_variable_array proof_contents; + + r1cs_ppzksnark_proof_variable(protoboard &pb, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(const r1cs_ppzksnark_proof > &proof); + static size_t size(); +}; + +template +class r1cs_ppzksnark_verification_key_variable : public gadget > { +public: + typedef Fr FieldT; + + std::shared_ptr > alphaA_g2; + std::shared_ptr > alphaB_g1; + std::shared_ptr > alphaC_g2; + std::shared_ptr > gamma_g2; + std::shared_ptr > gamma_beta_g1; + std::shared_ptr > gamma_beta_g2; + std::shared_ptr > rC_Z_g2; + std::shared_ptr > encoded_IC_base; + std::vector > > encoded_IC_query; + + pb_variable_array all_bits; + pb_linear_combination_array all_vars; + size_t input_size; + + std::vector > > all_G1_vars; + std::vector > > all_G2_vars; + + std::shared_ptr > packer; + + // Unfortunately, g++ 4.9 and g++ 5.0 have a bug related to + // incorrect inlining of small functions: + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65307, which + // produces wrong assembly even at -O1. The test case at the bug + // report is directly derived from this code here. As a temporary + // work-around we mark the key functions noinline to hint compiler + // that inlining should not be performed. + + // TODO: remove later, when g++ developers fix the bug. + + __attribute__((noinline)) r1cs_ppzksnark_verification_key_variable(protoboard &pb, + const pb_variable_array &all_bits, + const size_t input_size, + const std::string &annotation_prefix); + void generate_r1cs_constraints(const bool enforce_bitness); + void generate_r1cs_witness(const r1cs_ppzksnark_verification_key > &vk); + void generate_r1cs_witness(const bit_vector &vk_bits); + bit_vector get_bits() const; + static size_t __attribute__((noinline)) size_in_bits(const size_t input_size); + static bit_vector get_verification_key_bits(const r1cs_ppzksnark_verification_key > &r1cs_vk); +}; + +template +class r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable { +public: + typedef Fr FieldT; + + std::shared_ptr > encoded_IC_base; + std::vector > > encoded_IC_query; + + std::shared_ptr > vk_alphaB_g1_precomp; + std::shared_ptr > vk_gamma_beta_g1_precomp; + + std::shared_ptr > pp_G2_one_precomp; + std::shared_ptr > vk_alphaA_g2_precomp; + std::shared_ptr > vk_alphaC_g2_precomp; + std::shared_ptr > vk_gamma_beta_g2_precomp; + std::shared_ptr > vk_gamma_g2_precomp; + std::shared_ptr > vk_rC_Z_g2_precomp; + + r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable(); + r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable(protoboard &pb, + const r1cs_ppzksnark_verification_key > &r1cs_vk, + const std::string &annotation_prefix); +}; + +template +class r1cs_ppzksnark_verifier_process_vk_gadget : public gadget > { +public: + typedef Fr FieldT; + + std::shared_ptr > compute_vk_alphaB_g1_precomp; + std::shared_ptr > compute_vk_gamma_beta_g1_precomp; + + std::shared_ptr > compute_vk_alphaA_g2_precomp; + std::shared_ptr > compute_vk_alphaC_g2_precomp; + std::shared_ptr > compute_vk_gamma_beta_g2_precomp; + std::shared_ptr > compute_vk_gamma_g2_precomp; + std::shared_ptr > compute_vk_rC_Z_g2_precomp; + + r1cs_ppzksnark_verification_key_variable vk; + r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable &pvk; // important to have a reference here + + r1cs_ppzksnark_verifier_process_vk_gadget(protoboard &pb, + const r1cs_ppzksnark_verification_key_variable &vk, + r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable &pvk, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +class r1cs_ppzksnark_online_verifier_gadget : public gadget > { +public: + typedef Fr FieldT; + + r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable pvk; + + pb_variable_array input; + size_t elt_size; + r1cs_ppzksnark_proof_variable proof; + pb_variable result; + const size_t input_len; + + std::shared_ptr > acc; + std::shared_ptr > accumulate_input; + + std::shared_ptr > proof_g_A_g_acc; + std::shared_ptr > compute_proof_g_A_g_acc; + std::shared_ptr > proof_g_A_g_acc_C; + std::shared_ptr > compute_proof_g_A_g_acc_C; + + std::shared_ptr > proof_g_A_h_precomp; + std::shared_ptr > proof_g_A_g_acc_C_precomp; + std::shared_ptr > proof_g_A_g_acc_precomp; + std::shared_ptr > proof_g_A_g_precomp; + std::shared_ptr > proof_g_B_h_precomp; + std::shared_ptr > proof_g_C_h_precomp; + std::shared_ptr > proof_g_C_g_precomp; + std::shared_ptr > proof_g_K_precomp; + std::shared_ptr > proof_g_H_precomp; + + std::shared_ptr > proof_g_B_g_precomp; + + std::shared_ptr > compute_proof_g_A_h_precomp; + std::shared_ptr > compute_proof_g_A_g_acc_C_precomp; + std::shared_ptr > compute_proof_g_A_g_acc_precomp; + std::shared_ptr > compute_proof_g_A_g_precomp; + std::shared_ptr > compute_proof_g_B_h_precomp; + std::shared_ptr > compute_proof_g_C_h_precomp; + std::shared_ptr > compute_proof_g_C_g_precomp; + std::shared_ptr > compute_proof_g_K_precomp; + std::shared_ptr > compute_proof_g_H_precomp; + + std::shared_ptr > compute_proof_g_B_g_precomp; + + std::shared_ptr > check_kc_A_valid; + std::shared_ptr > check_kc_B_valid; + std::shared_ptr > check_kc_C_valid; + std::shared_ptr > check_QAP_valid; + std::shared_ptr > check_CC_valid; + + pb_variable kc_A_valid; + pb_variable kc_B_valid; + pb_variable kc_C_valid; + pb_variable QAP_valid; + pb_variable CC_valid; + + pb_variable_array all_test_results; + std::shared_ptr > all_tests_pass; + + r1cs_ppzksnark_online_verifier_gadget(protoboard &pb, + const r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable &pvk, + const pb_variable_array &input, + const size_t elt_size, + const r1cs_ppzksnark_proof_variable &proof, + const pb_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +class r1cs_ppzksnark_verifier_gadget : public gadget > { +public: + typedef Fr FieldT; + + std::shared_ptr > pvk; + std::shared_ptr > compute_pvk; + std::shared_ptr > online_verifier; + + r1cs_ppzksnark_verifier_gadget(protoboard &pb, + const r1cs_ppzksnark_verification_key_variable &vk, + const pb_variable_array &input, + const size_t elt_size, + const r1cs_ppzksnark_proof_variable &proof, + const pb_variable &result, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/verifiers/r1cs_ppzksnark_verifier_gadget.tcc" + +#endif // R1CS_PPZKSNARK_VERIFIER_GADGET_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/verifiers/r1cs_ppzksnark_verifier_gadget.tcc b/privacy/zsl/zsl/gadgetlib1/gadgets/verifiers/r1cs_ppzksnark_verifier_gadget.tcc new file mode 100644 index 0000000..f372fb6 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/verifiers/r1cs_ppzksnark_verifier_gadget.tcc @@ -0,0 +1,514 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the the R1CS ppzkSNARK verifier gadget. + + See r1cs_ppzksnark_verifier_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_PPZKSNARK_VERIFIER_GADGET_TCC_ +#define R1CS_PPZKSNARK_VERIFIER_GADGET_TCC_ + +#include "gadgetlib1/constraint_profiling.hpp" + +namespace libsnark { + +template +r1cs_ppzksnark_proof_variable::r1cs_ppzksnark_proof_variable(protoboard &pb, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + const size_t num_G1 = 7; + const size_t num_G2 = 1; + + g_A_g.reset(new G1_variable(pb, FMT(annotation_prefix, " g_A_g"))); + g_A_h.reset(new G1_variable(pb, FMT(annotation_prefix, " g_A_h"))); + g_B_g.reset(new G2_variable(pb, FMT(annotation_prefix, " g_B_g"))); + g_B_h.reset(new G1_variable(pb, FMT(annotation_prefix, " g_B_h"))); + g_C_g.reset(new G1_variable(pb, FMT(annotation_prefix, " g_C_g"))); + g_C_h.reset(new G1_variable(pb, FMT(annotation_prefix, " g_C_h"))); + g_H.reset(new G1_variable(pb, FMT(annotation_prefix, " g_H"))); + g_K.reset(new G1_variable(pb, FMT(annotation_prefix, " g_K"))); + + all_G1_vars = { g_A_g, g_A_h, g_B_h, g_C_g, g_C_h, g_H,g_K }; + all_G2_vars = { g_B_g }; + + all_G1_checkers.resize(all_G1_vars.size()); + + for (size_t i = 0; i < all_G1_vars.size(); ++i) + { + all_G1_checkers[i].reset(new G1_checker_gadget(pb, *all_G1_vars[i], FMT(annotation_prefix, " all_G1_checkers_%zu", i))); + } + G2_checker.reset(new G2_checker_gadget(pb, *g_B_g, FMT(annotation_prefix, " G2_checker"))); + + assert(all_G1_vars.size() == num_G1); + assert(all_G2_vars.size() == num_G2); +} + +template +void r1cs_ppzksnark_proof_variable::generate_r1cs_constraints() +{ + for (auto &G1_checker : all_G1_checkers) + { + G1_checker->generate_r1cs_constraints(); + } + + G2_checker->generate_r1cs_constraints(); +} + +template +void r1cs_ppzksnark_proof_variable::generate_r1cs_witness(const r1cs_ppzksnark_proof > &proof) +{ + std::vector > > G1_elems; + std::vector > > G2_elems; + + G1_elems = { proof.g_A.g, proof.g_A.h, proof.g_B.h, proof.g_C.g, proof.g_C.h, proof.g_H, proof.g_K }; + G2_elems = { proof.g_B.g }; + + assert(G1_elems.size() == all_G1_vars.size()); + assert(G2_elems.size() == all_G2_vars.size()); + + for (size_t i = 0; i < G1_elems.size(); ++i) + { + all_G1_vars[i]->generate_r1cs_witness(G1_elems[i]); + } + + for (size_t i = 0; i < G2_elems.size(); ++i) + { + all_G2_vars[i]->generate_r1cs_witness(G2_elems[i]); + } + + for (auto &G1_checker : all_G1_checkers) + { + G1_checker->generate_r1cs_witness(); + } + + G2_checker->generate_r1cs_witness(); +} + +template +size_t r1cs_ppzksnark_proof_variable::size() +{ + const size_t num_G1 = 7; + const size_t num_G2 = 1; + return (num_G1 * G1_variable::num_field_elems + num_G2 * G2_variable::num_field_elems); +} + +template +r1cs_ppzksnark_verification_key_variable::r1cs_ppzksnark_verification_key_variable(protoboard &pb, + const pb_variable_array &all_bits, + const size_t input_size, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + all_bits(all_bits), + input_size(input_size) +{ + const size_t num_G1 = 2 + (input_size + 1); + const size_t num_G2 = 5; + + assert(all_bits.size() == (G1_variable::size_in_bits() * num_G1 + G2_variable::size_in_bits() * num_G2)); + + this->alphaA_g2.reset(new G2_variable(pb, FMT(annotation_prefix, " alphaA_g2"))); + this->alphaB_g1.reset(new G1_variable(pb, FMT(annotation_prefix, " alphaB_g1"))); + this->alphaC_g2.reset(new G2_variable(pb, FMT(annotation_prefix, " alphaC_g2"))); + this->gamma_g2.reset(new G2_variable(pb, FMT(annotation_prefix, " gamma_g2"))); + this->gamma_beta_g1.reset(new G1_variable(pb, FMT(annotation_prefix, " gamma_beta_g1"))); + this->gamma_beta_g2.reset(new G2_variable(pb, FMT(annotation_prefix, " gamma_beta_g2"))); + this->rC_Z_g2.reset(new G2_variable(pb, FMT(annotation_prefix, " rC_Z_g2"))); + + all_G1_vars = { this->alphaB_g1, this->gamma_beta_g1 }; + all_G2_vars = { this->alphaA_g2, this->alphaC_g2, this->gamma_g2, this->gamma_beta_g2, this->rC_Z_g2 }; + + this->encoded_IC_query.resize(input_size); + this->encoded_IC_base.reset(new G1_variable(pb, FMT(annotation_prefix, " encoded_IC_base"))); + this->all_G1_vars.emplace_back(this->encoded_IC_base); + + for (size_t i = 0; i < input_size; ++i) + { + this->encoded_IC_query[i].reset(new G1_variable(pb, FMT(annotation_prefix, " encoded_IC_query_%zu", i))); + all_G1_vars.emplace_back(this->encoded_IC_query[i]); + } + + for (auto &G1_var : all_G1_vars) + { + all_vars.insert(all_vars.end(), G1_var->all_vars.begin(), G1_var->all_vars.end()); + } + + for (auto &G2_var : all_G2_vars) + { + all_vars.insert(all_vars.end(), G2_var->all_vars.begin(), G2_var->all_vars.end()); + } + + assert(all_G1_vars.size() == num_G1); + assert(all_G2_vars.size() == num_G2); + assert(all_vars.size() == (num_G1 * G1_variable::num_variables() + num_G2 * G2_variable::num_variables())); + + packer.reset(new multipacking_gadget(pb, all_bits, all_vars, FieldT::size_in_bits(), FMT(annotation_prefix, " packer"))); +} + +template +void r1cs_ppzksnark_verification_key_variable::generate_r1cs_constraints(const bool enforce_bitness) +{ + packer->generate_r1cs_constraints(enforce_bitness); +} + +template +void r1cs_ppzksnark_verification_key_variable::generate_r1cs_witness(const r1cs_ppzksnark_verification_key > &vk) +{ + std::vector > > G1_elems; + std::vector > > G2_elems; + + G1_elems = { vk.alphaB_g1, vk.gamma_beta_g1 }; + G2_elems = { vk.alphaA_g2, vk.alphaC_g2, vk.gamma_g2, vk.gamma_beta_g2, vk.rC_Z_g2 }; + + assert(vk.encoded_IC_query.rest.indices.size() == input_size); + G1_elems.emplace_back(vk.encoded_IC_query.first); + for (size_t i = 0; i < input_size; ++i) + { + assert(vk.encoded_IC_query.rest.indices[i] == i); + G1_elems.emplace_back(vk.encoded_IC_query.rest.values[i]); + } + + assert(G1_elems.size() == all_G1_vars.size()); + assert(G2_elems.size() == all_G2_vars.size()); + + for (size_t i = 0; i < G1_elems.size(); ++i) + { + all_G1_vars[i]->generate_r1cs_witness(G1_elems[i]); + } + + for (size_t i = 0; i < G2_elems.size(); ++i) + { + all_G2_vars[i]->generate_r1cs_witness(G2_elems[i]); + } + + packer->generate_r1cs_witness_from_packed(); +} + +template +void r1cs_ppzksnark_verification_key_variable::generate_r1cs_witness(const bit_vector &vk_bits) +{ + all_bits.fill_with_bits(this->pb, vk_bits); + packer->generate_r1cs_witness_from_bits(); +} + +template +bit_vector r1cs_ppzksnark_verification_key_variable::get_bits() const +{ + return all_bits.get_bits(this->pb); +} + +template +size_t r1cs_ppzksnark_verification_key_variable::size_in_bits(const size_t input_size) +{ + const size_t num_G1 = 2 + (input_size + 1); + const size_t num_G2 = 5; + const size_t result = G1_variable::size_in_bits() * num_G1 + G2_variable::size_in_bits() * num_G2; + printf("G1_size_in_bits = %zu, G2_size_in_bits = %zu\n", G1_variable::size_in_bits(), G2_variable::size_in_bits()); + printf("r1cs_ppzksnark_verification_key_variable::size_in_bits(%zu) = %zu\n", input_size, result); + return result; +} + +template +bit_vector r1cs_ppzksnark_verification_key_variable::get_verification_key_bits(const r1cs_ppzksnark_verification_key > &r1cs_vk) +{ + typedef Fr FieldT; + + const size_t input_size_in_elts = r1cs_vk.encoded_IC_query.rest.indices.size(); // this might be approximate for bound verification keys, however they are not supported by r1cs_ppzksnark_verification_key_variable + const size_t vk_size_in_bits = r1cs_ppzksnark_verification_key_variable::size_in_bits(input_size_in_elts); + + protoboard pb; + pb_variable_array vk_bits; + vk_bits.allocate(pb, vk_size_in_bits, "vk_bits"); + r1cs_ppzksnark_verification_key_variable vk(pb, vk_bits, input_size_in_elts, "translation_step_vk"); + vk.generate_r1cs_witness(r1cs_vk); + + return vk.get_bits(); +} + +template +r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable::r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable() +{ + // will be allocated outside +} + +template +r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable::r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable(protoboard &pb, + const r1cs_ppzksnark_verification_key > &r1cs_vk, + const std::string &annotation_prefix) +{ + encoded_IC_base.reset(new G1_variable(pb, r1cs_vk.encoded_IC_query.first, FMT(annotation_prefix, " encoded_IC_base"))); + encoded_IC_query.resize(r1cs_vk.encoded_IC_query.rest.indices.size()); + for (size_t i = 0; i < r1cs_vk.encoded_IC_query.rest.indices.size(); ++i) + { + assert(r1cs_vk.encoded_IC_query.rest.indices[i] == i); + encoded_IC_query[i].reset(new G1_variable(pb, r1cs_vk.encoded_IC_query.rest.values[i], FMT(annotation_prefix, " encoded_IC_query"))); + } + + vk_alphaB_g1_precomp.reset(new G1_precomputation(pb, r1cs_vk.alphaB_g1, FMT(annotation_prefix, " vk_alphaB_g1_precomp"))); + vk_gamma_beta_g1_precomp.reset(new G1_precomputation(pb, r1cs_vk.gamma_beta_g1, FMT(annotation_prefix, " vk_gamma_beta_g1_precomp"))); + + pp_G2_one_precomp.reset(new G2_precomputation(pb, G2 >::one(), FMT(annotation_prefix, " pp_G2_one_precomp"))); + vk_alphaA_g2_precomp.reset(new G2_precomputation(pb, r1cs_vk.alphaA_g2, FMT(annotation_prefix, " vk_alphaA_g2_precomp"))); + vk_alphaC_g2_precomp.reset(new G2_precomputation(pb, r1cs_vk.alphaC_g2, FMT(annotation_prefix, " vk_alphaC_g2_precomp"))); + vk_gamma_beta_g2_precomp.reset(new G2_precomputation(pb, r1cs_vk.gamma_beta_g2, FMT(annotation_prefix, " vk_gamma_beta_g2_precomp"))); + vk_gamma_g2_precomp.reset(new G2_precomputation(pb, r1cs_vk.gamma_g2, FMT(annotation_prefix, " vk_gamma_g2_precomp"))); + vk_rC_Z_g2_precomp.reset(new G2_precomputation(pb, r1cs_vk.rC_Z_g2, FMT(annotation_prefix, " vk_rC_Z_g2_precomp"))); +} + +template +r1cs_ppzksnark_verifier_process_vk_gadget::r1cs_ppzksnark_verifier_process_vk_gadget(protoboard &pb, + const r1cs_ppzksnark_verification_key_variable &vk, + r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable &pvk, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + vk(vk), + pvk(pvk) +{ + pvk.encoded_IC_base = vk.encoded_IC_base; + pvk.encoded_IC_query = vk.encoded_IC_query; + + pvk.vk_alphaB_g1_precomp.reset(new G1_precomputation()); + pvk.vk_gamma_beta_g1_precomp.reset(new G1_precomputation()); + + pvk.pp_G2_one_precomp.reset(new G2_precomputation()); + pvk.vk_alphaA_g2_precomp.reset(new G2_precomputation()); + pvk.vk_alphaC_g2_precomp.reset(new G2_precomputation()); + pvk.vk_gamma_beta_g2_precomp.reset(new G2_precomputation()); + pvk.vk_gamma_g2_precomp.reset(new G2_precomputation()); + pvk.vk_rC_Z_g2_precomp.reset(new G2_precomputation()); + + compute_vk_alphaB_g1_precomp.reset(new precompute_G1_gadget(pb, *vk.alphaB_g1, *pvk.vk_alphaB_g1_precomp, FMT(annotation_prefix, " compute_vk_alphaB_g1_precomp"))); + compute_vk_gamma_beta_g1_precomp.reset(new precompute_G1_gadget(pb, *vk.gamma_beta_g1, *pvk.vk_gamma_beta_g1_precomp, FMT(annotation_prefix, " compute_vk_gamma_beta_g1_precomp"))); + + pvk.pp_G2_one_precomp.reset(new G2_precomputation(pb, G2 >::one(), FMT(annotation_prefix, " pp_G2_one_precomp"))); + compute_vk_alphaA_g2_precomp.reset(new precompute_G2_gadget(pb, *vk.alphaA_g2, *pvk.vk_alphaA_g2_precomp, FMT(annotation_prefix, " compute_vk_alphaA_g2_precomp"))); + compute_vk_alphaC_g2_precomp.reset(new precompute_G2_gadget(pb, *vk.alphaC_g2, *pvk.vk_alphaC_g2_precomp, FMT(annotation_prefix, " compute_vk_alphaC_g2_precomp"))); + compute_vk_gamma_beta_g2_precomp.reset(new precompute_G2_gadget(pb, *vk.gamma_beta_g2, *pvk.vk_gamma_beta_g2_precomp, FMT(annotation_prefix, " compute_vk_gamma_beta_g2_precomp"))); + compute_vk_gamma_g2_precomp.reset(new precompute_G2_gadget(pb, *vk.gamma_g2, *pvk.vk_gamma_g2_precomp, FMT(annotation_prefix, " compute_vk_gamma_g2_precomp"))); + compute_vk_rC_Z_g2_precomp.reset(new precompute_G2_gadget(pb, *vk.rC_Z_g2, *pvk.vk_rC_Z_g2_precomp, FMT(annotation_prefix, " compute_vk_rC_Z_g2_precomp"))); +} + +template +void r1cs_ppzksnark_verifier_process_vk_gadget::generate_r1cs_constraints() +{ + compute_vk_alphaB_g1_precomp->generate_r1cs_constraints(); + compute_vk_gamma_beta_g1_precomp->generate_r1cs_constraints(); + + compute_vk_alphaA_g2_precomp->generate_r1cs_constraints(); + compute_vk_alphaC_g2_precomp->generate_r1cs_constraints(); + compute_vk_gamma_beta_g2_precomp->generate_r1cs_constraints(); + compute_vk_gamma_g2_precomp->generate_r1cs_constraints(); + compute_vk_rC_Z_g2_precomp->generate_r1cs_constraints(); +} + +template +void r1cs_ppzksnark_verifier_process_vk_gadget::generate_r1cs_witness() +{ + compute_vk_alphaB_g1_precomp->generate_r1cs_witness(); + compute_vk_gamma_beta_g1_precomp->generate_r1cs_witness(); + + compute_vk_alphaA_g2_precomp->generate_r1cs_witness(); + compute_vk_alphaC_g2_precomp->generate_r1cs_witness(); + compute_vk_gamma_beta_g2_precomp->generate_r1cs_witness(); + compute_vk_gamma_g2_precomp->generate_r1cs_witness(); + compute_vk_rC_Z_g2_precomp->generate_r1cs_witness(); +} + +template +r1cs_ppzksnark_online_verifier_gadget::r1cs_ppzksnark_online_verifier_gadget(protoboard &pb, + const r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable &pvk, + const pb_variable_array &input, + const size_t elt_size, + const r1cs_ppzksnark_proof_variable &proof, + const pb_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + pvk(pvk), + input(input), + elt_size(elt_size), + proof(proof), + result(result), + input_len(input.size()) +{ + // accumulate input and store base in acc + acc.reset(new G1_variable(pb, FMT(annotation_prefix, " acc"))); + std::vector > IC_terms; + for (size_t i = 0; i < pvk.encoded_IC_query.size(); ++i) + { + IC_terms.emplace_back(*(pvk.encoded_IC_query[i])); + } + accumulate_input.reset(new G1_multiscalar_mul_gadget(pb, *(pvk.encoded_IC_base), input, elt_size, IC_terms, *acc, FMT(annotation_prefix, " accumulate_input"))); + + // allocate results for precomputation + proof_g_A_h_precomp.reset(new G1_precomputation()); + proof_g_A_g_acc_C_precomp.reset(new G1_precomputation()); + proof_g_A_g_acc_precomp.reset(new G1_precomputation()); + proof_g_A_g_precomp.reset(new G1_precomputation()); + proof_g_B_h_precomp.reset(new G1_precomputation()); + proof_g_C_h_precomp.reset(new G1_precomputation()); + proof_g_C_g_precomp.reset(new G1_precomputation()); + proof_g_K_precomp.reset(new G1_precomputation()); + proof_g_H_precomp.reset(new G1_precomputation()); + + proof_g_B_g_precomp.reset(new G2_precomputation()); + + // do the necessary precomputations + // compute things not available in plain from proof/vk + proof_g_A_g_acc.reset(new G1_variable(pb, FMT(annotation_prefix, " proof_g_A_g_acc"))); + compute_proof_g_A_g_acc.reset(new G1_add_gadget(pb, *(proof.g_A_g), *acc , *proof_g_A_g_acc, FMT(annotation_prefix, " compute_proof_g_A_g_acc"))); + proof_g_A_g_acc_C.reset(new G1_variable(pb, FMT(annotation_prefix, " proof_g_A_g_acc_C"))); + compute_proof_g_A_g_acc_C.reset(new G1_add_gadget(pb, *proof_g_A_g_acc, *(proof.g_C_g) , *proof_g_A_g_acc_C, FMT(annotation_prefix, " compute_proof_g_A_g_acc_C"))); + + compute_proof_g_A_g_acc_precomp.reset(new precompute_G1_gadget(pb, *proof_g_A_g_acc, *proof_g_A_g_acc_precomp, FMT(annotation_prefix, " compute_proof_g_A_g_acc_precomp"))); + compute_proof_g_A_g_acc_C_precomp.reset(new precompute_G1_gadget(pb, *proof_g_A_g_acc_C, *proof_g_A_g_acc_C_precomp, FMT(annotation_prefix, " compute_proof_g_A_g_acc_C_precomp"))); + + // do other precomputations + compute_proof_g_A_h_precomp.reset(new precompute_G1_gadget(pb, *(proof.g_A_h), *proof_g_A_h_precomp, FMT(annotation_prefix, " compute_proof_g_A_h_precomp"))); + compute_proof_g_A_g_precomp.reset(new precompute_G1_gadget(pb, *(proof.g_A_g), *proof_g_A_g_precomp, FMT(annotation_prefix, " compute_proof_g_A_g_precomp"))); + compute_proof_g_B_h_precomp.reset(new precompute_G1_gadget(pb, *(proof.g_B_h), *proof_g_B_h_precomp, FMT(annotation_prefix, " compute_proof_g_B_h_precomp"))); + compute_proof_g_C_h_precomp.reset(new precompute_G1_gadget(pb, *(proof.g_C_h), *proof_g_C_h_precomp, FMT(annotation_prefix, " compute_proof_g_C_h_precomp"))); + compute_proof_g_C_g_precomp.reset(new precompute_G1_gadget(pb, *(proof.g_C_g), *proof_g_C_g_precomp, FMT(annotation_prefix, " compute_proof_g_C_g_precomp"))); + compute_proof_g_H_precomp.reset(new precompute_G1_gadget(pb, *(proof.g_H), *proof_g_H_precomp, FMT(annotation_prefix, " compute_proof_g_H_precomp"))); + compute_proof_g_K_precomp.reset(new precompute_G1_gadget(pb, *(proof.g_K), *proof_g_K_precomp, FMT(annotation_prefix, " compute_proof_g_K_precomp"))); + compute_proof_g_B_g_precomp.reset(new precompute_G2_gadget(pb, *(proof.g_B_g), *proof_g_B_g_precomp, FMT(annotation_prefix, " compute_proof_g_B_g_precomp"))); + + // check validity of A knowledge commitment + kc_A_valid.allocate(pb, FMT(annotation_prefix, " kc_A_valid")); + check_kc_A_valid.reset(new check_e_equals_e_gadget(pb, *proof_g_A_g_precomp, *(pvk.vk_alphaA_g2_precomp), *proof_g_A_h_precomp, *(pvk.pp_G2_one_precomp), kc_A_valid, FMT(annotation_prefix, " check_kc_A_valid"))); + + // check validity of B knowledge commitment + kc_B_valid.allocate(pb, FMT(annotation_prefix, " kc_B_valid")); + check_kc_B_valid.reset(new check_e_equals_e_gadget(pb, *(pvk.vk_alphaB_g1_precomp), *proof_g_B_g_precomp, *proof_g_B_h_precomp, *(pvk.pp_G2_one_precomp), kc_B_valid, FMT(annotation_prefix, " check_kc_B_valid"))); + + // check validity of C knowledge commitment + kc_C_valid.allocate(pb, FMT(annotation_prefix, " kc_C_valid")); + check_kc_C_valid.reset(new check_e_equals_e_gadget(pb, *proof_g_C_g_precomp, *(pvk.vk_alphaC_g2_precomp), *proof_g_C_h_precomp, *(pvk.pp_G2_one_precomp), kc_C_valid, FMT(annotation_prefix, " check_kc_C_valid"))); + + // check QAP divisibility + QAP_valid.allocate(pb, FMT(annotation_prefix, " QAP_valid")); + check_QAP_valid.reset(new check_e_equals_ee_gadget(pb, *proof_g_A_g_acc_precomp, *proof_g_B_g_precomp, *proof_g_H_precomp, *(pvk.vk_rC_Z_g2_precomp), *proof_g_C_g_precomp, *(pvk.pp_G2_one_precomp), QAP_valid, FMT(annotation_prefix, " check_QAP_valid"))); + + // check coefficients + CC_valid.allocate(pb, FMT(annotation_prefix, " CC_valid")); + check_CC_valid.reset(new check_e_equals_ee_gadget(pb, *proof_g_K_precomp, *(pvk.vk_gamma_g2_precomp), *proof_g_A_g_acc_C_precomp, *(pvk.vk_gamma_beta_g2_precomp), *(pvk.vk_gamma_beta_g1_precomp), *proof_g_B_g_precomp, CC_valid, FMT(annotation_prefix, " check_CC_valid"))); + + // final constraint + all_test_results.emplace_back(kc_A_valid); + all_test_results.emplace_back(kc_B_valid); + all_test_results.emplace_back(kc_C_valid); + all_test_results.emplace_back(QAP_valid); + all_test_results.emplace_back(CC_valid); + + all_tests_pass.reset(new conjunction_gadget(pb, all_test_results, result, FMT(annotation_prefix, " all_tests_pass"))); +} + +template +void r1cs_ppzksnark_online_verifier_gadget::generate_r1cs_constraints() +{ + PROFILE_CONSTRAINTS(this->pb, "accumulate verifier input") + { + print_indent(); printf("* Number of bits as an input to verifier gadget: %zu\n", input.size()); + accumulate_input->generate_r1cs_constraints(); + } + + PROFILE_CONSTRAINTS(this->pb, "rest of the verifier") + { + compute_proof_g_A_g_acc->generate_r1cs_constraints(); + compute_proof_g_A_g_acc_C->generate_r1cs_constraints(); + + compute_proof_g_A_g_acc_precomp->generate_r1cs_constraints(); + compute_proof_g_A_g_acc_C_precomp->generate_r1cs_constraints(); + + compute_proof_g_A_h_precomp->generate_r1cs_constraints(); + compute_proof_g_A_g_precomp->generate_r1cs_constraints(); + compute_proof_g_B_h_precomp->generate_r1cs_constraints(); + compute_proof_g_C_h_precomp->generate_r1cs_constraints(); + compute_proof_g_C_g_precomp->generate_r1cs_constraints(); + compute_proof_g_H_precomp->generate_r1cs_constraints(); + compute_proof_g_K_precomp->generate_r1cs_constraints(); + compute_proof_g_B_g_precomp->generate_r1cs_constraints(); + + check_kc_A_valid->generate_r1cs_constraints(); + check_kc_B_valid->generate_r1cs_constraints(); + check_kc_C_valid->generate_r1cs_constraints(); + check_QAP_valid->generate_r1cs_constraints(); + check_CC_valid->generate_r1cs_constraints(); + + all_tests_pass->generate_r1cs_constraints(); + } +} + +template +void r1cs_ppzksnark_online_verifier_gadget::generate_r1cs_witness() +{ + accumulate_input->generate_r1cs_witness(); + + compute_proof_g_A_g_acc->generate_r1cs_witness(); + compute_proof_g_A_g_acc_C->generate_r1cs_witness(); + + compute_proof_g_A_g_acc_precomp->generate_r1cs_witness(); + compute_proof_g_A_g_acc_C_precomp->generate_r1cs_witness(); + + compute_proof_g_A_h_precomp->generate_r1cs_witness(); + compute_proof_g_A_g_precomp->generate_r1cs_witness(); + compute_proof_g_B_h_precomp->generate_r1cs_witness(); + compute_proof_g_C_h_precomp->generate_r1cs_witness(); + compute_proof_g_C_g_precomp->generate_r1cs_witness(); + compute_proof_g_H_precomp->generate_r1cs_witness(); + compute_proof_g_K_precomp->generate_r1cs_witness(); + compute_proof_g_B_g_precomp->generate_r1cs_witness(); + + check_kc_A_valid->generate_r1cs_witness(); + check_kc_B_valid->generate_r1cs_witness(); + check_kc_C_valid->generate_r1cs_witness(); + check_QAP_valid->generate_r1cs_witness(); + check_CC_valid->generate_r1cs_witness(); + + all_tests_pass->generate_r1cs_witness(); +} + +template +r1cs_ppzksnark_verifier_gadget::r1cs_ppzksnark_verifier_gadget(protoboard &pb, + const r1cs_ppzksnark_verification_key_variable &vk, + const pb_variable_array &input, + const size_t elt_size, + const r1cs_ppzksnark_proof_variable &proof, + const pb_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + pvk.reset(new r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable()); + compute_pvk.reset(new r1cs_ppzksnark_verifier_process_vk_gadget(pb, vk, *pvk, FMT(annotation_prefix, " compute_pvk"))); + online_verifier.reset(new r1cs_ppzksnark_online_verifier_gadget(pb, *pvk, input, elt_size, proof, result, FMT(annotation_prefix, " online_verifier"))); +} + +template +void r1cs_ppzksnark_verifier_gadget::generate_r1cs_constraints() +{ + PROFILE_CONSTRAINTS(this->pb, "precompute pvk") + { + compute_pvk->generate_r1cs_constraints(); + } + + PROFILE_CONSTRAINTS(this->pb, "online verifier") + { + online_verifier->generate_r1cs_constraints(); + } +} + +template +void r1cs_ppzksnark_verifier_gadget::generate_r1cs_witness() +{ + compute_pvk->generate_r1cs_witness(); + online_verifier->generate_r1cs_witness(); +} + +} // libsnark + +#endif // R1CS_PPZKSNARK_VERIFIER_GADGET_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/gadgets/verifiers/tests/test_r1cs_ppzksnark_verifier_gadget.cpp b/privacy/zsl/zsl/gadgetlib1/gadgets/verifiers/tests/test_r1cs_ppzksnark_verifier_gadget.cpp new file mode 100644 index 0000000..299720c --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/gadgets/verifiers/tests/test_r1cs_ppzksnark_verifier_gadget.cpp @@ -0,0 +1,429 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +#include "algebra/fields/field_utils.hpp" +#include "gadgetlib1/gadgets/fields/fp2_gadgets.hpp" +#include "gadgetlib1/gadgets/fields/fp3_gadgets.hpp" +#include "gadgetlib1/gadgets/fields/fp4_gadgets.hpp" +#include "gadgetlib1/gadgets/fields/fp6_gadgets.hpp" +#include "gadgetlib1/gadgets/verifiers/r1cs_ppzksnark_verifier_gadget.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" + +using namespace libsnark; + +template +void dump_constraints(const protoboard &pb) +{ +#ifdef DEBUG + for (auto s : pb.constraint_system.constraint_annotations) + { + printf("constraint: %s\n", s.second.c_str()); + } +#endif +} + +template +void test_verifier(const std::string &annotation_A, const std::string &annotation_B) +{ + typedef Fr FieldT_A; + typedef Fr FieldT_B; + + const size_t num_constraints = 50; + const size_t primary_input_size = 3; + + r1cs_example example = generate_r1cs_example_with_field_input(num_constraints, primary_input_size); + assert(example.primary_input.size() == primary_input_size); + + assert(example.constraint_system.is_satisfied(example.primary_input, example.auxiliary_input)); + const r1cs_ppzksnark_keypair keypair = r1cs_ppzksnark_generator(example.constraint_system); + const r1cs_ppzksnark_proof pi = r1cs_ppzksnark_prover(keypair.pk, example.primary_input, example.auxiliary_input); + bool bit = r1cs_ppzksnark_verifier_strong_IC(keypair.vk, example.primary_input, pi); + assert(bit); + + const size_t elt_size = FieldT_A::size_in_bits(); + const size_t primary_input_size_in_bits = elt_size * primary_input_size; + const size_t vk_size_in_bits = r1cs_ppzksnark_verification_key_variable::size_in_bits(primary_input_size); + + protoboard pb; + pb_variable_array vk_bits; + vk_bits.allocate(pb, vk_size_in_bits, "vk_bits"); + + pb_variable_array primary_input_bits; + primary_input_bits.allocate(pb, primary_input_size_in_bits, "primary_input_bits"); + + r1cs_ppzksnark_proof_variable proof(pb, "proof"); + + r1cs_ppzksnark_verification_key_variable vk(pb, vk_bits, primary_input_size, "vk"); + + pb_variable result; + result.allocate(pb, "result"); + + r1cs_ppzksnark_verifier_gadget verifier(pb, vk, primary_input_bits, elt_size, proof, result, "verifier"); + + PROFILE_CONSTRAINTS(pb, "check that proofs lies on the curve") + { + proof.generate_r1cs_constraints(); + } + verifier.generate_r1cs_constraints(); + + bit_vector input_as_bits; + for (const FieldT_A &el : example.primary_input) + { + bit_vector v = convert_field_element_to_bit_vector(el, elt_size); + input_as_bits.insert(input_as_bits.end(), v.begin(), v.end()); + } + + primary_input_bits.fill_with_bits(pb, input_as_bits); + + vk.generate_r1cs_witness(keypair.vk); + proof.generate_r1cs_witness(pi); + verifier.generate_r1cs_witness(); + pb.val(result) = FieldT_B::one(); + + printf("positive test:\n"); + assert(pb.is_satisfied()); + + pb.val(primary_input_bits[0]) = FieldT_B::one() - pb.val(primary_input_bits[0]); + verifier.generate_r1cs_witness(); + pb.val(result) = FieldT_B::one(); + + printf("negative test:\n"); + assert(!pb.is_satisfied()); + PRINT_CONSTRAINT_PROFILING(); + printf("number of constraints for verifier: %zu (verifier is implemented in %s constraints and verifies %s proofs))\n", + pb.num_constraints(), annotation_B.c_str(), annotation_A.c_str()); +} + +template +void test_hardcoded_verifier(const std::string &annotation_A, const std::string &annotation_B) +{ + typedef Fr FieldT_A; + typedef Fr FieldT_B; + + const size_t num_constraints = 50; + const size_t primary_input_size = 3; + + r1cs_example example = generate_r1cs_example_with_field_input(num_constraints, primary_input_size); + assert(example.primary_input.size() == primary_input_size); + + assert(example.constraint_system.is_satisfied(example.primary_input, example.auxiliary_input)); + const r1cs_ppzksnark_keypair keypair = r1cs_ppzksnark_generator(example.constraint_system); + const r1cs_ppzksnark_proof pi = r1cs_ppzksnark_prover(keypair.pk, example.primary_input, example.auxiliary_input); + bool bit = r1cs_ppzksnark_verifier_strong_IC(keypair.vk, example.primary_input, pi); + assert(bit); + + const size_t elt_size = FieldT_A::size_in_bits(); + const size_t primary_input_size_in_bits = elt_size * primary_input_size; + + protoboard pb; + r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable hardcoded_vk(pb, keypair.vk, "hardcoded_vk"); + pb_variable_array primary_input_bits; + primary_input_bits.allocate(pb, primary_input_size_in_bits, "primary_input_bits"); + + r1cs_ppzksnark_proof_variable proof(pb, "proof"); + + pb_variable result; + result.allocate(pb, "result"); + + r1cs_ppzksnark_online_verifier_gadget online_verifier(pb, hardcoded_vk, primary_input_bits, elt_size, proof, result, "online_verifier"); + + PROFILE_CONSTRAINTS(pb, "check that proofs lies on the curve") + { + proof.generate_r1cs_constraints(); + } + online_verifier.generate_r1cs_constraints(); + + bit_vector input_as_bits; + for (const FieldT_A &el : example.primary_input) + { + bit_vector v = convert_field_element_to_bit_vector(el, elt_size); + input_as_bits.insert(input_as_bits.end(), v.begin(), v.end()); + } + + primary_input_bits.fill_with_bits(pb, input_as_bits); + + proof.generate_r1cs_witness(pi); + online_verifier.generate_r1cs_witness(); + pb.val(result) = FieldT_B::one(); + + printf("positive test:\n"); + assert(pb.is_satisfied()); + + pb.val(primary_input_bits[0]) = FieldT_B::one() - pb.val(primary_input_bits[0]); + online_verifier.generate_r1cs_witness(); + pb.val(result) = FieldT_B::one(); + + printf("negative test:\n"); + assert(!pb.is_satisfied()); + PRINT_CONSTRAINT_PROFILING(); + printf("number of constraints for verifier: %zu (verifier is implemented in %s constraints and verifies %s proofs))\n", + pb.num_constraints(), annotation_B.c_str(), annotation_A.c_str()); +} + +template class VarT, template class MulT> +void test_mul(const std::string &annotation) +{ + typedef typename FpExtT::my_Fp FieldT; + + protoboard pb; + VarT x(pb, "x"); + VarT y(pb, "y"); + VarT xy(pb, "xy"); + MulT mul(pb, x, y, xy, "mul"); + mul.generate_r1cs_constraints(); + + for (size_t i = 0; i < 10; ++i) + { + const FpExtT x_val = FpExtT::random_element(); + const FpExtT y_val = FpExtT::random_element(); + x.generate_r1cs_witness(x_val); + y.generate_r1cs_witness(y_val); + mul.generate_r1cs_witness(); + const FpExtT res = xy.get_element(); + assert(res == x_val*y_val); + assert(pb.is_satisfied()); + } + printf("number of constraints for %s_mul = %zu\n", annotation.c_str(), pb.num_constraints()); +} + +template class VarT, template class SqrT> +void test_sqr(const std::string &annotation) +{ + typedef typename FpExtT::my_Fp FieldT; + + protoboard pb; + VarT x(pb, "x"); + VarT xsq(pb, "xsq"); + SqrT sqr(pb, x, xsq, "sqr"); + sqr.generate_r1cs_constraints(); + + for (size_t i = 0; i < 10; ++i) + { + const FpExtT x_val = FpExtT::random_element(); + x.generate_r1cs_witness(x_val); + sqr.generate_r1cs_witness(); + const FpExtT res = xsq.get_element(); + assert(res == x_val.squared()); + assert(pb.is_satisfied()); + } + printf("number of constraints for %s_sqr = %zu\n", annotation.c_str(), pb.num_constraints()); +} + +template class VarT, template class CycloSqrT> +void test_cyclotomic_sqr(const std::string &annotation) +{ + typedef Fqk FpExtT; + typedef typename FpExtT::my_Fp FieldT; + + + protoboard pb; + VarT x(pb, "x"); + VarT xsq(pb, "xsq"); + CycloSqrT sqr(pb, x, xsq, "sqr"); + sqr.generate_r1cs_constraints(); + + for (size_t i = 0; i < 10; ++i) + { + FpExtT x_val = FpExtT::random_element(); + x_val = ppT::final_exponentiation(x_val); + + x.generate_r1cs_witness(x_val); + sqr.generate_r1cs_witness(); + const FpExtT res = xsq.get_element(); + assert(res == x_val.squared()); + assert(pb.is_satisfied()); + } + printf("number of constraints for %s_cyclotomic_sqr = %zu\n", annotation.c_str(), pb.num_constraints()); +} + +template class VarT> +void test_Frobenius(const std::string &annotation) +{ + typedef typename FpExtT::my_Fp FieldT; + + for (size_t i = 0; i < 100; ++i) + { + protoboard pb; + VarT x(pb, "x"); + VarT x_frob = x.Frobenius_map(i); + + const FpExtT x_val = FpExtT::random_element(); + x.generate_r1cs_witness(x_val); + x_frob.evaluate(); + const FpExtT res = x_frob.get_element(); + assert(res == x_val.Frobenius_map(i)); + assert(pb.is_satisfied()); + } + + printf("Frobenius map for %s correct\n", annotation.c_str()); +} + +template +void test_full_pairing(const std::string &annotation) +{ + typedef Fr FieldT; + + protoboard pb; + G1 > P_val = Fr >::random_element() * G1 >::one(); + G2 > Q_val = Fr >::random_element() * G2 >::one(); + + G1_variable P(pb, "P"); + G2_variable Q(pb, "Q"); + G1_precomputation prec_P; + G2_precomputation prec_Q; + + precompute_G1_gadget compute_prec_P(pb, P, prec_P, "compute_prec_P"); + precompute_G2_gadget compute_prec_Q(pb, Q, prec_Q, "compute_prec_Q"); + + Fqk_variable miller_result(pb, "miller_result"); + mnt_miller_loop_gadget miller(pb, prec_P, prec_Q, miller_result, "miller"); + pb_variable result_is_one; + result_is_one.allocate(pb, "result_is_one"); + final_exp_gadget finexp(pb, miller_result, result_is_one, "finexp"); + + PROFILE_CONSTRAINTS(pb, "precompute P") + { + compute_prec_P.generate_r1cs_constraints(); + } + PROFILE_CONSTRAINTS(pb, "precompute Q") + { + compute_prec_Q.generate_r1cs_constraints(); + } + PROFILE_CONSTRAINTS(pb, "Miller loop") + { + miller.generate_r1cs_constraints(); + } + PROFILE_CONSTRAINTS(pb, "final exp") + { + finexp.generate_r1cs_constraints(); + } + PRINT_CONSTRAINT_PROFILING(); + + P.generate_r1cs_witness(P_val); + compute_prec_P.generate_r1cs_witness(); + Q.generate_r1cs_witness(Q_val); + compute_prec_Q.generate_r1cs_witness(); + miller.generate_r1cs_witness(); + finexp.generate_r1cs_witness(); + assert(pb.is_satisfied()); + + affine_ate_G1_precomp > native_prec_P = other_curve::affine_ate_precompute_G1(P_val); + affine_ate_G2_precomp > native_prec_Q = other_curve::affine_ate_precompute_G2(Q_val); + Fqk > native_miller_result = other_curve::affine_ate_miller_loop(native_prec_P, native_prec_Q); + + Fqk > native_finexp_result = other_curve::final_exponentiation(native_miller_result); + printf("Must match:\n"); + finexp.result->get_element().print(); + native_finexp_result.print(); + + assert(finexp.result->get_element() == native_finexp_result); + + printf("number of constraints for full pairing (Fr is %s) = %zu\n", annotation.c_str(), pb.num_constraints()); +} + +template +void test_full_precomputed_pairing(const std::string &annotation) +{ + typedef Fr FieldT; + + protoboard pb; + G1 > P_val = Fr >::random_element() * G1 >::one(); + G2 > Q_val = Fr >::random_element() * G2 >::one(); + + G1_precomputation prec_P(pb, P_val, "prec_P"); + G2_precomputation prec_Q(pb, Q_val, "prec_Q"); + + Fqk_variable miller_result(pb, "miller_result"); + mnt_miller_loop_gadget miller(pb, prec_P, prec_Q, miller_result, "miller"); + pb_variable result_is_one; + result_is_one.allocate(pb, "result_is_one"); + final_exp_gadget finexp(pb, miller_result, result_is_one, "finexp"); + + PROFILE_CONSTRAINTS(pb, "Miller loop") + { + miller.generate_r1cs_constraints(); + } + PROFILE_CONSTRAINTS(pb, "final exp") + { + finexp.generate_r1cs_constraints(); + } + PRINT_CONSTRAINT_PROFILING(); + + miller.generate_r1cs_witness(); + finexp.generate_r1cs_witness(); + assert(pb.is_satisfied()); + + affine_ate_G1_precomp > native_prec_P = other_curve::affine_ate_precompute_G1(P_val); + affine_ate_G2_precomp > native_prec_Q = other_curve::affine_ate_precompute_G2(Q_val); + Fqk > native_miller_result = other_curve::affine_ate_miller_loop(native_prec_P, native_prec_Q); + + Fqk > native_finexp_result = other_curve::final_exponentiation(native_miller_result); + printf("Must match:\n"); + finexp.result->get_element().print(); + native_finexp_result.print(); + + assert(finexp.result->get_element() == native_finexp_result); + + printf("number of constraints for full precomputed pairing (Fr is %s) = %zu\n", annotation.c_str(), pb.num_constraints()); +} + +int main(void) +{ + start_profiling(); + mnt4_pp::init_public_params(); + mnt6_pp::init_public_params(); + + test_mul("mnt4_Fp2"); + test_sqr("mnt4_Fp2"); + + test_mul("mnt4_Fp4"); + test_sqr("mnt4_Fp4"); + test_cyclotomic_sqr("mnt4_Fp4"); + test_exponentiation_gadget(mnt4_final_exponent_last_chunk_abs_of_w0, "mnt4_Fq4"); + test_Frobenius("mnt4_Fq4"); + + test_mul("mnt6_Fp3"); + test_sqr("mnt6_Fp3"); + + test_mul("mnt6_Fp6"); + test_sqr("mnt6_Fp6"); + test_cyclotomic_sqr("mnt6_Fp6"); + test_exponentiation_gadget(mnt6_final_exponent_last_chunk_abs_of_w0, "mnt6_Fq6"); + test_Frobenius("mnt6_Fq6"); + + test_G2_checker_gadget("mnt4"); + test_G2_checker_gadget("mnt6"); + + test_G1_variable_precomp("mnt4"); + test_G1_variable_precomp("mnt6"); + + test_G2_variable_precomp("mnt4"); + test_G2_variable_precomp("mnt6"); + + test_mnt_miller_loop("mnt4"); + test_mnt_miller_loop("mnt6"); + + test_mnt_e_over_e_miller_loop("mnt4"); + test_mnt_e_over_e_miller_loop("mnt6"); + + test_mnt_e_times_e_over_e_miller_loop("mnt4"); + test_mnt_e_times_e_over_e_miller_loop("mnt6"); + + test_full_pairing("mnt4"); + test_full_pairing("mnt6"); + + test_full_precomputed_pairing("mnt4"); + test_full_precomputed_pairing("mnt6"); + + test_verifier("mnt4", "mnt6"); + test_verifier("mnt6", "mnt4"); + + test_hardcoded_verifier("mnt4", "mnt6"); + test_hardcoded_verifier("mnt6", "mnt4"); +} diff --git a/privacy/zsl/zsl/gadgetlib1/pb_variable.hpp b/privacy/zsl/zsl/gadgetlib1/pb_variable.hpp new file mode 100644 index 0000000..fdf64d0 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/pb_variable.hpp @@ -0,0 +1,144 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PB_VARIABLE_HPP_ +#define PB_VARIABLE_HPP_ + +#include +#include +#include +#include "common/utils.hpp" +#include "relations/variable.hpp" + +namespace libsnark { + +typedef size_t lc_index_t; + +template +class protoboard; + +template +class pb_variable : public variable { +public: + pb_variable(const var_index_t index = 0) : variable(index) {}; + + void allocate(protoboard &pb, const std::string &annotation=""); +}; + +template +class pb_variable_array : private std::vector > +{ + typedef std::vector > contents; +public: + using typename contents::iterator; + using typename contents::const_iterator; + using typename contents::reverse_iterator; + using typename contents::const_reverse_iterator; + + using contents::begin; + using contents::end; + using contents::rbegin; + using contents::rend; + using contents::emplace_back; + using contents::insert; + using contents::reserve; + using contents::size; + using contents::empty; + using contents::operator[]; + using contents::resize; + + pb_variable_array() : contents() {}; + pb_variable_array(size_t count, const pb_variable &value) : contents(count, value) {}; + pb_variable_array(typename contents::const_iterator first, typename contents::const_iterator last) : contents(first, last) {}; + pb_variable_array(typename contents::const_reverse_iterator first, typename contents::const_reverse_iterator last) : contents(first, last) {}; + void allocate(protoboard &pb, const size_t n, const std::string &annotation_prefix=""); + + void fill_with_field_elements(protoboard &pb, const std::vector& vals) const; + void fill_with_bits(protoboard &pb, const bit_vector& bits) const; + void fill_with_bits_of_ulong(protoboard &pb, const unsigned long i) const; + void fill_with_bits_of_field_element(protoboard &pb, const FieldT &r) const; + + std::vector get_vals(const protoboard &pb) const; + bit_vector get_bits(const protoboard &pb) const; + + FieldT get_field_element_from_bits(const protoboard &pb) const; +}; + +/* index 0 corresponds to the constant term (used in legacy code) */ +#define ONE pb_variable(0) + +template +class pb_linear_combination : public linear_combination { +public: + bool is_variable; + lc_index_t index; + + pb_linear_combination(); + pb_linear_combination(const pb_variable &var); + + void assign(protoboard &pb, const linear_combination &lc); + void evaluate(protoboard &pb) const; + + bool is_constant() const; + FieldT constant_term() const; +}; + +template +class pb_linear_combination_array : private std::vector > +{ + typedef std::vector > contents; +public: + using typename contents::iterator; + using typename contents::const_iterator; + using typename contents::reverse_iterator; + using typename contents::const_reverse_iterator; + + using contents::begin; + using contents::end; + using contents::rbegin; + using contents::rend; + using contents::emplace_back; + using contents::insert; + using contents::reserve; + using contents::size; + using contents::empty; + using contents::operator[]; + using contents::resize; + + pb_linear_combination_array() : contents() {}; + pb_linear_combination_array(const pb_variable_array &arr) { for (auto &v : arr) this->emplace_back(pb_linear_combination(v)); }; + pb_linear_combination_array(size_t count) : contents(count) {}; + pb_linear_combination_array(size_t count, const pb_linear_combination &value) : contents(count, value) {}; + pb_linear_combination_array(typename contents::const_iterator first, typename contents::const_iterator last) : contents(first, last) {}; + pb_linear_combination_array(typename contents::const_reverse_iterator first, typename contents::const_reverse_iterator last) : contents(first, last) {}; + + void evaluate(protoboard &pb) const; + + void fill_with_field_elements(protoboard &pb, const std::vector& vals) const; + void fill_with_bits(protoboard &pb, const bit_vector& bits) const; + void fill_with_bits_of_ulong(protoboard &pb, const unsigned long i) const; + void fill_with_bits_of_field_element(protoboard &pb, const FieldT &r) const; + + std::vector get_vals(const protoboard &pb) const; + bit_vector get_bits(const protoboard &pb) const; + + FieldT get_field_element_from_bits(const protoboard &pb) const; +}; + +template +linear_combination pb_sum(const pb_linear_combination_array &v); + +template +linear_combination pb_packing_sum(const pb_linear_combination_array &v); + +template +linear_combination pb_coeff_sum(const pb_linear_combination_array &v, const std::vector &coeffs); + +} // libsnark +#include "gadgetlib1/pb_variable.tcc" + +#endif // PB_VARIABLE_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/pb_variable.tcc b/privacy/zsl/zsl/gadgetlib1/pb_variable.tcc new file mode 100644 index 0000000..7e90f25 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/pb_variable.tcc @@ -0,0 +1,329 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PB_VARIABLE_TCC_ +#define PB_VARIABLE_TCC_ +#include +#include "gadgetlib1/protoboard.hpp" +#include "common/utils.hpp" + +namespace libsnark { + +template +void pb_variable::allocate(protoboard &pb, const std::string &annotation) +{ + this->index = pb.allocate_var_index(annotation); +} + +/* allocates pb_variable array in MSB->LSB order */ +template +void pb_variable_array::allocate(protoboard &pb, const size_t n, const std::string &annotation_prefix) +{ +#ifdef DEBUG + assert(annotation_prefix != ""); +#endif + (*this).resize(n); + + for (size_t i = 0; i < n; ++i) + { + (*this)[i].allocate(pb, FMT(annotation_prefix, "_%zu", i)); + } +} + +template +void pb_variable_array::fill_with_field_elements(protoboard &pb, const std::vector& vals) const +{ + assert(this->size() == vals.size()); + for (size_t i = 0; i < vals.size(); ++i) + { + pb.val((*this)[i]) = vals[i]; + } +} + +template +void pb_variable_array::fill_with_bits(protoboard &pb, const bit_vector& bits) const +{ + assert(this->size() == bits.size()); + for (size_t i = 0; i < bits.size(); ++i) + { + pb.val((*this)[i]) = (bits[i] ? FieldT::one() : FieldT::zero()); + } +} + +template +void pb_variable_array::fill_with_bits_of_field_element(protoboard &pb, const FieldT &r) const +{ + const bigint rint = r.as_bigint(); + for (size_t i = 0; i < this->size(); ++i) + { + pb.val((*this)[i]) = rint.test_bit(i) ? FieldT::one() : FieldT::zero(); + } +} + +template +void pb_variable_array::fill_with_bits_of_ulong(protoboard &pb, const unsigned long i) const +{ + this->fill_with_bits_of_field_element(pb, FieldT(i, true)); +} + +template +std::vector pb_variable_array::get_vals(const protoboard &pb) const +{ + std::vector result(this->size()); + for (size_t i = 0; i < this->size(); ++i) + { + result[i] = pb.val((*this)[i]); + } + return result; +} + +template +bit_vector pb_variable_array::get_bits(const protoboard &pb) const +{ + bit_vector result; + for (size_t i = 0; i < this->size(); ++i) + { + const FieldT v = pb.val((*this)[i]); + assert(v == FieldT::zero() || v == FieldT::one()); + result.push_back(v == FieldT::one()); + } + return result; +} + +template +FieldT pb_variable_array::get_field_element_from_bits(const protoboard &pb) const +{ + FieldT result = FieldT::zero(); + + for (size_t i = 0; i < this->size(); ++i) + { + /* push in the new bit */ + const FieldT v = pb.val((*this)[this->size()-1-i]); + assert(v == FieldT::zero() || v == FieldT::one()); + result += result + v; + } + + return result; +} + +template +pb_linear_combination::pb_linear_combination() +{ + this->is_variable = false; +} + +template +pb_linear_combination::pb_linear_combination(const pb_variable &var) +{ + this->is_variable = true; + this->index = var.index; + this->terms.emplace_back(linear_term(var)); +} + +template +void pb_linear_combination::assign(protoboard &pb, const linear_combination &lc) +{ + assert(this->is_variable == false); + this->index = pb.allocate_lc_index(); + this->terms = lc.terms; +} + +template +void pb_linear_combination::evaluate(protoboard &pb) const +{ + if (this->is_variable) + { + return; // do nothing + } + + FieldT sum = 0; + for (auto term : this->terms) + { + sum += term.coeff * pb.val(pb_variable(term.index)); + } + + pb.lc_val(*this) = sum; +} + +template +bool pb_linear_combination::is_constant() const +{ + if (is_variable) + { + return (index == 0); + } + else + { + for (auto term : this->terms) + { + if (term.index != 0) + { + return false; + } + } + + return true; + } +} + +template +FieldT pb_linear_combination::constant_term() const +{ + if (is_variable) + { + return (index == 0 ? FieldT::one() : FieldT::zero()); + } + else + { + FieldT result = FieldT::zero(); + for (auto term : this->terms) + { + if (term.index == 0) + { + result += term.coeff; + } + } + return result; + } +} + +template +void pb_linear_combination_array::evaluate(protoboard &pb) const +{ + for (size_t i = 0; i < this->size(); ++i) + { + (*this)[i].evaluate(pb); + } +} + +template +void pb_linear_combination_array::fill_with_field_elements(protoboard &pb, const std::vector& vals) const +{ + assert(this->size() == vals.size()); + for (size_t i = 0; i < vals.size(); ++i) + { + pb.lc_val((*this)[i]) = vals[i]; + } +} + +template +void pb_linear_combination_array::fill_with_bits(protoboard &pb, const bit_vector& bits) const +{ + assert(this->size() == bits.size()); + for (size_t i = 0; i < bits.size(); ++i) + { + pb.lc_val((*this)[i]) = (bits[i] ? FieldT::one() : FieldT::zero()); + } +} + +template +void pb_linear_combination_array::fill_with_bits_of_field_element(protoboard &pb, const FieldT &r) const +{ + const bigint rint = r.as_bigint(); + for (size_t i = 0; i < this->size(); ++i) + { + pb.lc_val((*this)[i]) = rint.test_bit(i) ? FieldT::one() : FieldT::zero(); + } +} + +template +void pb_linear_combination_array::fill_with_bits_of_ulong(protoboard &pb, const unsigned long i) const +{ + this->fill_with_bits_of_field_element(pb, FieldT(i)); +} + +template +std::vector pb_linear_combination_array::get_vals(const protoboard &pb) const +{ + std::vector result(this->size()); + for (size_t i = 0; i < this->size(); ++i) + { + result[i] = pb.lc_val((*this)[i]); + } + return result; +} + +template +bit_vector pb_linear_combination_array::get_bits(const protoboard &pb) const +{ + bit_vector result; + for (size_t i = 0; i < this->size(); ++i) + { + const FieldT v = pb.lc_val((*this)[i]); + assert(v == FieldT::zero() || v == FieldT::one()); + result.push_back(v == FieldT::one()); + } + return result; +} + +template +FieldT pb_linear_combination_array::get_field_element_from_bits(const protoboard &pb) const +{ + FieldT result = FieldT::zero(); + + for (size_t i = 0; i < this->size(); ++i) + { + /* push in the new bit */ + const FieldT v = pb.lc_val((*this)[this->size()-1-i]); + assert(v == FieldT::zero() || v == FieldT::one()); + result += result + v; + } + + return result; +} + +template +linear_combination pb_sum(const pb_linear_combination_array &v) +{ + linear_combination result; + for (auto &term : v) + { + result = result + term; + } + + return result; +} + +template +linear_combination pb_packing_sum(const pb_linear_combination_array &v) +{ + FieldT twoi = FieldT::one(); // will hold 2^i entering each iteration + std::vector > all_terms; + for (auto &lc : v) + { + for (auto &term : lc.terms) + { + all_terms.emplace_back(twoi * term); + } + twoi += twoi; + } + + return linear_combination(all_terms); +} + +template +linear_combination pb_coeff_sum(const pb_linear_combination_array &v, const std::vector &coeffs) +{ + assert(v.size() == coeffs.size()); + std::vector > all_terms; + + auto coeff_it = coeffs.begin(); + for (auto &lc : v) + { + for (auto &term : lc.terms) + { + all_terms.emplace_back((*coeff_it) * term); + } + ++coeff_it; + } + + return linear_combination(all_terms); +} + + +} // libsnark +#endif // PB_VARIABLE_TCC diff --git a/privacy/zsl/zsl/gadgetlib1/protoboard.hpp b/privacy/zsl/zsl/gadgetlib1/protoboard.hpp new file mode 100644 index 0000000..8ef4a53 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/protoboard.hpp @@ -0,0 +1,75 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PROTOBOARD_HPP_ +#define PROTOBOARD_HPP_ + +#include +#include +#include +#include +#include +#include "gadgetlib1/pb_variable.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" +#include "common/utils.hpp" + +namespace libsnark { + +template +class r1cs_constraint; + +template +class r1cs_constraint_system; + +template +class protoboard { +private: + FieldT constant_term; /* only here, because pb.val() needs to be able to return reference to the constant 1 term */ + r1cs_variable_assignment values; /* values[0] will hold the value of the first allocated variable of the protoboard, *NOT* constant 1 */ + var_index_t next_free_var; + lc_index_t next_free_lc; + std::vector lc_values; + +public: + r1cs_constraint_system constraint_system; + protoboard(); + + void clear_values(); + + FieldT& val(const pb_variable &var); + FieldT val(const pb_variable &var) const; + + FieldT& lc_val(const pb_linear_combination &lc); + FieldT lc_val(const pb_linear_combination &lc) const; + + void add_r1cs_constraint(const r1cs_constraint &constr, const std::string &annotation=""); + void augment_variable_annotation(const pb_variable &v, const std::string &postfix); + bool is_satisfied() const; + void dump_variables() const; + + size_t num_constraints() const; + size_t num_inputs() const; + size_t num_variables() const; + + void set_input_sizes(const size_t primary_input_size); + + r1cs_variable_assignment full_variable_assignment() const; + r1cs_primary_input primary_input() const; + r1cs_auxiliary_input auxiliary_input() const; + r1cs_constraint_system get_constraint_system() const; + + friend class pb_variable; + friend class pb_linear_combination; + +private: + var_index_t allocate_var_index(const std::string &annotation=""); + lc_index_t allocate_lc_index(); +}; + +} // libsnark +#include "gadgetlib1/protoboard.tcc" +#endif // PROTOBOARD_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib1/protoboard.tcc b/privacy/zsl/zsl/gadgetlib1/protoboard.tcc new file mode 100644 index 0000000..882af28 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/protoboard.tcc @@ -0,0 +1,189 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PROTOBOARD_TCC_ +#define PROTOBOARD_TCC_ + +#include +#include +#include "common/profiling.hpp" + +namespace libsnark { + +template +protoboard::protoboard() +{ + constant_term = FieldT::one(); + +#ifdef DEBUG + constraint_system.variable_annotations[0] = "ONE"; +#endif + + next_free_var = 1; /* to account for constant 1 term */ + next_free_lc = 0; +} + +template +void protoboard::clear_values() +{ + std::fill(values.begin(), values.end(), FieldT::zero()); +} + +template +var_index_t protoboard::allocate_var_index(const std::string &annotation) +{ +#ifdef DEBUG + assert(annotation != ""); + constraint_system.variable_annotations[next_free_var] = annotation; +#else + UNUSED(annotation); +#endif + ++constraint_system.auxiliary_input_size; + values.emplace_back(FieldT::zero()); + return next_free_var++; +} + +template +lc_index_t protoboard::allocate_lc_index() +{ + lc_values.emplace_back(FieldT::zero()); + return next_free_lc++; +} + +template +FieldT& protoboard::val(const pb_variable &var) +{ + assert(var.index <= values.size()); + return (var.index == 0 ? constant_term : values[var.index-1]); +} + +template +FieldT protoboard::val(const pb_variable &var) const +{ + assert(var.index <= values.size()); + return (var.index == 0 ? constant_term : values[var.index-1]); +} + +template +FieldT& protoboard::lc_val(const pb_linear_combination &lc) +{ + if (lc.is_variable) + { + return this->val(pb_variable(lc.index)); + } + else + { + assert(lc.index < lc_values.size()); + return lc_values[lc.index]; + } +} + +template +FieldT protoboard::lc_val(const pb_linear_combination &lc) const +{ + if (lc.is_variable) + { + return this->val(pb_variable(lc.index)); + } + else + { + assert(lc.index < lc_values.size()); + return lc_values[lc.index]; + } +} + +template +void protoboard::add_r1cs_constraint(const r1cs_constraint &constr, const std::string &annotation) +{ +#ifdef DEBUG + assert(annotation != ""); + constraint_system.constraint_annotations[constraint_system.constraints.size()] = annotation; +#else + UNUSED(annotation); +#endif + constraint_system.constraints.emplace_back(constr); +} + +template +void protoboard::augment_variable_annotation(const pb_variable &v, const std::string &postfix) +{ +#ifdef DEBUG + auto it = constraint_system.variable_annotations.find(v.index); + constraint_system.variable_annotations[v.index] = (it == constraint_system.variable_annotations.end() ? "" : it->second + " ") + postfix; +#endif +} + +template +bool protoboard::is_satisfied() const +{ + return constraint_system.is_satisfied(primary_input(), auxiliary_input()); +} + +template +void protoboard::dump_variables() const +{ +#ifdef DEBUG + for (size_t i = 0; i < constraint_system.num_variables; ++i) + { + printf("%-40s --> ", constraint_system.variable_annotations[i].c_str()); + values[i].as_bigint().print_hex(); + } +#endif +} + +template +size_t protoboard::num_constraints() const +{ + return constraint_system.num_constraints(); +} + +template +size_t protoboard::num_inputs() const +{ + return constraint_system.num_inputs(); +} + +template +size_t protoboard::num_variables() const +{ + return next_free_var - 1; +} + +template +void protoboard::set_input_sizes(const size_t primary_input_size) +{ + assert(primary_input_size <= num_variables()); + constraint_system.primary_input_size = primary_input_size; + constraint_system.auxiliary_input_size = num_variables() - primary_input_size; +} + +template +r1cs_variable_assignment protoboard::full_variable_assignment() const +{ + return values; +} + +template +r1cs_primary_input protoboard::primary_input() const +{ + return r1cs_primary_input(values.begin(), values.begin() + num_inputs()); +} + +template +r1cs_auxiliary_input protoboard::auxiliary_input() const +{ + return r1cs_primary_input(values.begin() + num_inputs(), values.end()); +} + +template +r1cs_constraint_system protoboard::get_constraint_system() const +{ + return constraint_system; +} + +} // libsnark +#endif // PROTOBOARD_TCC_ diff --git a/privacy/zsl/zsl/gadgetlib1/tests/gadgetlib1_test.cpp b/privacy/zsl/zsl/gadgetlib1/tests/gadgetlib1_test.cpp new file mode 100644 index 0000000..4fc5106 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib1/tests/gadgetlib1_test.cpp @@ -0,0 +1,32 @@ +/** @file + ***************************************************************************** + Unit tests for gadgetlib1 - main() for running all tests + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include "gadgetlib1/examples/simple_example.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp" + +namespace { + +TEST(gadgetLib1,Integration) { + typedef libsnark::Fr FieldT; + // Create an example constraint system and translate to libsnark format + libsnark::default_ec_pp::init_public_params(); + const auto example = libsnark::gen_r1cs_example_from_protoboard(100); + const bool test_serialization = false; + // Run ppzksnark. Jump into function for breakdown + const bool bit = libsnark::run_r1cs_ppzksnark(example, test_serialization); + EXPECT_TRUE(bit); +}; + +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/privacy/zsl/zsl/gadgetlib2/adapters.cpp b/privacy/zsl/zsl/gadgetlib2/adapters.cpp new file mode 100644 index 0000000..03d4d5d --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/adapters.cpp @@ -0,0 +1,94 @@ +/** @file + ***************************************************************************** + Implementation of an adapter for interfacing to SNARKs. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "adapters.hpp" + +using gadgetlib2::Variable; +using gadgetlib2::Rank1Constraint; + +namespace gadgetlib2 { + +typedef GadgetLibAdapter GLA; + +GLA::linear_term_t GLA::convert(const LinearTerm& lt) const { + const variable_index_t var = lt.variable_.index_; + const Fp_elem_t coeff = convert(lt.coeff_); + return{ var, coeff }; +} + +GLA::linear_combination_t GLA::convert(const LinearCombination& lc) const { + sparse_vec_t sparse_vec; + sparse_vec.reserve(lc.linearTerms_.size()); + for (auto lt : lc.linearTerms_) { + sparse_vec.emplace_back(convert(lt)); + } + const Fp_elem_t offset = convert(lc.constant_); + return{ sparse_vec, offset }; +} + +GLA::constraint_t GLA::convert(const Constraint& constraint) const { + const auto rank1_constraint = dynamic_cast(constraint); + return constraint_t(convert(rank1_constraint.a()), + convert(rank1_constraint.b()), + convert(rank1_constraint.c())); +} + +GLA::constraint_sys_t GLA::convert(const ConstraintSystem& constraint_sys) const { + constraint_sys_t retval; + retval.reserve(constraint_sys.constraintsPtrs_.size()); + for (auto constraintPtr : constraint_sys.constraintsPtrs_) { + retval.emplace_back(convert(*constraintPtr)); + } + return retval; +} + +GLA::assignment_t GLA::convert(const VariableAssignment& assignment) const { + assignment_t retval; + for (const auto assignmentPair : assignment) { + const variable_index_t var = assignmentPair.first.index_; + const Fp_elem_t elem = convert(assignmentPair.second); + retval[var] = elem; + } + return retval; +} + +void GLA::resetVariableIndex() { // This is a hack, used for testing + Variable::nextFreeIndex_ = 0; +} + +/***TODO: Remove reliance of GadgetLibAdapter conversion on global variable indices, and the resulting limit of single protoboard instance at a time. +This limitation is to prevent a logic bug that may occur if the variables used are given different indices in different generations of the same constraint system. +The indices are assigned on the Variable constructor, using the global variable nextFreeIndex. Thus, creating two protoboards in the same program may cause +unexpected behavior when converting. +Moreover, the bug will create more variables than needed in the converted system, e.g. if variables 0,1,3,4 were used in the gadgetlib2 +generated system, than the conversion will create a new r1cs system with variables 0,1,2,3,4 and assign variable 2 the value zero +(when converting the assignment). +Everything should be fixed soon. +If you are sure you know what you are doing, you can comment out the ASSERT line. +*/ +GLA::protoboard_t GLA::convert(const Protoboard& pb) const { + //GADGETLIB_ASSERT(pb.numVars()==getNextFreeIndex(), "Some Variables were created and not used, or, more than one protoboard was used."); + return protoboard_t(convert(pb.constraintSystem()), convert(pb.assignment())); +} + +GLA::Fp_elem_t GLA::convert(FElem fElem) const { + using gadgetlib2::R1P_Elem; + fElem.promoteToFieldType(gadgetlib2::R1P); // convert fElem from FConst to R1P_Elem + const R1P_Elem* pR1P = dynamic_cast(fElem.elem_.get()); + return pR1P->elem_; +} + +bool operator==(const GLA::linear_combination_t& lhs, + const GLA::linear_term_t& rhs) { + return lhs.first.size() == 1 && + lhs.first.at(0) == rhs && + lhs.second == Fp(0); +} + +} diff --git a/privacy/zsl/zsl/gadgetlib2/adapters.d b/privacy/zsl/zsl/gadgetlib2/adapters.d new file mode 100644 index 0000000..f326cbb --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/adapters.d @@ -0,0 +1,19 @@ +src/gadgetlib2/adapters.o: src/gadgetlib2/adapters.cpp \ + src/gadgetlib2/adapters.hpp src/gadgetlib2/pp.hpp \ + src/common/default_types/ec_pp.hpp src/algebra/curves/bn128/bn128_pp.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/bn128/bn128_init.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc depinst/include/bn.h \ + depinst/include/zm2.h depinst/include/zm.h \ + src/algebra/curves/bn128/bn128_g1.hpp src/algebra/curves/curve_utils.hpp \ + src/algebra/curves/curve_utils.tcc src/algebra/curves/bn128/bn128_g2.hpp \ + src/algebra/curves/bn128/bn128_gt.hpp \ + src/algebra/curves/bn128/bn128_pairing.hpp src/gadgetlib2/variable.hpp \ + src/gadgetlib2/infrastructure.hpp src/gadgetlib2/variable_operators.hpp \ + src/gadgetlib2/constraint.hpp src/gadgetlib2/protoboard.hpp diff --git a/privacy/zsl/zsl/gadgetlib2/adapters.hpp b/privacy/zsl/zsl/gadgetlib2/adapters.hpp new file mode 100644 index 0000000..ba4678d --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/adapters.hpp @@ -0,0 +1,71 @@ +/** @file + ***************************************************************************** + Declaration of an adapter to POD types for interfacing to SNARKs + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_ADAPTERS_HPP_ +#define LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_ADAPTERS_HPP_ + +#include +#include +#include +#include "pp.hpp" +#include "variable.hpp" +#include "constraint.hpp" +#include "protoboard.hpp" + +using gadgetlib2::LinearTerm; +using gadgetlib2::LinearCombination; +using gadgetlib2::Constraint; +using gadgetlib2::ConstraintSystem; +using gadgetlib2::VariableAssignment; +using gadgetlib2::Protoboard; +using gadgetlib2::FElem; + + +namespace gadgetlib2 { + +/** + * This class is a temporary hack for quick integration of Fp constraints with ppsnark. It is the + * IDDQD of classes and has "god mode" friend access to many of the gadgetlib classes. This will + * be refactored out in the future. --Shaul + */ +class GadgetLibAdapter { +public: + typedef unsigned long variable_index_t; + typedef gadgetlib2::Fp Fp_elem_t; + typedef ::std::pair linear_term_t; + typedef ::std::vector sparse_vec_t; + typedef ::std::pair linear_combination_t; + typedef ::std::tuple constraint_t; + typedef ::std::vector constraint_sys_t; + typedef ::std::map assignment_t; + typedef ::std::pair protoboard_t; + + GadgetLibAdapter() {}; + + linear_term_t convert(const LinearTerm& lt) const; + linear_combination_t convert(const LinearCombination& lc) const; + constraint_t convert(const Constraint& constraint) const; + constraint_sys_t convert(const ConstraintSystem& constraint_sys) const; + assignment_t convert(const VariableAssignment& assignment) const; + static void resetVariableIndex(); ///< Resets variable index to 0 to make variable indices deterministic. + //TODO: Kill GadgetLibAdapter::resetVariableIndex() + static size_t getNextFreeIndex(){return Variable::nextFreeIndex_;} + protoboard_t convert(const Protoboard& pb) const; + Fp_elem_t convert(FElem fElem) const; + static size_t getVariableIndex(const Variable& v){return v.index_;} +}; + +bool operator==(const GadgetLibAdapter::linear_combination_t& lhs, + const GadgetLibAdapter::linear_term_t& rhs); + +} + +#endif // LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_ADAPTERS_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib2/constraint.cpp b/privacy/zsl/zsl/gadgetlib2/constraint.cpp new file mode 100644 index 0000000..2033e25 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/constraint.cpp @@ -0,0 +1,216 @@ +/** @file + ***************************************************************************** + Implementation of the Constraint class. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include "constraint.hpp" +#include "variable.hpp" + +using ::std::string; +using ::std::vector; +using ::std::set; +using ::std::cout; +using ::std::cerr; +using ::std::endl; +using ::std::shared_ptr; + +namespace gadgetlib2 { + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Constraint ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +#ifdef DEBUG +Constraint::Constraint(const string& name) : name_(name) {} +#else +Constraint::Constraint(const string& name) { UNUSED(name); } +#endif + +string Constraint::name() const { +# ifdef DEBUG + return name_; +# else + return ""; +# endif +} + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Rank1Constraint ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +Rank1Constraint::Rank1Constraint(const LinearCombination &a, + const LinearCombination &b, + const LinearCombination &c, + const string& name) + : Constraint(name), a_(a), b_(b), c_(c) {} + +LinearCombination Rank1Constraint::a() const {return a_;} +LinearCombination Rank1Constraint::b() const {return b_;} +LinearCombination Rank1Constraint::c() const {return c_;} + +bool Rank1Constraint::isSatisfied(const VariableAssignment& assignment, + const PrintOptions& printOnFail) const { + const FElem ares = a_.eval(assignment); + const FElem bres = b_.eval(assignment); + const FElem cres = c_.eval(assignment); + if (ares*bres != cres) { +# ifdef DEBUG + if (printOnFail == PrintOptions::DBG_PRINT_IF_NOT_SATISFIED) { + cerr << GADGETLIB2_FMT("Constraint named \"%s\" not satisfied. Constraint is:", + name().c_str()) << endl; + cerr << annotation() << endl; + cerr << "Variable assignments are:" << endl; + const Variable::set varSet = getUsedVariables(); + for(const Variable& var : varSet) { + cerr << var.name() << ": " << assignment.at(var).asString() << endl; + } + cerr << "a: " << ares.asString() << endl; + cerr << "b: " << bres.asString() << endl; + cerr << "a*b: " << (ares*bres).asString() << endl; + cerr << "c: " << cres.asString() << endl; + } +# else + UNUSED(printOnFail); +# endif + return false; + } + return true; +} + +string Rank1Constraint::annotation() const { +# ifndef DEBUG + return ""; +# endif + return string("( ") + a_.asString() + " ) * ( " + b_.asString() + " ) = "+ c_.asString(); +} + +const Variable::set Rank1Constraint::getUsedVariables() const { + Variable::set retSet; + const Variable::set aSet = a_.getUsedVariables(); + retSet.insert(aSet.begin(), aSet.end()); + const Variable::set bSet = b_.getUsedVariables(); + retSet.insert(bSet.begin(), bSet.end()); + const Variable::set cSet = c_.getUsedVariables(); + retSet.insert(cSet.begin(), cSet.end()); + return retSet; +} + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class PolynomialConstraint ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +PolynomialConstraint::PolynomialConstraint(const Polynomial& a, const Polynomial& b, + const string& name) : Constraint(name), a_(a), b_(b) {} + +bool PolynomialConstraint::isSatisfied(const VariableAssignment& assignment, + const PrintOptions& printOnFail) const { + const FElem aEval = a_.eval(assignment); + const FElem bEval = b_.eval(assignment); + if (aEval != bEval) { +# ifdef DEBUG + if(printOnFail == PrintOptions::DBG_PRINT_IF_NOT_SATISFIED) { + cerr << GADGETLIB2_FMT("Constraint named \"%s\" not satisfied. Constraint is:", + name().c_str()) << endl; + cerr << annotation() << endl; + cerr << "Expecting: " << aEval << " == " << bEval << endl; + cerr << "Variable assignments are:" << endl; + const Variable::set varSet = getUsedVariables(); + for(const Variable& var : varSet) { + cerr << var.name() << ": " << assignment.at(var).asString() << endl; + } + } +# else + UNUSED(printOnFail); +# endif + + return false; + } + return true; +} + +string PolynomialConstraint::annotation() const { +# ifndef DEBUG + return ""; +# endif + return a_.asString() + " == " + b_.asString(); +} + +const Variable::set PolynomialConstraint::getUsedVariables() const { + Variable::set retSet; + const Variable::set aSet = a_.getUsedVariables(); + retSet.insert(aSet.begin(), aSet.end()); + const Variable::set bSet = b_.getUsedVariables(); + retSet.insert(bSet.begin(), bSet.end()); + return retSet; +} + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + + +void ConstraintSystem::addConstraint(const Rank1Constraint& c) { + constraintsPtrs_.emplace_back(::std::shared_ptr(new Rank1Constraint(c))); +} + +void ConstraintSystem::addConstraint(const PolynomialConstraint& c) { + constraintsPtrs_.emplace_back(::std::shared_ptr(new PolynomialConstraint(c))); +} + +bool ConstraintSystem::isSatisfied(const VariableAssignment& assignment, + const PrintOptions& printOnFail) const { + for(size_t i = 0; i < constraintsPtrs_.size(); ++i) { + if (!constraintsPtrs_[i]->isSatisfied(assignment, printOnFail)){ + return false; + } + } + return true; +} + +string ConstraintSystem::annotation() const { + string retVal("\n"); + for(auto i = constraintsPtrs_.begin(); i != constraintsPtrs_.end(); ++i) { + retVal += (*i)->annotation() + '\n'; + } + return retVal; +} + +Variable::set ConstraintSystem::getUsedVariables() const { + Variable::set retSet; + for(auto& pConstraint : constraintsPtrs_) { + const Variable::set curSet = pConstraint->getUsedVariables(); + retSet.insert(curSet.begin(), curSet.end()); + } + return retSet; +} + +} // namespace gadgetlib2 diff --git a/privacy/zsl/zsl/gadgetlib2/constraint.d b/privacy/zsl/zsl/gadgetlib2/constraint.d new file mode 100644 index 0000000..5a7817c --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/constraint.d @@ -0,0 +1,19 @@ +src/gadgetlib2/constraint.o: src/gadgetlib2/constraint.cpp \ + src/gadgetlib2/constraint.hpp src/gadgetlib2/variable.hpp \ + src/gadgetlib2/pp.hpp src/common/default_types/ec_pp.hpp \ + src/algebra/curves/bn128/bn128_pp.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/bn128/bn128_init.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc depinst/include/bn.h \ + depinst/include/zm2.h depinst/include/zm.h \ + src/algebra/curves/bn128/bn128_g1.hpp src/algebra/curves/curve_utils.hpp \ + src/algebra/curves/curve_utils.tcc src/algebra/curves/bn128/bn128_g2.hpp \ + src/algebra/curves/bn128/bn128_gt.hpp \ + src/algebra/curves/bn128/bn128_pairing.hpp \ + src/gadgetlib2/infrastructure.hpp src/gadgetlib2/variable_operators.hpp diff --git a/privacy/zsl/zsl/gadgetlib2/constraint.hpp b/privacy/zsl/zsl/gadgetlib2/constraint.hpp new file mode 100644 index 0000000..5b51e44 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/constraint.hpp @@ -0,0 +1,177 @@ +/** @file + ***************************************************************************** + Declaration of the Constraint class. + + A constraint is an algebraic equation which can be either satisfied by an assignment, + (the equation is true with that assignment) or unsatisfied. For instance the rank-1 + constraint (X * Y = 15) is satisfied by {X=5 Y=3} or {X=3 Y=5} + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_CONSTRAINT_HPP_ +#define LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_CONSTRAINT_HPP_ + +#include +#include +#include "variable.hpp" + +namespace gadgetlib2 { + +enum class PrintOptions { + DBG_PRINT_IF_NOT_SATISFIED, + DBG_PRINT_IF_TRUE, + DBG_PRINT_IF_FALSE, + NO_DBG_PRINT +}; + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Constraint ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/// An abstract class for a field agnostic constraint. The derived classes will be field specific. +class Constraint { +public: + explicit Constraint(const ::std::string& name); // casting disallowed by 'explicit' + ::std::string name() const; ///< @returns name of the constraint as a string + /** + @param[in] assignment - An assignment of field elements for each variable. + @param[in] printOnFail - when set to true, an unsatisfied constraint will print to stderr + information explaining why it is not satisfied. + @returns true if constraint is satisfied by the assignment + **/ + virtual bool isSatisfied(const VariableAssignment& assignment, + const PrintOptions& printOnFail) const = 0; + /// @returns the constraint in a human readable string format + virtual ::std::string annotation() const = 0; + virtual const Variable::set getUsedVariables() const = 0; + virtual Polynomial asPolynomial() const = 0; +protected: +# ifdef DEBUG + ::std::string name_; +# endif + +}; // class Constraint + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Rank1Constraint ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/// A rank-1 prime characteristic constraint. The constraint is defined by * = +/// where x is an assignment of field elements to the variables. +class Rank1Constraint : public Constraint { +private: + LinearCombination a_, b_, c_; // * = +public: + Rank1Constraint(const LinearCombination& a, + const LinearCombination& b, + const LinearCombination& c, + const ::std::string& name); + + LinearCombination a() const; + LinearCombination b() const; + LinearCombination c() const; + + virtual bool isSatisfied(const VariableAssignment& assignment, + const PrintOptions& printOnFail = PrintOptions::NO_DBG_PRINT) const; + virtual ::std::string annotation() const; + virtual const Variable::set getUsedVariables() const; /**< @returns a list of all variables + used in the constraint */ + virtual Polynomial asPolynomial() const {return a_ * b_ - c_;} +}; // class Rank1Constraint + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class PolynomialConstraint ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +class PolynomialConstraint : public Constraint { +private: + Polynomial a_, b_; +public: + PolynomialConstraint(const Polynomial& a, + const Polynomial& b, + const ::std::string& name); + + bool isSatisfied(const VariableAssignment& assignment, + const PrintOptions& printOnFail = PrintOptions::NO_DBG_PRINT) const; + ::std::string annotation() const; + virtual const Variable::set getUsedVariables() const; /**< @returns a list of all variables + used in the constraint */ + virtual Polynomial asPolynomial() const {return a_ - b_;} +}; // class PolynomialConstraint + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class ConstraintSystem ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +class ConstraintSystem { +protected: + typedef ::std::shared_ptr ConstraintPtr; + ::std::vector constraintsPtrs_; +public: + ConstraintSystem() : constraintsPtrs_() {}; + + /** + Checks if all constraints are satisfied by an assignment. + @param[in] assignment - An assignment of field elements for each variable. + @param[in] printOnFail - when set to true, an unsatisfied constraint will print to stderr + information explaining why it is not satisfied. + @returns true if constraint is satisfied by the assignment + **/ + bool isSatisfied(const VariableAssignment& assignment, + const PrintOptions& printOnFail = PrintOptions::NO_DBG_PRINT) const; + void addConstraint(const Rank1Constraint& c); + void addConstraint(const PolynomialConstraint& c); + ::std::string annotation() const; + Variable::set getUsedVariables() const; + + typedef ::std::set< ::std::unique_ptr > PolyPtrSet; + /// Required for interfacing with BREX. Should be optimized in the future + PolyPtrSet getConstraintPolynomials() const { + PolyPtrSet retset; + for(const auto& pConstraint : constraintsPtrs_) { + retset.insert(::std::unique_ptr(new Polynomial(pConstraint->asPolynomial()))); + } + return retset; + } + size_t getNumberOfConstraints() { return constraintsPtrs_.size(); } + ConstraintPtr getConstraint(size_t idx){ return constraintsPtrs_[idx];} + friend class GadgetLibAdapter; +}; // class ConstraintSystem + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +} // namespace gadgetlib2 + +#endif // LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_CONSTRAINT_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib2/examples/simple_example.cpp b/privacy/zsl/zsl/gadgetlib2/examples/simple_example.cpp new file mode 100644 index 0000000..3bbe321 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/examples/simple_example.cpp @@ -0,0 +1,57 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "gadgetlib2/examples/simple_example.hpp" + +#include "gadgetlib2/adapters.hpp" +#include "gadgetlib2/gadget.hpp" +#include "gadgetlib2/integration.hpp" + +namespace libsnark { + +/* NOTE: all examples here actually generate one constraint less to account for soundness constraint in QAP */ +r1cs_example > gen_r1cs_example_from_gadgetlib2_protoboard(const size_t size) +{ + typedef Fr FieldT; + + gadgetlib2::initPublicParamsFromDefaultPp(); + // necessary in case a protoboard was built before, libsnark assumes variable indices always + // begin with 0 so we must reset the index before creating constraints which will be used by + // libsnark + gadgetlib2::GadgetLibAdapter::resetVariableIndex(); + + // create a gadgetlib2 gadget. This part is done by both generator and prover. + auto pb = gadgetlib2::Protoboard::create(gadgetlib2::R1P); + gadgetlib2::VariableArray A(size, "A"); + gadgetlib2::VariableArray B(size, "B"); + gadgetlib2::Variable result("result"); + auto g = gadgetlib2::InnerProduct_Gadget::create(pb, A, B, result); + // create constraints. This part is done by generator. + g->generateConstraints(); + // create assignment (witness). This part is done by prover. + for (size_t k = 0; k < size; ++k) + { + pb->val(A[k]) = std::rand() % 2; + pb->val(B[k]) = std::rand() % 2; + } + g->generateWitness(); + // translate constraint system to libsnark format. + r1cs_constraint_system cs = get_constraint_system_from_gadgetlib2(*pb); + // translate full variable assignment to libsnark format + const r1cs_variable_assignment full_assignment = get_variable_assignment_from_gadgetlib2(*pb); + // extract primary and auxiliary input + const r1cs_primary_input primary_input(full_assignment.begin(), full_assignment.begin() + cs.num_inputs()); + const r1cs_auxiliary_input auxiliary_input(full_assignment.begin() + cs.num_inputs(), full_assignment.end()); + + assert(cs.is_valid()); + assert(cs.is_satisfied(primary_input, auxiliary_input)); + + return r1cs_example(cs, primary_input, auxiliary_input); +} + +} // libsnark + diff --git a/privacy/zsl/zsl/gadgetlib2/examples/simple_example.d b/privacy/zsl/zsl/gadgetlib2/examples/simple_example.d new file mode 100644 index 0000000..e92a12b --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/examples/simple_example.d @@ -0,0 +1,30 @@ +src/gadgetlib2/examples/simple_example.o: \ + src/gadgetlib2/examples/simple_example.cpp \ + src/gadgetlib2/examples/simple_example.hpp \ + src/common/default_types/ec_pp.hpp src/algebra/curves/bn128/bn128_pp.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/bn128/bn128_init.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc depinst/include/bn.h \ + depinst/include/zm2.h depinst/include/zm.h \ + src/algebra/curves/bn128/bn128_g1.hpp src/algebra/curves/curve_utils.hpp \ + src/algebra/curves/curve_utils.tcc src/algebra/curves/bn128/bn128_g2.hpp \ + src/algebra/curves/bn128/bn128_gt.hpp \ + src/algebra/curves/bn128/bn128_pairing.hpp \ + src/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp \ + src/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp \ + src/relations/variable.hpp src/relations/variable.tcc \ + src/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc \ + src/common/profiling.hpp \ + src/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc \ + src/gadgetlib2/adapters.hpp src/gadgetlib2/pp.hpp \ + src/gadgetlib2/variable.hpp src/gadgetlib2/infrastructure.hpp \ + src/gadgetlib2/variable_operators.hpp src/gadgetlib2/constraint.hpp \ + src/gadgetlib2/protoboard.hpp src/gadgetlib2/gadget.hpp \ + src/gadgetlib2/gadgetMacros.hpp src/gadgetlib2/integration.hpp \ + src/gadgetlib2/protoboard.hpp diff --git a/privacy/zsl/zsl/gadgetlib2/examples/simple_example.hpp b/privacy/zsl/zsl/gadgetlib2/examples/simple_example.hpp new file mode 100644 index 0000000..4440146 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/examples/simple_example.hpp @@ -0,0 +1,20 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SIMPLE_EXAMPLE_HPP_ +#define SIMPLE_EXAMPLE_HPP_ + +#include "common/default_types/ec_pp.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" + +namespace libsnark { + +r1cs_example > gen_r1cs_example_from_gadgetlib2_protoboard(const size_t size); + +} // libsnark + +#endif // SIMPLE_EXAMPLE_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib2/examples/tutorial.cpp b/privacy/zsl/zsl/gadgetlib2/examples/tutorial.cpp new file mode 100644 index 0000000..01f7543 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/examples/tutorial.cpp @@ -0,0 +1,505 @@ +/** @file +******************************************************************************** +Tutorial and usage examples of the gadgetlib2 library and ppzkSNARK integration. +This file is meant to be read top-down as a tutorial for gadget writing. + ***************************************************************************** + Tutorial and usage examples of the gadgetlib2 library. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" +#include "gadgetlib2/examples/simple_example.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp" + +namespace gadgetExamples { + +using namespace gadgetlib2; + +/* + This test gives the first example of a construction of a constraint system. We use the terms + 'Constraint System' and 'Circuit' interchangeably rather loosly. It is easy to + visualize a circuit with inputs and outputs. Each gate imposes some logic on the inputs and + output wires. For instance, AND(inp1, inp2) will impose the 'constraint' (inp1 & inp2 = out) + Thus, we can also think of this circuit as a system of constraints. Each gate is a mathematical + constraint and each wire is a variable. In the AND example over a boolean field {0,1} we would + write the constraint as (inp1 * inp2 == out). This constraint is 'satisfied' relative to an + assignment if we assign values to {inp1, inp2, out} such that the constraint evaluates to TRUE. + All following examples will be either field agnostic or of a specific form of prime fields: + (1) Field agnostic case: In these examples we create high level circuits by using lower level + circuits. This way we can ignore the specifics of a field and assume the lower level takes + care of this. If we must explicitly write constraints in these circuits, they will always + be very basic constraints which are defined over every field (e.g. x + y = 0). + (2) All field specific examples in this library are for a prime characteristic field with the + special form of 'quadratic rank 1 polynomials', or R1P. This is the only form used with the + current implementaition of SNARKs. The form for these constraints is + (Linear Combination) * (Linear Combination) == (Linear Combination). + The library has been designed to allow future addition of other characteristics/forms in + the future by implementing only low level circuits for these forms. +*/ +TEST(Examples, ProtoboardUsage) { + // Initialize prime field parameters. This is always needed for R1P. + initPublicParamsFromDefaultPp(); + // The protoboard is the 'memory manager' which holds all constraints (when creating the + // verifying circuit) and variable assignments (when creating the proof witness). We specify + // the type as R1P, this can be augmented in the future to allow for BOOLEAN or GF2_EXTENSION + // fields in the future. + ProtoboardPtr pb = Protoboard::create(R1P); + // We now create 3 input variables and one output + VariableArray input(3, "input"); + Variable output("output"); + // We can now add some constraints. The string is for debuging purposes and can be a textual + // description of the constraint + pb->addRank1Constraint(input[0], 5 + input[2], output, + "Constraint 1: input[0] * (5 + input[2]) == output"); + // The second form addUnaryConstraint(LinearCombination) means (LinearCombination == 0). + pb->addUnaryConstraint(input[1] - output, + "Constraint 2: input[1] - output == 0"); + // Notice this could also have been written: + // pb->addRank1Constraint(1, input[1] - input[2], 0, ""); + // + // For fields with more general forms, once implemented, we could use + // addGeneralConstraint(Polynomial1, Polynomial2, string) which translates to the constraint + // (Polynomial1 == Polynomial2). Example: + // pb->addGeneralConstraint(input[0] * (3 + input[1]) * input[2], output + 5, + // "input[0] * (3 + input[1]) * input[2] == output + 5"); + // + // Now we can assign values to the variables and see if the constraints are satisfied. + // Later, when we will run a SNARK (or any other proof system), the constraints will be + // used by the verifier, and the assigned values will be used by the prover. + // Notice the protoboard stores the assignment values. + pb->val(input[0]) = pb->val(input[1]) = pb->val(input[2]) = pb->val(output) = 42; + EXPECT_FALSE(pb->isSatisfied()); + // The constraint system is not satisfied. Now lets try values which satisfy the two equations + // above: + pb->val(input[0]) = 1; + pb->val(input[1]) = pb->val(output) = 42; // input[1] - output == 0 + pb->val(input[2]) = 37; // 1 * (5 + 37) == 42 + EXPECT_TRUE(pb->isSatisfied()); +} + +/* + In the above example we explicitly wrote all constraints and assignments. + + In this example we will construct a very simple gadget, one that implements a NAND gate. This + gadget is field-agnostic as it only uses lower level gadgets and the field elments '0' and '1'. + + Gadgets are the framework which allow us to delegate construction of sophisticated circuitry + to lower levels. Each gadget can construct a constraint system or a witness or both, by + defining constraints and assignments as well as by utilizing sub-gadgets. +*/ + +class NAND_Gadget : public Gadget { +public: + // This is a convention we use to always create gadgets as if from a factory class. This will + // be needed later for gadgets which have different implementaions in different fields. + static GadgetPtr create(ProtoboardPtr pb, + const FlagVariableArray& inputs, + const FlagVariable& output); + // generateConstraints() is the method which creates all constraints on the protoboard + void generateConstraints(); + // generateWitness() is the method which generates the witness by assigning a valid value to + // each wire in the circuit (variable) and putting this on the protoboard + void generateWitness(); +private: + // constructor is private in order to stick to the convention that gadgets are created using a + // create() method. This may not make sense now, but when dealing with non-field agnostic + // gadgets it is very convenient to have a factory class with this convention. + // Notice the protoboard. This can be thought of as a 'memory manager' which holds the circuit + // as the constraints are being built, and the 'wire values' as the witness is being built + NAND_Gadget(ProtoboardPtr pb, const FlagVariableArray& inputs, const FlagVariable& output); + // init() does any non trivial work which we don't want in the constructor. This is where we + // will 'wire' the sub-gadgets into the circuit. Each sub-gadget can be thought of as a + // circuit gate with some specific functionality. + void init(); + // we want every gadget to be explicitly constructed + DISALLOW_COPY_AND_ASSIGN(NAND_Gadget); + + // This is an internal gadget. Once a gadget is created it can be used as a black box gate. We + // will initialize this pointer to be an AND_Gadget in the init() method. + GadgetPtr andGadget_; + // These are internal variables used by the class. They will always include the variables from + // the constructor, but can include many more as well. Notice that almost always the variables + // can be declared 'const', as these are local copies of formal variables, and do not change + // over the span of the class' lifetime. + const VariableArray inputs_; + const FlagVariable output_; + const FlagVariable andResult_; +}; + +// IMPLEMENTATION +// Most constructors are trivial and only initialize and assert values. +NAND_Gadget::NAND_Gadget(ProtoboardPtr pb, + const FlagVariableArray& inputs, + const FlagVariable& output) + : Gadget(pb), inputs_(inputs), output_(output), andResult_("andResult") {} + +void NAND_Gadget::init() { + // we 'wire' the AND gate. + andGadget_ = AND_Gadget::create(pb_, inputs_, andResult_); +} + +// The create() method will usually look like this, for field-agnostic gadgets: +GadgetPtr NAND_Gadget::create(ProtoboardPtr pb, + const FlagVariableArray& inputs, + const FlagVariable& output) { + GadgetPtr pGadget(new NAND_Gadget(pb, inputs, output)); + pGadget->init(); + return pGadget; +} + +void NAND_Gadget::generateConstraints() { + // we will invoke the AND gate constraint generator + andGadget_->generateConstraints(); + // and add our out negation constraint in order to make this a NAND gate + addRank1Constraint(1, 1 - andResult_, output_, "1 * (1 - andResult) = output"); + // Another way to write the same constraint is: + // addUnaryConstraint(1 - andResult_ - output_, "1 - andResult == output"); + // + // At first look, it would seem that this is enough. However, the AND_Gadget expects all of its + // inputs to be boolean, a dishonest prover could put non-boolean inputs, so we must check this + // here. Notice 'FlagVariable' means a variable which we intend to hold only '0' or '1', but + // this is just a convention (it is a typedef for Variable) and we must enforce it. + // Look into the internals of the R1P implementation of AND_Gadget and see that + // {2, 1, 0} as inputs with {1} as output would satisfy all constraints, even though this is + // clearly not our intent! + for (const auto& input : inputs_) { + enforceBooleanity(input); // This adds a constraint of the form: input * (1 - input) == 0 + } +} + +void NAND_Gadget::generateWitness() { + // First we can assert that all input values are indeed boolean. The purpose of this assertion + // is simply to print a clear error message, it is not security critical. + // Notice the method val() which returns a reference to the current assignment for a variable + for (const auto& input : inputs_) { + GADGETLIB_ASSERT(val(input) == 0 || val(input) == 1, "NAND input is not boolean"); + } + // we will invoke the AND gate witness generator, this will set andResult_ correctly + andGadget_->generateWitness(); + // and now we set the value of output_ + val(output_) = 1 - val(andResult_); + // notice the use of 'val()' to tell the protoboard to assign this new value to the + // variable 'output_'. The variable itself is only a formal variable and never changes. +} + +// And now for a test which will exemplify the usage: +TEST(Examples, NAND_Gadget) { + // initialize the field + initPublicParamsFromDefaultPp(); + // create a protoboard for a system of rank 1 constraints over a prime field. + ProtoboardPtr pb = Protoboard::create(R1P); + // create 5 variables inputs[0]...iputs[4]. The string "inputs" is used for debug messages + FlagVariableArray inputs(5, "inputs"); + FlagVariable output("output"); + GadgetPtr nandGadget = NAND_Gadget::create(pb, inputs, output); + // now we can generate a constraint system (or circuit) + nandGadget->generateConstraints(); + // if we try to evaluate the circuit now, an exception will be thrown, because we will + // be attempting to evaluate unasigned variables. + EXPECT_ANY_THROW(pb->isSatisfied()); + // so lets assign the input variables for NAND and try again after creating the witness + for (const auto& input : inputs) { + pb->val(input) = 1; + } + nandGadget->generateWitness(); + EXPECT_TRUE(pb->isSatisfied()); + EXPECT_TRUE(pb->val(output) == 0); + // now lets try to ruin something and see what happens + pb->val(inputs[2]) = 0; + EXPECT_FALSE(pb->isSatisfied()); + // now let try to cheat. If we hadn't enforced booleanity, this would have worked! + pb->val(inputs[1]) = 2; + EXPECT_FALSE(pb->isSatisfied()); + // now lets reset inputs[1] to a valid value + pb->val(inputs[1]) = 1; + // before, we set both the inputs and the output. Notice the output is still set to '0' + EXPECT_TRUE(pb->val(output) == 0); + // Now we will let the gadget compute the result using generateWitness() and see what happens + nandGadget->generateWitness(); + EXPECT_TRUE(pb->val(output) == 1); + EXPECT_TRUE(pb->isSatisfied()); +} + +/* + Another example showing the use of DualVariable. A DualVariable is a variable which holds both + a bitwise representation of a word and a packed representation (e.g. both the packed value {42} + and the unpacked value {1,0,1,0,1,0}). If the word is short enough + (for example any integer smaller than the prime characteristic) then the packed representation + will be stored in 1 field element. 'word' in this context means a set of bits, it is a + convention which means we expect some semantic ability to decompose the packed value into its + bits. + The use of DualVariables is for efficiency reasons. More on this at the end of this example. + In this example we will construct a gadget which receives as input a packed integer value + called 'hash', and a 'difficulty' level in bits, and constructs a circuit validating that the + first 'difficulty' bits of 'hash' are '0'. For simplicity we will assume 'hash' is always 64 + bits long. +*/ + +class HashDifficultyEnforcer_Gadget : public Gadget { +public: + static GadgetPtr create(ProtoboardPtr pb, + const MultiPackedWord& hashValue, + const size_t difficultyBits); + void generateConstraints(); + void generateWitness(); +private: + const size_t hashSizeInBits_; + const size_t difficultyBits_; + DualWord hashValue_; + // This GadgetPtr will be a gadget to unpack hashValue_ from packed representation to bit + // representation. Recall 'DualWord' holds both values, but only the packed version will be + // recieved as input to the constructor. + GadgetPtr hashValueUnpacker_; + + HashDifficultyEnforcer_Gadget(ProtoboardPtr pb, + const MultiPackedWord& hashValue, + const size_t difficultyBits); + void init(); + DISALLOW_COPY_AND_ASSIGN(HashDifficultyEnforcer_Gadget); +}; + +// IMPLEMENTATION +HashDifficultyEnforcer_Gadget::HashDifficultyEnforcer_Gadget(ProtoboardPtr pb, + const MultiPackedWord& hashValue, + const size_t difficultyBits) + : Gadget(pb), hashSizeInBits_(64), difficultyBits_(difficultyBits), + hashValue_(hashValue, UnpackedWord(64, "hashValue_u")) +{ +} + +void HashDifficultyEnforcer_Gadget::init() { + // because we are using a prime field with large characteristic, we can assume a 64 bit value + // fits in the first element of a multipacked variable. + GADGETLIB_ASSERT(hashValue_.multipacked().size() == 1, "multipacked word size too large"); + // A DualWord_Gadget's constraints assert that the unpacked and packed values represent the + // same integer element. The generateWitnes() method has two modes, one for packing (taking the + // bit representation as input) and one for unpacking (creating the bit representation from + // the packed representation) + hashValueUnpacker_ = DualWord_Gadget::create(pb_, hashValue_, PackingMode::UNPACK); +} + +GadgetPtr HashDifficultyEnforcer_Gadget::create(ProtoboardPtr pb, + const MultiPackedWord& hashValue, + const size_t difficultyBits) { + GadgetPtr pGadget(new HashDifficultyEnforcer_Gadget(pb, hashValue, difficultyBits)); + pGadget->init(); + return pGadget; +} + +void HashDifficultyEnforcer_Gadget::generateConstraints() { + // enforce that both representations are equal + hashValueUnpacker_->generateConstraints(); + // add constraints asserting that the first 'difficultyBits' bits of 'hashValue' equal 0. Note + // endianness, unpacked()[0] is LSB and unpacked()[63] is MSB + for (size_t i = 0; i < difficultyBits_; ++i) { + addUnaryConstraint(hashValue_.unpacked()[63 - i], GADGETLIB2_FMT("hashValue[%u] == 0", 63 - i)); + } +} + +void HashDifficultyEnforcer_Gadget::generateWitness() { + // Take the packed representation and unpack to bits. + hashValueUnpacker_->generateWitness(); + // In a real setting we would add an assertion that the value will indeed satisfy the + // difficulty constraint, and notify the user with an error otherwise. As this is a tutorial, + // we'll let invalid values pass through so that we can see how isSatisfied() returns false. +} + +// Remember we pointed out that DualVariables are used for efficiency reasons. Now is the time to +// elaborate on this. As you've seen, we needed a bit representation in order to check the first +// bits of hashValue. But hashValue may be used in many other places, for instance we may want to +// check equality with another value. Checking equality on a packed representation will 'cost' us +// 1 constraint, while checking equality on the unpacked value will 'cost' us 64 constraints. This +// translates heavily into proof construction time and memory in the ppzkSNARK proof system. + +TEST(Examples, HashDifficultyEnforcer_Gadget) { + initPublicParamsFromDefaultPp(); + auto pb = Protoboard::create(R1P); + const MultiPackedWord hashValue(64, R1P, "hashValue"); + const size_t difficulty = 10; + auto difficultyEnforcer = HashDifficultyEnforcer_Gadget::create(pb, hashValue, difficulty); + difficultyEnforcer->generateConstraints(); + // constraints are created but no assignment yet. Will throw error on evaluation + EXPECT_ANY_THROW(pb->isSatisfied()); + pb->val(hashValue[0]) = 42; + difficultyEnforcer->generateWitness(); + // First 10 bits of 42 (when represented as a 64 bit number) are '0' so this should work + EXPECT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + pb->val(hashValue[0]) = 1000000000000000000; + // This is a value > 2^54 so we expect constraint system not to be satisfied. + difficultyEnforcer->generateWitness(); // This would have failed had we put an assertion + EXPECT_FALSE(pb->isSatisfied()); +} + + +/* + In this exampe we will construct a gadget which builds a circuit for proof (witness) and + validation (constraints) that a bitcoin transaction's sum of inputs equals the the sum of + outputs + miners fee. Construction of the proof will include finding the miners' + fee. This fee can be thought of as an output of the circuit. + + This is a field specific gadget, as we will use the '+' operator freely. The addition + operation works as expected over integers while in prime characteristic fields but not so in + extension fields. If you are not familiar with extension fields, don't worry about it. Simply + be aware that + and * behave differently in different fields and don't necessarily give the + integer values you would expect. + + The library design supports multiple field constructs due to different applied use cases. Some + cryptogragraphic applications may need extension fields while others may need prime fields + but with constraints which are not rank-1 and yet others may need boolean circuits. The library + was designed so that high level gadgets can be reused by implementing only the low level for + a new field or constraint structure. + + Later we will supply a recipe for creation of such field specfic gadgets with agnostic + interfaces. We use a few conventions here in order to ease the process by using macros. +*/ + + +// This is a macro which creates an interface class for all field specific derived gadgets +// Convention is: class {GadgetName}_GadgetBase +CREATE_GADGET_BASE_CLASS(VerifyTransactionAmounts_GadgetBase); + +// Notice the multiple inheritance. We must specify the interface as well as the field specific +// base gadget. This is what allows the factory class to decide at compile time which field +// specific class to instantiate for every protoboard. See design notes in "gadget.hpp" +// Convention is: class {FieldType}_{GadgetName}_Gadget +class R1P_VerifyTransactionAmounts_Gadget : public VerifyTransactionAmounts_GadgetBase, + public R1P_Gadget { +public: + void generateConstraints(); + void generateWitness(); + + // We give the factory class friend access in order to instantiate via private constructor. + friend class VerifyTransactionAmounts_Gadget; +private: + R1P_VerifyTransactionAmounts_Gadget(ProtoboardPtr pb, + const VariableArray& txInputAmounts, + const VariableArray& txOutputAmounts, + const Variable& minersFee); + void init(); + + const VariableArray txInputAmounts_; + const VariableArray txOutputAmounts_; + const Variable minersFee_; + + DISALLOW_COPY_AND_ASSIGN(R1P_VerifyTransactionAmounts_Gadget); +}; + +// create factory class using CREATE_GADGET_FACTORY_CLASS_XX macro (substitute XX with the number +// of arguments to the constructor, excluding the protoboard). Sometimes we want multiple +// constructors, see AND_Gadget for example. In this case we will have to manually write the +// factory class. +CREATE_GADGET_FACTORY_CLASS_3(VerifyTransactionAmounts_Gadget, + VariableArray, txInputAmounts, + VariableArray, txOutputAmounts, + Variable, minersFee); + +// IMPLEMENTATION + +// Destructor for the Base class +VerifyTransactionAmounts_GadgetBase::~VerifyTransactionAmounts_GadgetBase() {} + +void R1P_VerifyTransactionAmounts_Gadget::generateConstraints() { + addUnaryConstraint(sum(txInputAmounts_) - sum(txOutputAmounts_) - minersFee_, + "sum(txInputAmounts) == sum(txOutputAmounts) + minersFee"); + // It would seem this is enough, but an adversary could cause an overflow of one side of the + // equation over the field modulus. In fact, for every input/output sum we will always find a + // miners' fee which will satisfy this constraint! + // It is left as an excercise for the reader to implement additional constraints (and witness) + // to check that each of the amounts (inputs, outputs, fee) are between 0 and 21,000,000 * 1E8 + // satoshis. Combine this with a maximum amount of inputs/outputs to disallow field overflow. + // + // Hint: use Comparison_Gadget to create a gadget which compares a variable's assigned value + // to a constant. Use a vector of these new gadgets to check each amount. + // Don't forget to: + // (1) Wire these gadgets in init() + // (2) Invoke the gadgets' constraints in generateConstraints() + // (3) Invoke the gadgets' witnesses in generateWitness() +} + +void R1P_VerifyTransactionAmounts_Gadget::generateWitness() { + FElem sumInputs = 0; + FElem sumOutputs = 0; + for (const auto& inputAmount : txInputAmounts_) { + sumInputs += val(inputAmount); + } + for (const auto& outputAmount : txOutputAmounts_) { + sumOutputs += val(outputAmount); + } + val(minersFee_) = sumInputs - sumOutputs; +} + +R1P_VerifyTransactionAmounts_Gadget::R1P_VerifyTransactionAmounts_Gadget( + ProtoboardPtr pb, + const VariableArray& txInputAmounts, + const VariableArray& txOutputAmounts, + const Variable& minersFee) + // Notice we must initialize 3 base classes (diamond inheritance): + : Gadget(pb), VerifyTransactionAmounts_GadgetBase(pb), R1P_Gadget(pb), + txInputAmounts_(txInputAmounts), txOutputAmounts_(txOutputAmounts), + minersFee_(minersFee) {} + +void R1P_VerifyTransactionAmounts_Gadget::init() {} + +/* + As promised, recipe for creating field specific gadgets with agnostic interfaces: + + (1) Create the Base class using macro: + CREATE_GADGET_BASE_CLASS({GadgetName}_GadgetBase); + (2) Create the destructor for the base class: + {GadgetName_Gadget}Base::~{GadgetName}_GadgetBase() {} + (3) Create any field specific gadgets with multiple inheritance: + class {FieldType}_{GadgetName}_Gadget : public {GadgetName}_GadgetBase, + public {FieldType_Gadget} + Notice all arguments to the constructors must be const& in order to use the factory class + macro. Constructor arguments must be the same for all field specific implementations. + (4) Give the factory class {GadgetName}_Gadget public friend access to the field specific + classes. + (5) Create the factory class using the macro: + CREATE_GADGET_FACTORY_CLASS_XX({GadgetName}_Gadget, type1, input1, type2, input2, ... , + typeXX, inputXX); +*/ + +TEST(Examples, R1P_VerifyTransactionAmounts_Gadget) { + initPublicParamsFromDefaultPp(); + auto pb = Protoboard::create(R1P); + const VariableArray inputAmounts(2, "inputAmounts"); + const VariableArray outputAmounts(3, "outputAmounts"); + const Variable minersFee("minersFee"); + auto verifyTx = VerifyTransactionAmounts_Gadget::create(pb, inputAmounts, outputAmounts, + minersFee); + verifyTx->generateConstraints(); + pb->val(inputAmounts[0]) = pb->val(inputAmounts[1]) = 2; + pb->val(outputAmounts[0]) = pb->val(outputAmounts[1]) = pb->val(outputAmounts[2]) = 1; + verifyTx->generateWitness(); + EXPECT_TRUE(pb->isSatisfied()); + EXPECT_EQ(pb->val(minersFee), 1); + pb->val(minersFee) = 3; + EXPECT_FALSE(pb->isSatisfied()); +} + +/* + Below is an example of integrating gadgetlib2 constructed constraint systems with the + ppzkSNARK. +*/ + +TEST(gadgetLib2,Integration) { + initPublicParamsFromDefaultPp(); + // Create an example constraint system and translate to libsnark format + const libsnark::r1cs_example > example = libsnark::gen_r1cs_example_from_gadgetlib2_protoboard(100); + const bool test_serialization = false; + // Run ppzksnark. Jump into function for breakdown + const bool bit = libsnark::run_r1cs_ppzksnark(example, test_serialization); + EXPECT_TRUE(bit); +}; + +} // namespace gadgetExamples + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/privacy/zsl/zsl/gadgetlib2/gadget.cpp b/privacy/zsl/zsl/gadgetlib2/gadget.cpp new file mode 100644 index 0000000..71a0409 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/gadget.cpp @@ -0,0 +1,955 @@ +/** @file + ***************************************************************************** + Declarations of the interfaces and basic gadgets for R1P (Rank 1 prime characteristic) + constraint systems. + + See details in gadget.hpp . + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include "gadget.hpp" + +using ::std::shared_ptr; +using ::std::string; +using ::std::vector; +using ::std::cout; +using ::std::cerr; +using ::std::endl; + +namespace gadgetlib2 { + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* Gadget Interfaces ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/***********************************/ +/*** Gadget ***/ +/***********************************/ + +Gadget::Gadget(ProtoboardPtr pb) : pb_(pb) { + GADGETLIB_ASSERT(pb != NULL, "Attempted to create gadget with uninitialized Protoboard."); +} + +void Gadget::generateWitness() { + GADGETLIB_FATAL("Attempted to generate witness for an incomplete Gadget type."); +} + +void Gadget::addUnaryConstraint(const LinearCombination& a, const ::std::string& name) { + pb_->addUnaryConstraint(a, name); +} + +void Gadget::addRank1Constraint(const LinearCombination& a, + const LinearCombination& b, + const LinearCombination& c, + const ::std::string& name) { + pb_->addRank1Constraint(a, b, c, name); +} + +/***********************************/ +/*** R1P_Gadget ***/ +/***********************************/ +R1P_Gadget::~R1P_Gadget() {}; + +void R1P_Gadget::addRank1Constraint(const LinearCombination& a, + const LinearCombination& b, + const LinearCombination& c, + const string& name) { + pb_->addRank1Constraint(a,b,c, name); +} + +/***********************************/ +/*** End of Gadget Interfaces ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* AND Gadgets ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +AND_GadgetBase::~AND_GadgetBase() {}; + +/* + Constraint breakdown: + (1) input1 * input2 = result +*/ +BinaryAND_Gadget::BinaryAND_Gadget(ProtoboardPtr pb, + const LinearCombination& input1, + const LinearCombination& input2, + const Variable& result) + : Gadget(pb), AND_GadgetBase(pb), input1_(input1), input2_(input2), result_(result) {} + +void BinaryAND_Gadget::init() {} + +void BinaryAND_Gadget::generateConstraints() { + addRank1Constraint(input1_, input2_, result_, "result = AND(input1, input2)"); +} + +void BinaryAND_Gadget::generateWitness() { + if (val(input1_) == 1 && val(input2_) == 1) { + val(result_) = 1; + } else { + val(result_) = 0; + } +} + +/* + Constraint breakdown: + + (*) sum = sum(input[i]) - n + (1) sum * result = 0 + (2) sum * sumInverse = 1 - result + + [ AND(inputs) == 1 ] (*)==> [sum == 0] (2)==> [result == 1] + [ AND(inputs) == 0 ] (*)==> [sum != 0] (1)==> [result == 0] +*/ + +R1P_AND_Gadget::R1P_AND_Gadget(ProtoboardPtr pb, + const VariableArray &input, + const Variable &result) + : Gadget(pb), AND_GadgetBase(pb), R1P_Gadget(pb), input_(input), result_(result), + sumInverse_("sumInverse") { + GADGETLIB_ASSERT(input.size() > 0, "Attempted to create an R1P_AND_Gadget with 0 inputs."); + GADGETLIB_ASSERT(input.size() <= Fp(-1).as_ulong(), "Attempted to create R1P_AND_Gadget with too " + "many inputs. Will cause overflow!"); +} + +void R1P_AND_Gadget::init() { + const int numInputs = input_.size(); + sum_ = sum(input_) - numInputs; +} + +void R1P_AND_Gadget::generateConstraints() { + addRank1Constraint(sum_, result_, 0, + "sum * result = 0 | sum == sum(input[i]) - n"); + addRank1Constraint(sumInverse_, sum_, 1-result_, + "sumInverse * sum = 1-result | sum == sum(input[i]) - n"); +} + +void R1P_AND_Gadget::generateWitness() { + FElem sum = 0; + for(size_t i = 0; i < input_.size(); ++i) { + sum += val(input_[i]); + } + sum -= input_.size(); // sum(input[i]) - n ==> sum + if (sum == 0) { // AND(input[0], input[1], ...) == 1 + val(sumInverse_) = 0; + val(result_) = 1; + } else { // AND(input[0], input[1], ...) == 0 + val(sumInverse_) = sum.inverse(R1P); + val(result_) = 0; + } +} + +GadgetPtr AND_Gadget::create(ProtoboardPtr pb, const VariableArray& input, const Variable& result){ + GadgetPtr pGadget; + if (pb->fieldType_ == R1P) { + pGadget.reset(new R1P_AND_Gadget(pb, input, result)); + } else { + GADGETLIB_FATAL("Attempted to create gadget of undefined Protoboard type."); + } + pGadget->init(); + return pGadget; +} + +GadgetPtr AND_Gadget::create(ProtoboardPtr pb, + const LinearCombination& input1, + const LinearCombination& input2, + const Variable& result) { + GadgetPtr pGadget(new BinaryAND_Gadget(pb, input1, input2, result)); + pGadget->init(); + return pGadget; +} + +/***********************************/ +/*** End of AND Gadgets ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* OR Gadgets ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +OR_GadgetBase::~OR_GadgetBase() {}; + +/* + Constraint breakdown: + (1) result = input1 + input2 - input1 * input2 + input1 * input2 = input1 + input2 - result +*/ +BinaryOR_Gadget::BinaryOR_Gadget(ProtoboardPtr pb, + const LinearCombination& input1, + const LinearCombination& input2, + const Variable& result) + : Gadget(pb), OR_GadgetBase(pb), input1_(input1), input2_(input2), result_(result) {} + +void BinaryOR_Gadget::init() {} + +void BinaryOR_Gadget::generateConstraints() { + addRank1Constraint(input1_, input2_, input1_ + input2_ - result_, + "result = OR(input1, input2)"); +} + +void BinaryOR_Gadget::generateWitness() { + if (val(input1_) == 1 || val(input2_) == 1) { + val(result_) = 1; + } else { + val(result_) = 0; + } +} + +/* + Constraint breakdown: + + (*) sum = sum(input[i]) + (1) sum * (1 - result) = 0 + (2) sum * sumInverse = result + + [ OR(inputs) == 1 ] (*)==> [sum != 0] (1)==> [result == 1] + [ OR(inputs) == 0 ] (*)==> [sum == 0] (2)==> [result == 0] +*/ + +R1P_OR_Gadget::R1P_OR_Gadget(ProtoboardPtr pb, + const VariableArray &input, + const Variable &result) + : Gadget(pb), OR_GadgetBase(pb), R1P_Gadget(pb), sumInverse_("sumInverse"), input_(input), + result_(result) { + GADGETLIB_ASSERT(input.size() > 0, "Attempted to create an R1P_OR_Gadget with 0 inputs."); + GADGETLIB_ASSERT(input.size() <= Fp(-1).as_ulong(), "Attempted to create R1P_OR_Gadget with too " + "many inputs. Will cause overflow!"); + + } + +void R1P_OR_Gadget::init() { + sum_ = sum(input_); +} + +void R1P_OR_Gadget::generateConstraints() { + addRank1Constraint(sum_, 1 - result_, 0, + "sum * (1 - result) = 0 | sum == sum(input[i])"); + addRank1Constraint(sumInverse_, sum_, result_, + "sum * sumInverse = result | sum == sum(input[i])"); +} + +void R1P_OR_Gadget::generateWitness() { + FElem sum = 0; + for(size_t i = 0; i < input_.size(); ++i) { // sum(input[i]) ==> sum + sum += val(input_[i]); + } + if (sum == 0) { // OR(input[0], input[1], ...) == 0 + val(sumInverse_) = 0; + val(result_) = 0; + } else { // OR(input[0], input[1], ...) == 1 + val(sumInverse_) = sum.inverse(R1P); + val(result_) = 1; + } +} + +GadgetPtr OR_Gadget::create(ProtoboardPtr pb, const VariableArray& input, const Variable& result) { + GadgetPtr pGadget; + if (pb->fieldType_ == R1P) { + pGadget.reset(new R1P_OR_Gadget(pb, input, result)); + } else { + GADGETLIB_FATAL("Attempted to create gadget of undefined Protoboard type."); + } + pGadget->init(); + return pGadget; +} + +GadgetPtr OR_Gadget::create(ProtoboardPtr pb, + const LinearCombination& input1, + const LinearCombination& input2, + const Variable& result) { + GadgetPtr pGadget(new BinaryOR_Gadget(pb, input1, input2, result)); + pGadget->init(); + return pGadget; +} + +/***********************************/ +/*** End of OR Gadgets ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* InnerProduct Gadgets ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +InnerProduct_GadgetBase::~InnerProduct_GadgetBase() {}; + +/* + Constraint breakdown: + + (1) partialSums[0] = A[0] * B[0] + (2) partialSums[i] = partialSums[i-1] + A[0] * B[0] ==> i = 1..n-2 + partialSums[i] - partialSums[i-1] = A[i] * B[i] + (3) result = partialSums[n-1] = partialSums[n-2] + A[n-1] * B[n-1] ==> + result - partialSums[n-2] = A[n-1] * B[n-1] + +*/ + +R1P_InnerProduct_Gadget::R1P_InnerProduct_Gadget(ProtoboardPtr pb, + const VariableArray& A, + const VariableArray& B, + const Variable& result) + : Gadget(pb), InnerProduct_GadgetBase(pb), R1P_Gadget(pb), partialSums_(A.size(), + "partialSums"), A_(A), B_(B), result_(result) { + GADGETLIB_ASSERT(A.size() > 0, "Attempted to create an R1P_InnerProduct_Gadget with 0 inputs."); + GADGETLIB_ASSERT(A.size() == B.size(), GADGETLIB2_FMT("Inner product vector sizes not equal. Sizes are: " + "(A) - %u, (B) - %u", A.size(), B.size())); +} + +void R1P_InnerProduct_Gadget::init() {} + +void R1P_InnerProduct_Gadget::generateConstraints() { + const int n = A_.size(); + if (n == 1) { + addRank1Constraint(A_[0], B_[0], result_, "A[0] * B[0] = result"); + return; + } + // else (n > 1) + addRank1Constraint(A_[0], B_[0], partialSums_[0], "A[0] * B[0] = partialSums[0]"); + for(int i = 1; i <= n-2; ++i) { + addRank1Constraint(A_[i], B_[i], partialSums_[i] - partialSums_[i-1], + GADGETLIB2_FMT("A[%u] * B[%u] = partialSums[%u] - partialSums[%u]", i, i, i, i-1)); + } + addRank1Constraint(A_[n-1], B_[n-1], result_ - partialSums_[n-2], + "A[n-1] * B[n-1] = result - partialSums[n-2]"); +} + +void R1P_InnerProduct_Gadget::generateWitness() { + const int n = A_.size(); + if (n == 1) { + val(result_) = val(A_[0]) * val(B_[0]); + return; + } + // else (n > 1) + val(partialSums_[0]) = val(A_[0]) * val(B_[0]); + for(int i = 1; i <= n-2; ++i) { + val(partialSums_[i]) = val(partialSums_[i-1]) + val(A_[i]) * val(B_[i]); + } + val(result_) = val(partialSums_[n-2]) + val(A_[n-1]) * val(B_[n-1]); +} + +/***********************************/ +/*** End of InnerProduct Gadgets ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* LooseMUX Gadgets ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +LooseMUX_GadgetBase::~LooseMUX_GadgetBase() {}; + +/* + Constraint breakdown: + (1) indicators[i] * (index - i) = 0 | i = 0..n-1 ==> only indicators[index] will be non-zero + (2) sum(indicators[i]) = successFlag ==> successFlag = indicators[index] + (3) successFlag is boolean + (4) result[j] = * | j = 1..output.size() ==> + result[j] = inputs[index][j] + +*/ + +R1P_LooseMUX_Gadget::R1P_LooseMUX_Gadget(ProtoboardPtr pb, + const MultiPackedWordArray& inputs, + const Variable& index, + const VariableArray& output, + const Variable& successFlag) + : Gadget(pb), LooseMUX_GadgetBase(pb), R1P_Gadget(pb), + indicators_(inputs.size(), "indicators"), inputs_(inputs.size()), index_(index), + output_(output), successFlag_(successFlag) { + GADGETLIB_ASSERT(inputs.size() <= Fp(-1).as_ulong(), "Attempted to create R1P_LooseMUX_Gadget " + "with too many inputs. May cause overflow!"); +// for(const VariableArray& inpArr : inputs) { + for(size_t i = 0; i < inputs.size(); ++i) { + GADGETLIB_ASSERT(inputs[i].size() == output.size(), "Input VariableArray is of incorrect size."); + } + ::std::copy(inputs.begin(), inputs.end(), inputs_.begin()); // change type to R1P_VariableArray +} + +void R1P_LooseMUX_Gadget::init() { + // create inputs for the inner products and initialize them. Each iteration creates a + // VariableArray for the i'th elements from each of the vector's VariableArrays. + for(size_t i = 0; i < output_.size(); ++i) { + VariableArray curInput; + for(size_t j = 0; j < inputs_.size(); ++j) { + curInput.push_back(inputs_[j][i]); + } + computeResult_.push_back(InnerProduct_Gadget::create(pb_, indicators_, curInput, + output_[i])); + } +} + +void R1P_LooseMUX_Gadget::generateConstraints() { + const size_t n = inputs_.size(); + for(size_t i = 0; i < n; ++i) { + addRank1Constraint(indicators_[i], (index_-i), 0, + GADGETLIB2_FMT("indicators[%u] * (index - %u) = 0", i, i)); + } + addRank1Constraint(sum(indicators_), 1, successFlag_, "sum(indicators) * 1 = successFlag"); + enforceBooleanity(successFlag_); + for(auto& curGadget : computeResult_) { + curGadget->generateConstraints(); + } +} + +void R1P_LooseMUX_Gadget::generateWitness() { + const size_t n = inputs_.size(); + /* assumes that idx can be fit in ulong; true for our purposes for now */ + const size_t index = val(index_).asLong(); + const FElem arraySize = n; + for(size_t i = 0; i < n; ++i) { + val(indicators_[i]) = 0; // Redundant, but just in case. + } + if (index >= n) { // || index < 0 + val(successFlag_) = 0; + } else { // index in bounds + val(indicators_[index]) = 1; + val(successFlag_) = 1; + } + for(auto& curGadget : computeResult_) { + curGadget->generateWitness(); + } +} + +VariableArray R1P_LooseMUX_Gadget::indicatorVariables() const {return indicators_;} + +GadgetPtr LooseMUX_Gadget::create(ProtoboardPtr pb, + const MultiPackedWordArray& inputs, + const Variable& index, + const VariableArray& output, + const Variable& successFlag) { + GadgetPtr pGadget; + if (pb->fieldType_ == R1P) { + pGadget.reset(new R1P_LooseMUX_Gadget(pb, inputs, index, output, successFlag)); + } else { + GADGETLIB_FATAL("Attempted to create gadget of undefined Protoboard type."); + } + pGadget->init(); + return pGadget; +} + +/** + An overload for the private case in which we only want to multiplex one Variable. This is + usually the case in R1P. +**/ +GadgetPtr LooseMUX_Gadget::create(ProtoboardPtr pb, + const VariableArray& inputs, + const Variable& index, + const Variable& output, + const Variable& successFlag) { + MultiPackedWordArray inpVec; + for(size_t i = 0; i < inputs.size(); ++i) { + MultiPackedWord cur(pb->fieldType_); + cur.push_back(inputs[i]); + inpVec.push_back(cur); + } + VariableArray outVec; + outVec.push_back(output); + auto result = LooseMUX_Gadget::create(pb, inpVec, index, outVec, successFlag); + return result; +} + +/***********************************/ +/*** End of LooseMUX Gadgets ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* CompressionPacking Gadgets ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* + Compression Packing gadgets have two modes, which differ in the way the witness and constraints + are created. In PACK mode gerateWitness() will take the bits and create a packed element (or + number of elements) while generateConstraints() will not enforce that bits are indeed Boolean. + In UNPACK mode generateWitness() will take the packed repreentation and unpack it to bits while + generateConstraints will in addition enforce that unpacked bits are indeed Boolean. +*/ + +CompressionPacking_GadgetBase::~CompressionPacking_GadgetBase() {}; + +/* + Constraint breakdown: + + (1) packed = sum(unpacked[i] * 2^i) + (2) (UNPACK only) unpacked[i] is Boolean. +*/ + +R1P_CompressionPacking_Gadget::R1P_CompressionPacking_Gadget(ProtoboardPtr pb, + const VariableArray& unpacked, + const VariableArray& packed, + PackingMode packingMode) + : Gadget(pb), CompressionPacking_GadgetBase(pb), R1P_Gadget(pb), packingMode_(packingMode), + unpacked_(unpacked), packed_(packed) { + const int n = unpacked.size(); + GADGETLIB_ASSERT(n > 0, "Attempted to pack 0 bits in R1P.") + GADGETLIB_ASSERT(packed.size() == 1, + "Attempted to pack into more than 1 Variable in R1P_CompressionPacking_Gadget.") + // TODO add assertion that 'n' bits can fit in the field characteristic +} + +void R1P_CompressionPacking_Gadget::init() {} + +void R1P_CompressionPacking_Gadget::generateConstraints() { + const int n = unpacked_.size(); + LinearCombination packed; + FElem two_i(R1P_Elem(1)); // Will hold 2^i + for (int i = 0; i < n; ++i) { + packed += unpacked_[i]*two_i; + two_i += two_i; + if (packingMode_ == PackingMode::UNPACK) {enforceBooleanity(unpacked_[i]);} + } + addRank1Constraint(packed_[0], 1, packed, "packed[0] = sum(2^i * unpacked[i])"); +} + +void R1P_CompressionPacking_Gadget::generateWitness() { + const int n = unpacked_.size(); + if (packingMode_ == PackingMode::PACK) { + FElem packedVal = 0; + FElem two_i(R1P_Elem(1)); // will hold 2^i + for(int i = 0; i < n; ++i) { + GADGETLIB_ASSERT(val(unpacked_[i]).asLong() == 0 || val(unpacked_[i]).asLong() == 1, + GADGETLIB2_FMT("unpacked[%u] = %u. Expected a Boolean value.", i, + val(unpacked_[i]).asLong())); + packedVal += two_i * val(unpacked_[i]).asLong(); + two_i += two_i; + } + val(packed_[0]) = packedVal; + return; + } + // else (UNPACK) + GADGETLIB_ASSERT(packingMode_ == PackingMode::UNPACK, "Packing gadget created with unknown packing mode."); + for(int i = 0; i < n; ++i) { + val(unpacked_[i]) = val(packed_[0]).getBit(i, R1P); + } +} + +/*****************************************/ +/*** End of CompressionPacking Gadgets ***/ +/*****************************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* IntegerPacking Gadgets ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* + Arithmetic Packing gadgets have two modes, which differ in the way the witness and constraints + are created. In PACK mode gerateWitness() will take the bits and create a packed element (or + number of elements) while generateConstraints() will not enforce that bits are indeed Boolean. + In UNPACK mode generateWitness() will take the packed repreentation and unpack it to bits while + generateConstraints will in addition enforce that unpacked bits are indeed Boolean. +*/ + +IntegerPacking_GadgetBase::~IntegerPacking_GadgetBase() {}; + +/* + Constraint breakdown: + + (1) packed = sum(unpacked[i] * 2^i) + (2) (UNPACK only) unpacked[i] is Boolean. +*/ + +R1P_IntegerPacking_Gadget::R1P_IntegerPacking_Gadget(ProtoboardPtr pb, + const VariableArray& unpacked, + const VariableArray& packed, + PackingMode packingMode) + : Gadget(pb), IntegerPacking_GadgetBase(pb), R1P_Gadget(pb), packingMode_(packingMode), + unpacked_(unpacked), packed_(packed) { + const int n = unpacked.size(); + GADGETLIB_ASSERT(n > 0, "Attempted to pack 0 bits in R1P.") + GADGETLIB_ASSERT(packed.size() == 1, + "Attempted to pack into more than 1 Variable in R1P_IntegerPacking_Gadget.") +} + +void R1P_IntegerPacking_Gadget::init() { + compressionPackingGadget_ = CompressionPacking_Gadget::create(pb_, unpacked_, packed_, + packingMode_); +} + +void R1P_IntegerPacking_Gadget::generateConstraints() { + compressionPackingGadget_->generateConstraints(); +} + +void R1P_IntegerPacking_Gadget::generateWitness() { + compressionPackingGadget_->generateWitness(); +} + + +/*****************************************/ +/*** End of IntegerPacking Gadgets ***/ +/*****************************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* EqualsConst Gadgets ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +EqualsConst_GadgetBase::~EqualsConst_GadgetBase() {}; + +/* + Constraint breakdown: + + (1) (input - n) * result = 0 + (2) (input - n) * aux = 1 - result + + [ input == n ] (2)==> [result == 1] (aux can ake any value) + [ input != n ] (1)==> [result == 0] (aux == inverse(input - n)) +*/ + +R1P_EqualsConst_Gadget::R1P_EqualsConst_Gadget(ProtoboardPtr pb, + const FElem& n, + const LinearCombination &input, + const Variable &result) + : Gadget(pb), EqualsConst_GadgetBase(pb), R1P_Gadget(pb), n_(n), + aux_("aux (R1P_EqualsConst_Gadget)"), input_(input), result_(result) {} + +void R1P_EqualsConst_Gadget::init() {} + +void R1P_EqualsConst_Gadget::generateConstraints() { + addRank1Constraint(input_ - n_, result_, 0, "(input - n) * result = 0"); + addRank1Constraint(input_ - n_, aux_, 1 - result_, "(input - n) * aux = 1 - result"); +} + +void R1P_EqualsConst_Gadget::generateWitness() { + val(aux_) = val(input_) == n_ ? 0 : (val(input_) - n_).inverse(R1P) ; + val(result_) = val(input_) == n_ ? 1 : 0 ; +} + +/***********************************/ +/*** End of EqualsConst Gadgets ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* DualWord_Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +DualWord_Gadget::DualWord_Gadget(ProtoboardPtr pb, + const DualWord& var, + PackingMode packingMode) + : Gadget(pb), var_(var), packingMode_(packingMode), packingGadget_() {} + +void DualWord_Gadget::init() { + packingGadget_ = CompressionPacking_Gadget::create(pb_, var_.unpacked(), var_.multipacked(), + packingMode_); +} + +GadgetPtr DualWord_Gadget::create(ProtoboardPtr pb, + const DualWord& var, + PackingMode packingMode) { + GadgetPtr pGadget(new DualWord_Gadget(pb, var, packingMode)); + pGadget->init(); + return pGadget; +} + +void DualWord_Gadget::generateConstraints() { + packingGadget_->generateConstraints(); +} + +void DualWord_Gadget::generateWitness() { + packingGadget_->generateWitness(); +} + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* DualWordArray_Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +DualWordArray_Gadget::DualWordArray_Gadget(ProtoboardPtr pb, + const DualWordArray& vars, + PackingMode packingMode) + : Gadget(pb), vars_(vars), packingMode_(packingMode), packingGadgets_() {} + +void DualWordArray_Gadget::init() { + const UnpackedWordArray unpacked = vars_.unpacked(); + const MultiPackedWordArray packed = vars_.multipacked(); + for(size_t i = 0; i < vars_.size(); ++i) { + const auto curGadget = CompressionPacking_Gadget::create(pb_, unpacked[i], packed[i], + packingMode_); + packingGadgets_.push_back(curGadget); + } +} + +GadgetPtr DualWordArray_Gadget::create(ProtoboardPtr pb, + const DualWordArray& vars, + PackingMode packingMode) { + GadgetPtr pGadget(new DualWordArray_Gadget(pb, vars, packingMode)); + pGadget->init(); + return pGadget; +} + +void DualWordArray_Gadget::generateConstraints() { + for(auto& gadget : packingGadgets_) { + gadget->generateConstraints(); + } +} + +void DualWordArray_Gadget::generateWitness() { + for(auto& gadget : packingGadgets_) { + gadget->generateWitness(); + } +} + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* Toggle_Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* + Constraint breakdown: + + (1) result = (1 - toggle) * zeroValue + toggle * oneValue + (rank 1 format) ==> toggle * (oneValue - zeroValue) = result - zeroValue + +*/ + +Toggle_Gadget::Toggle_Gadget(ProtoboardPtr pb, + const FlagVariable& toggle, + const LinearCombination& zeroValue, + const LinearCombination& oneValue, + const Variable& result) + : Gadget(pb), toggle_(toggle), zeroValue_(zeroValue), oneValue_(oneValue), + result_(result) {} + +GadgetPtr Toggle_Gadget::create(ProtoboardPtr pb, + const FlagVariable& toggle, + const LinearCombination& zeroValue, + const LinearCombination& oneValue, + const Variable& result) { + GadgetPtr pGadget(new Toggle_Gadget(pb, toggle, zeroValue, oneValue, result)); + pGadget->init(); + return pGadget; +} + +void Toggle_Gadget::generateConstraints() { + pb_->addRank1Constraint(toggle_, oneValue_ - zeroValue_, result_ - zeroValue_, + "result = (1 - toggle) * zeroValue + toggle * oneValue"); +} + +void Toggle_Gadget::generateWitness() { + if (val(toggle_) == 0) { + val(result_) = val(zeroValue_); + } else if (val(toggle_) == 1) { + val(result_) = val(oneValue_); + } else { + GADGETLIB_FATAL("Toggle value must be Boolean."); + } +} + + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* ConditionalFlag_Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* + semantics: condition != 0 --> flag = 1 + condition == 0 --> flag = 0 + + Constraint breakdown: + (1) condition * not(flag) = 0 + (2) condition * auxConditionInverse = flag + + */ + +ConditionalFlag_Gadget::ConditionalFlag_Gadget(ProtoboardPtr pb, + const LinearCombination& condition, + const FlagVariable& flag) + : Gadget(pb), flag_(flag), condition_(condition), + auxConditionInverse_("ConditionalFlag_Gadget::auxConditionInverse_") {} + +GadgetPtr ConditionalFlag_Gadget::create(ProtoboardPtr pb, + const LinearCombination& condition, + const FlagVariable& flag) { + GadgetPtr pGadget(new ConditionalFlag_Gadget(pb, condition, flag)); + pGadget->init(); + return pGadget; +} + +void ConditionalFlag_Gadget::generateConstraints() { + pb_->addRank1Constraint(condition_, negate(flag_), 0, "condition * not(flag) = 0"); + pb_->addRank1Constraint(condition_, auxConditionInverse_, flag_, + "condition * auxConditionInverse = flag"); +} + +void ConditionalFlag_Gadget::generateWitness() { + if (val(condition_) == 0) { + val(flag_) = 0; + val(auxConditionInverse_) = 0; + } else { + val(flag_) = 1; + val(auxConditionInverse_) = val(condition_).inverse(fieldType()); + } +} + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* LogicImplication_Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* + semantics: condition == 1 --> flag = 1 + + Constraint breakdown: + (1) condition * (1 - flag) = 0 + + */ + +LogicImplication_Gadget::LogicImplication_Gadget(ProtoboardPtr pb, + const LinearCombination& condition, + const FlagVariable& flag) + : Gadget(pb), flag_(flag), condition_(condition) {} + +GadgetPtr LogicImplication_Gadget::create(ProtoboardPtr pb, + const LinearCombination& condition, + const FlagVariable& flag) { + GadgetPtr pGadget(new LogicImplication_Gadget(pb, condition, flag)); + pGadget->init(); + return pGadget; +} + +void LogicImplication_Gadget::generateConstraints() { + pb_->addRank1Constraint(condition_, negate(flag_), 0, "condition * not(flag) = 0"); +} + +void LogicImplication_Gadget::generateWitness() { + if (val(condition_) == 1) { + val(flag_) = 1; + } +} + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* Compare_Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +Comparison_GadgetBase::~Comparison_GadgetBase() {} + +R1P_Comparison_Gadget::R1P_Comparison_Gadget(ProtoboardPtr pb, + const size_t& wordBitSize, + const PackedWord& lhs, + const PackedWord& rhs, + const FlagVariable& less, + const FlagVariable& lessOrEqual) + : Gadget(pb), Comparison_GadgetBase(pb), R1P_Gadget(pb), wordBitSize_(wordBitSize), + lhs_(lhs), rhs_(rhs), less_(less), lessOrEqual_(lessOrEqual), + alpha_u_(wordBitSize, "alpha"), notAllZeroes_("notAllZeroes") {} + +void R1P_Comparison_Gadget::init() { + allZeroesTest_ = OR_Gadget::create(pb_, alpha_u_, notAllZeroes_); + alpha_u_.emplace_back(lessOrEqual_); + alphaDualVariablePacker_ = CompressionPacking_Gadget::create(pb_, alpha_u_,VariableArray(1,alpha_p_), PackingMode::UNPACK); +} +/* + Constraint breakdown: + + for succinctness we shall define: + (1) wordBitSize == n + (2) lhs == A + (3) rhs == B + + packed(alpha) = 2^n + B - A + not_all_zeros = OR(alpha.unpacked) + + if B - A > 0, then: alpha > 2^n, + so alpha[n] = 1 and notAllZeroes = 1 + if B - A = 0, then: alpha = 2^n, + so alpha[n] = 1 and notAllZeroes = 0 + if B - A < 0, then: 0 <= alpha <= 2^n-1 + so alpha[n] = 0 + + therefore: + (1) alpha[n] = lessOrEqual + (2) alpha[n] * notAllZeroes = less + + +*/ +void R1P_Comparison_Gadget::generateConstraints() { + enforceBooleanity(notAllZeroes_); + const FElem two_n = long(POW2(wordBitSize_)); + addRank1Constraint(1, alpha_p_, two_n + rhs_ - lhs_, + "packed(alpha) = 2^n + B - A"); + alphaDualVariablePacker_->generateConstraints(); + allZeroesTest_->generateConstraints(); + addRank1Constraint(1, alpha_u_[wordBitSize_], lessOrEqual_, "alpha[n] = lessOrEqual"); + addRank1Constraint(alpha_u_[wordBitSize_], notAllZeroes_, less_, + "alpha[n] * notAllZeroes = less"); +} + +void R1P_Comparison_Gadget::generateWitness() { + const FElem two_n = long(POW2(wordBitSize_)); + val(alpha_p_) = two_n + val(rhs_) - val(lhs_); + alphaDualVariablePacker_->generateWitness(); + allZeroesTest_->generateWitness(); + val(lessOrEqual_) = val(alpha_u_[wordBitSize_]); + val(less_) = val(lessOrEqual_) * val(notAllZeroes_); +} + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +} // namespace gadgetlib2 diff --git a/privacy/zsl/zsl/gadgetlib2/gadget.d b/privacy/zsl/zsl/gadgetlib2/gadget.d new file mode 100644 index 0000000..de334a6 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/gadget.d @@ -0,0 +1,21 @@ +src/gadgetlib2/gadget.o: src/gadgetlib2/gadget.cpp \ + src/gadgetlib2/gadget.hpp src/gadgetlib2/variable.hpp \ + src/gadgetlib2/pp.hpp src/common/default_types/ec_pp.hpp \ + src/algebra/curves/bn128/bn128_pp.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/bn128/bn128_init.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc depinst/include/bn.h \ + depinst/include/zm2.h depinst/include/zm.h \ + src/algebra/curves/bn128/bn128_g1.hpp src/algebra/curves/curve_utils.hpp \ + src/algebra/curves/curve_utils.tcc src/algebra/curves/bn128/bn128_g2.hpp \ + src/algebra/curves/bn128/bn128_gt.hpp \ + src/algebra/curves/bn128/bn128_pairing.hpp \ + src/gadgetlib2/infrastructure.hpp src/gadgetlib2/variable_operators.hpp \ + src/gadgetlib2/protoboard.hpp src/gadgetlib2/constraint.hpp \ + src/gadgetlib2/gadgetMacros.hpp diff --git a/privacy/zsl/zsl/gadgetlib2/gadget.hpp b/privacy/zsl/zsl/gadgetlib2/gadget.hpp new file mode 100644 index 0000000..dbd23e9 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/gadget.hpp @@ -0,0 +1,747 @@ +/** @file + ***************************************************************************** + Interfaces and basic gadgets for R1P (Rank 1 prime characteristic) + constraint systems. + + These interfaces have been designed to allow later adding other fields or constraint + structures while allowing high level design to stay put. + + A gadget represents (and generates) the constraints, constraint "wiring", and + witness for a logical task. This is best explained using the physical design of a printed + circuit. The Protoboard is the board on which we will "solder" our circuit. The wires + (implemented by Variables) can hold any element of the underlying field. Each constraint + enforces a relation between wires. These can be thought of as gates. + + The delegation of tasks is as follows: + + - Constructor - Allocates all Variables to a Protoboard. Creates all sub-gadgets + that will be needed and wires their inputs and outputs. + generateConstraints - Generates the constraints which define the + necessary relations between the previously allocated Variables. + + - generateWitness - Generates an assignment for all non-input Variables which is + consistent with the assignment of the input Variables and satisfies + all of the constraints. In essence, this computes the logical + function of the Gadget. + + - create - A static factory method used for construction of the Gadget. This is + used in order to create a Gadget without explicit knowledge of the + underlying algebraic field. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_GADGET_HPP_ +#define LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_GADGET_HPP_ + +#include +#include "variable.hpp" +#include "protoboard.hpp" +#include "gadgetMacros.hpp" + +namespace gadgetlib2 { + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/** + Gadget class, representing the constraints and witness generation for a logical task. + + Gadget hierarchy: + (Here and elsewhere: R1P = Rank 1 constraints over a prime-characteristic field.) + Gadgets have a somewhat cumbursome class heirarchy, for the sake of clean gadget construction. + (1) A field agnostic, concrete (as opposed to interface) gadget will derive from Gadget. For + instance NAND needs only AND and NOT and does not care about the field, thus it derives from + Gadget. + (2) Field specific interface class R1P_Gadget derives from Gadget using virtual + inheritance, in order to avoid the Dreaded Diamond problem (see + http://stackoverflow.com/a/21607/1756254 for more info) + (3) Functional interface classes such as LooseMUX_GadgetBase virtually derive from Gadget and + define special gadget functionality. For gadgets with no special interfaces we use the macro + CREATE_GADGET_BASE_CLASS() for the sake of code consistency (these gadgets can work the same + without this base class). This is an interface only and the implementation of AND_Gadget is + field specific. + (4) These field specific gadgets will have a factory class with static method create, such as + AND_Gadget::create(...) in order to agnostically create this gadget for use by a field + agnostic gadget. + (5) Concrete field dependant gadgets derive via multiple inheritance from two interfaces. + e.g. R1P_AND_Gadget derives from both AND_Gadget and R1P_Gadget. This was done to allow usage + of AND_Gadget's field agnostic create() method and R1P_Gadget's field specific val() method. +*/ +class Gadget { +private: + DISALLOW_COPY_AND_ASSIGN(Gadget); +protected: + ProtoboardPtr pb_; +public: + Gadget(ProtoboardPtr pb); + virtual void init() = 0; + /* generate constraints must have this interface, however generateWitness for some gadgets + (like CTime) will take auxiliary information (like memory contents). We do not want to force + the interface for generateWitness but do want to make sure it is never invoked from base + class. + */ + virtual void generateConstraints() = 0; + virtual void generateWitness(); // Not abstract as this method may have different signatures. + void addUnaryConstraint(const LinearCombination& a, const ::std::string& name); + void addRank1Constraint(const LinearCombination& a, + const LinearCombination& b, + const LinearCombination& c, + const ::std::string& name); + void enforceBooleanity(const Variable& var) {pb_->enforceBooleanity(var);} + FElem& val(const Variable& var) {return pb_->val(var);} + FElem val(const LinearCombination& lc) {return pb_->val(lc);} + FieldType fieldType() const {return pb_->fieldType_;} + bool flagIsSet(const FlagVariable& flag) const {return pb_->flagIsSet(flag);} +}; + +typedef ::std::shared_ptr GadgetPtr; // Not a unique_ptr because sometimes we need to cast + // these pointers for specific gadget operations. +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* Gadget Interfaces ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* + We use multiple inheritance in order to use much needed syntactic sugar. We want val() to be + able to return different types depending on the field so we need to differentiate the interfaces + between R1P and other fields. We also want the interfaces of specific logical gadgets + (for instance AND_Gadget which has n inputs and 1 output) in order to construct higher level + gadgets without specific knowledge of the underlying field. Both interfaces (for instance + R1P_gadget and AND_Gadget) inherit from Gadget using virtual inheritance (this means only one + instance of Gadget will be created. For a more thorough discussion on virtual inheritance see + http://www.phpcompiler.org/articles/virtualinheritance.html + */ + +class R1P_Gadget : virtual public Gadget { +public: + R1P_Gadget(ProtoboardPtr pb) : Gadget(pb) {} + virtual ~R1P_Gadget() = 0; + + virtual void addRank1Constraint(const LinearCombination& a, + const LinearCombination& b, + const LinearCombination& c, + const ::std::string& name); +private: + virtual void init() = 0; // private in order to force programmer to invoke from a Gadget* only + DISALLOW_COPY_AND_ASSIGN(R1P_Gadget); +}; // class R1P_Gadget + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* AND_Gadget classes ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +CREATE_GADGET_BASE_CLASS(AND_GadgetBase); + +/// Specific case for and AND with two inputs. Field agnostic +class BinaryAND_Gadget : public AND_GadgetBase { +private: + BinaryAND_Gadget(ProtoboardPtr pb, + const LinearCombination& input1, + const LinearCombination& input2, + const Variable& result); + void init(); + void generateConstraints(); + void generateWitness(); +public: + friend class AND_Gadget; +private: + //external variables + const LinearCombination input1_; + const LinearCombination input2_; + const Variable result_; + + DISALLOW_COPY_AND_ASSIGN(BinaryAND_Gadget); +}; // class BinaryAND_Gadget + +class R1P_AND_Gadget : public AND_GadgetBase, public R1P_Gadget { +private: + R1P_AND_Gadget(ProtoboardPtr pb, const VariableArray& input, const Variable& result); + virtual void init(); +public: + void generateConstraints(); + void generateWitness(); + friend class AND_Gadget; +private: + //external variables + const VariableArray input_; + const Variable result_; + //internal variables + LinearCombination sum_; + Variable sumInverse_; + + DISALLOW_COPY_AND_ASSIGN(R1P_AND_Gadget); +}; + + +class AND_Gadget { +public: + static GadgetPtr create(ProtoboardPtr pb, const VariableArray& input, const Variable& result); + static GadgetPtr create(ProtoboardPtr pb, + const LinearCombination& input1, + const LinearCombination& input2, + const Variable& result); +private: + DISALLOW_CONSTRUCTION(AND_Gadget); + DISALLOW_COPY_AND_ASSIGN(AND_Gadget); +}; // class GadgetType + + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* OR_Gadget classes ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +CREATE_GADGET_BASE_CLASS(OR_GadgetBase); + +/// Specific case for and OR with two inputs. Field agnostic +class BinaryOR_Gadget : public OR_GadgetBase { +private: + BinaryOR_Gadget(ProtoboardPtr pb, + const LinearCombination& input1, + const LinearCombination& input2, + const Variable& result); + void init(); + void generateConstraints(); + void generateWitness(); +public: + friend class OR_Gadget; +private: + //external variables + const LinearCombination input1_; + const LinearCombination input2_; + const Variable result_; + + DISALLOW_COPY_AND_ASSIGN(BinaryOR_Gadget); +}; // class BinaryOR_Gadget + +class R1P_OR_Gadget : public OR_GadgetBase, public R1P_Gadget { +private: + LinearCombination sum_; + Variable sumInverse_; + R1P_OR_Gadget(ProtoboardPtr pb, const VariableArray& input, const Variable& result); + virtual void init(); +public: + const VariableArray input_; + const Variable result_; + void generateConstraints(); + void generateWitness(); + friend class OR_Gadget; +private: + DISALLOW_COPY_AND_ASSIGN(R1P_OR_Gadget); +}; + +class OR_Gadget { +public: + static GadgetPtr create(ProtoboardPtr pb, const VariableArray& input, const Variable& result); + static GadgetPtr create(ProtoboardPtr pb, + const LinearCombination& input1, + const LinearCombination& input2, + const Variable& result); +private: + DISALLOW_CONSTRUCTION(OR_Gadget); + DISALLOW_COPY_AND_ASSIGN(OR_Gadget); +}; // class GadgetType + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* InnerProduct_Gadget classes ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +CREATE_GADGET_BASE_CLASS(InnerProduct_GadgetBase); + +class R1P_InnerProduct_Gadget : public InnerProduct_GadgetBase, public R1P_Gadget { +private: + VariableArray partialSums_; + R1P_InnerProduct_Gadget(ProtoboardPtr pb, + const VariableArray& A, + const VariableArray& B, + const Variable& result); + virtual void init(); +public: + const VariableArray A_, B_; + const Variable result_; + void generateConstraints(); + void generateWitness(); + friend class InnerProduct_Gadget; +private: + DISALLOW_COPY_AND_ASSIGN(R1P_InnerProduct_Gadget); +}; + +CREATE_GADGET_FACTORY_CLASS_3(InnerProduct_Gadget, VariableArray, A, + VariableArray, B, + Variable, result); + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* LooseMUX_Gadget classes ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* + Loose Multiplexer (MUX): + Multiplexes one Variable + index not in bounds -> success_flag = 0 + index in bounds && success_flag = 1 -> result is correct + index is in bounds, we can also set success_flag to 0 -> result will be forced to 0 +*/ + +class LooseMUX_GadgetBase : virtual public Gadget { +protected: + LooseMUX_GadgetBase(ProtoboardPtr pb) : Gadget(pb) {} +public: + virtual ~LooseMUX_GadgetBase() = 0; + virtual VariableArray indicatorVariables() const = 0; +private: + virtual void init() = 0; + DISALLOW_COPY_AND_ASSIGN(LooseMUX_GadgetBase); +}; // class LooseMUX_GadgetBase + + +class R1P_LooseMUX_Gadget : public LooseMUX_GadgetBase, public R1P_Gadget { +private: + VariableArray indicators_; + ::std::vector computeResult_; // Inner product gadgets + R1P_LooseMUX_Gadget(ProtoboardPtr pb, + const MultiPackedWordArray& inputs, + const Variable& index, + const VariableArray& output, + const Variable& successFlag); + virtual void init(); +public: + MultiPackedWordArray inputs_; + const Variable index_; + const VariableArray output_; + const Variable successFlag_; + void generateConstraints(); + void generateWitness(); + virtual VariableArray indicatorVariables() const; + friend class LooseMUX_Gadget; +private: + DISALLOW_COPY_AND_ASSIGN(R1P_LooseMUX_Gadget); +}; + +class LooseMUX_Gadget { +public: + static GadgetPtr create(ProtoboardPtr pb, + const MultiPackedWordArray& inputs, + const Variable& index, + const VariableArray& output, + const Variable& successFlag); + static GadgetPtr create(ProtoboardPtr pb, + const VariableArray& inputs, + const Variable& index, + const Variable& output, + const Variable& successFlag); +private: + DISALLOW_CONSTRUCTION(LooseMUX_Gadget); + DISALLOW_COPY_AND_ASSIGN(LooseMUX_Gadget); +}; // class GadgetType + + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* CompressionPacking_Gadget classes ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +// TODO change class name to bitpacking +enum class PackingMode : bool {PACK, UNPACK}; + +CREATE_GADGET_BASE_CLASS(CompressionPacking_GadgetBase); + +class R1P_CompressionPacking_Gadget : public CompressionPacking_GadgetBase, public R1P_Gadget { +private: + PackingMode packingMode_; + R1P_CompressionPacking_Gadget(ProtoboardPtr pb, + const VariableArray& unpacked, + const VariableArray& packed, + PackingMode packingMode); + virtual void init(); +public: + const VariableArray unpacked_; + const VariableArray packed_; + void generateConstraints(); + void generateWitness(); + friend class CompressionPacking_Gadget; +private: + DISALLOW_COPY_AND_ASSIGN(R1P_CompressionPacking_Gadget); +}; + +CREATE_GADGET_FACTORY_CLASS_3(CompressionPacking_Gadget, VariableArray, unpacked, VariableArray, + packed, PackingMode, packingMode); + + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* IntegerPacking_Gadget classes ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +CREATE_GADGET_BASE_CLASS(IntegerPacking_GadgetBase); + +// In R1P compression and arithmetic packing are implemented the same, hence this gadget simply +// instantiates an R1P_CompressionPacking_Gadget +class R1P_IntegerPacking_Gadget : public IntegerPacking_GadgetBase, public R1P_Gadget { +private: + PackingMode packingMode_; + GadgetPtr compressionPackingGadget_; + R1P_IntegerPacking_Gadget(ProtoboardPtr pb, + const VariableArray& unpacked, + const VariableArray& packed, + PackingMode packingMode); + virtual void init(); +public: + const VariableArray unpacked_; + const VariableArray packed_; + void generateConstraints(); + void generateWitness(); + friend class IntegerPacking_Gadget; +private: + DISALLOW_COPY_AND_ASSIGN(R1P_IntegerPacking_Gadget); +}; + +CREATE_GADGET_FACTORY_CLASS_3(IntegerPacking_Gadget, VariableArray, unpacked, VariableArray, + packed, PackingMode, packingMode); + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* EqualsConst_Gadget classes ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* + Gadgets recieve a constant field element n, and an input. + input == n ==> result = 1 + input != n ==> result = 0 +*/ + +// TODO change to take LinearCombination as input and change AND/OR to use this +CREATE_GADGET_BASE_CLASS(EqualsConst_GadgetBase); + +class R1P_EqualsConst_Gadget : public EqualsConst_GadgetBase, public R1P_Gadget { +private: + const FElem n_; + Variable aux_; + R1P_EqualsConst_Gadget(ProtoboardPtr pb, + const FElem& n, + const LinearCombination& input, + const Variable& result); + virtual void init(); +public: + const LinearCombination input_; + const Variable result_; + void generateConstraints(); + void generateWitness(); + friend class EqualsConst_Gadget; +private: + DISALLOW_COPY_AND_ASSIGN(R1P_EqualsConst_Gadget); +}; + +CREATE_GADGET_FACTORY_CLASS_3(EqualsConst_Gadget, FElem, n, LinearCombination, input, + Variable, result); + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* DualWord_Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +//TODO add test + +class DualWord_Gadget : public Gadget { + +private: + const DualWord var_; + const PackingMode packingMode_; + + GadgetPtr packingGadget_; + + DualWord_Gadget(ProtoboardPtr pb, const DualWord& var, PackingMode packingMode); + virtual void init(); + DISALLOW_COPY_AND_ASSIGN(DualWord_Gadget); +public: + static GadgetPtr create(ProtoboardPtr pb, const DualWord& var, PackingMode packingMode); + void generateConstraints(); + void generateWitness(); +}; + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* DualWordArray_Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +//TODO add test + +class DualWordArray_Gadget : public Gadget { + +private: + const DualWordArray vars_; + const PackingMode packingMode_; + + ::std::vector packingGadgets_; + + DualWordArray_Gadget(ProtoboardPtr pb, + const DualWordArray& vars, + PackingMode packingMode); + virtual void init(); + DISALLOW_COPY_AND_ASSIGN(DualWordArray_Gadget); +public: + static GadgetPtr create(ProtoboardPtr pb, + const DualWordArray& vars, + PackingMode packingMode); + void generateConstraints(); + void generateWitness(); +}; + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* Toggle_Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +//TODO add test + +/// A gadget for the following semantics: +/// If toggle is 0, zeroValue --> result +/// If toggle is 1, oneValue --> result +/// Uses 1 constraint + +class Toggle_Gadget : public Gadget { +private: + FlagVariable toggle_; + LinearCombination zeroValue_; + LinearCombination oneValue_; + Variable result_; + + Toggle_Gadget(ProtoboardPtr pb, + const FlagVariable& toggle, + const LinearCombination& zeroValue, + const LinearCombination& oneValue, + const Variable& result); + + virtual void init() {} + DISALLOW_COPY_AND_ASSIGN(Toggle_Gadget); +public: + static GadgetPtr create(ProtoboardPtr pb, + const FlagVariable& toggle, + const LinearCombination& zeroValue, + const LinearCombination& oneValue, + const Variable& result); + + void generateConstraints(); + void generateWitness(); +}; + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* ConditionalFlag_Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/// A gadget for the following semantics: +/// condition != 0 --> flag = 1 +/// condition == 0 --> flag = 0 +/// Uses 2 constraints + +class ConditionalFlag_Gadget : public Gadget { +private: + FlagVariable flag_; + LinearCombination condition_; + Variable auxConditionInverse_; + + ConditionalFlag_Gadget(ProtoboardPtr pb, + const LinearCombination& condition, + const FlagVariable& flag); + + virtual void init() {} + DISALLOW_COPY_AND_ASSIGN(ConditionalFlag_Gadget); +public: + static GadgetPtr create(ProtoboardPtr pb, + const LinearCombination& condition, + const FlagVariable& flag); + + void generateConstraints(); + void generateWitness(); +}; + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* LogicImplication_Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/// A gadget for the following semantics: +/// condition == 1 --> flag = 1 +/// Uses 1 constraint + +class LogicImplication_Gadget : public Gadget { +private: + FlagVariable flag_; + LinearCombination condition_; + + LogicImplication_Gadget(ProtoboardPtr pb, + const LinearCombination& condition, + const FlagVariable& flag); + + virtual void init() {} + DISALLOW_COPY_AND_ASSIGN(LogicImplication_Gadget); +public: + static GadgetPtr create(ProtoboardPtr pb, + const LinearCombination& condition, + const FlagVariable& flag); + + void generateConstraints(); + void generateWitness(); +}; + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* Compare_Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +// TODO create unit test +CREATE_GADGET_BASE_CLASS(Comparison_GadgetBase); + +class R1P_Comparison_Gadget : public Comparison_GadgetBase, public R1P_Gadget { +private: + const size_t wordBitSize_; + const PackedWord lhs_; + const PackedWord rhs_; + const FlagVariable less_; + const FlagVariable lessOrEqual_; + const PackedWord alpha_p_; + UnpackedWord alpha_u_; + const FlagVariable notAllZeroes_; + GadgetPtr allZeroesTest_; + GadgetPtr alphaDualVariablePacker_; + + R1P_Comparison_Gadget(ProtoboardPtr pb, + const size_t& wordBitSize, + const PackedWord& lhs, + const PackedWord& rhs, + const FlagVariable& less, + const FlagVariable& lessOrEqual); + virtual void init(); +public: + + static GadgetPtr create(ProtoboardPtr pb, + const size_t& wordBitSize, + const PackedWord& lhs, + const PackedWord& rhs, + const FlagVariable& less, + const FlagVariable& lessOrEqual); + + void generateConstraints(); + void generateWitness(); + friend class Comparison_Gadget; +private: + DISALLOW_COPY_AND_ASSIGN(R1P_Comparison_Gadget); +}; + +CREATE_GADGET_FACTORY_CLASS_5(Comparison_Gadget, // TODO uncomment this + size_t, wordBitSize, + PackedWord, lhs, + PackedWord, rhs, + FlagVariable, less, + FlagVariable, lessOrEqual); + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +} // namespace gadgetlib2 + +#endif // LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_GADGET_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib2/gadgetMacros.hpp b/privacy/zsl/zsl/gadgetlib2/gadgetMacros.hpp new file mode 100644 index 0000000..eed8f99 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/gadgetMacros.hpp @@ -0,0 +1,284 @@ +/** @file + ***************************************************************************** + Macros for quick construction of interface and factory classes for non field + agnostic gadgets. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_GADGETMACROS_HPP_ +#define LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_GADGETMACROS_HPP_ + +// The macro below counts the number of arguments sent with __VA_ARGS__ +// it has not been tested yet. Due to a current MSVC bug it is not in use yet. + +///* The PP_NARG macro returns the number of arguments that have been +// * passed to it. +// */ + +/* +//#define PP_NARG(...) \ +// PP_NARG_(__VA_ARGS__,PP_RSEQ_N()) +//#define PP_NARG_(...) \ +// PP_ARG_N(__VA_ARGS__) +//#define PP_ARG_N( \ +// _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ +// _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ +// _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ +// _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \ +// _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \ +// _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \ +// _61,_62,_63,N,...) N +//#define PP_RSEQ_N() \ +// 63,62,61,60, \ +// 59,58,57,56,55,54,53,52,51,50, \ +// 49,48,47,46,45,44,43,42,41,40, \ +// 39,38,37,36,35,34,33,32,31,30, \ +// 29,28,27,26,25,24,23,22,21,20, \ +// 19,18,17,16,15,14,13,12,11,10, \ +// 9,8,7,6,5,4,3,2,1,0 +*/ + +/** + Macro which creates Base classes for function specific gadgets. For instance + CREATE_GADGET_BASE_CLASS(AND_GadgetBase) will create a base class which should be inherited by + R1P_AND_Gadget and ANOTHER_FIELD_AND_Gadget. The Factory class which makes a field agnostic + gadget will be created by the CREATE_GADGET_FACTORY_CLASS(AND_Gadget, ...) macro +*/ +#define CREATE_GADGET_BASE_CLASS(GadgetBase) \ +class GadgetBase : virtual public Gadget { \ +protected: \ + GadgetBase(ProtoboardPtr pb) : Gadget(pb) {} \ +public: \ + virtual ~GadgetBase() = 0; \ +private: \ + virtual void init() = 0; \ + DISALLOW_COPY_AND_ASSIGN(GadgetBase); \ +}; // class GadgetBase + + + +/** + Macro for creating gadget factory classes. For instance + CREATE_GADGET_FACTORY_CLASS(AND_Gadget, 2, VariableArray, input, Variable, result); creates a + class AND_Gadget with the method: + GadgetPtr AND_Gadget::create(ProtoboardPtr pb, + const VariableArray& input, + const Variable& result) + which will instantiate a field specific gadget depending on the Protoboard type. + This macro implements the factory design pattern. +*/ +#define ADD_ELLIPSES_1(Type1, name1) \ + const Type1 & name1 + +#define ADD_ELLIPSES_2(Type1, name1, Type2, name2) \ + const Type1 & name1, const Type2 & name2 + +#define ADD_ELLIPSES_3(Type1, name1, Type2, name2, Type3, name3) \ + const Type1 & name1, const Type2 & name2, const Type3 & name3 + +#define ADD_ELLIPSES_4(Type1, name1, Type2, name2, Type3, name3, Type4, name4) \ + const Type1 & name1, const Type2 & name2, const Type3 & name3, const Type4 & name4 + +#define ADD_ELLIPSES_5(Type1, name1, Type2, name2, Type3, name3, Type4, name4, Type5, name5) \ + const Type1 & name1, const Type2 & name2, const Type3 & name3, const Type4 & name4, \ + const Type5 & name5 + +#define ADD_ELLIPSES_7(Type1, name1, Type2, name2, Type3, name3, Type4, name4, Type5, name5, \ + Type6, name6, Type7, name7, Type8, name8, Type9, name9) \ + const Type1 & name1, const Type2 & name2, const Type3 & name3, const Type4 & name4, \ + const Type5 & name5, const Type6 & name6, const Type7 & name7 + +#define ADD_ELLIPSES_8(Type1, name1, Type2, name2, Type3, name3, Type4, name4, Type5, name5, \ + Type6, name6, Type7, name7, Type8, name8) \ + const Type1 & name1, const Type2 & name2, const Type3 & name3, const Type4 & name4, \ + const Type5 & name5, const Type6 & name6, const Type7 & name7, const Type8 & name8 + +#define ADD_ELLIPSES_9(Type1, name1, Type2, name2, Type3, name3, Type4, name4, Type5, name5, \ + Type6, name6, Type7, name7, Type8, name8, Type9, name9) \ + const Type1 & name1, const Type2 & name2, const Type3 & name3, const Type4 & name4, \ + const Type5 & name5, const Type6 & name6, const Type7 & name7, const Type8 & name8, \ + const Type9 & name9 + +/* + This was supposed to be a variadic macro CREATE_GADGET_FACTORY_CLASS(...) which invokes the + correct number of arguments. Due to an MSVC bug and lack of time it will currently be copied + with different names. + Hopefully some day I will have time to find a workaround / use Boost preprocessor instead. + The MSVC bug (feature...) is that __VA_ARGS__ passes to sub macros as 1 argument, so defining + the following: + #define CREATE_GADGET_FACTORY_CLASS(__VA_ARGS__) \ + CREATE_GADGET_FACTORY_CLASS_ ## PP_NARG(__VA_ARGS__)(__VA_ARGS__) + will always create CREATE_GADGET_FACTORY_CLASS_1(__VA_ARGS__) + Moreover, this macro considers __VA_ARGS__ to be only 1 argument! +*/ +#define CREATE_GADGET_FACTORY_CLASS_1(GadgetType, Type1, name1) \ +class GadgetType { \ +public: \ + static GadgetPtr create(ProtoboardPtr pb, ADD_ELLIPSES_1(Type1, name1)) { \ + GadgetPtr pGadget; \ + if (pb->fieldType_ == R1P) { \ + pGadget.reset(new R1P_ ## GadgetType(pb, name1)); \ + } else { \ + GADGETLIB_FATAL("Attempted to create gadget of undefined Protoboard type."); \ + } \ + pGadget->init(); \ + return pGadget; \ + } \ +private: \ + DISALLOW_CONSTRUCTION(GadgetType); \ + DISALLOW_COPY_AND_ASSIGN(GadgetType); \ +}; // class GadgetType + +#define CREATE_GADGET_FACTORY_CLASS_2(GadgetType, Type1, name1, Type2, name2) \ +class GadgetType { \ +public: \ + static GadgetPtr create(ProtoboardPtr pb, \ + ADD_ELLIPSES_2(Type1, name1, Type2, name2)) { \ + GadgetPtr pGadget; \ + if (pb->fieldType_ == R1P) { \ + pGadget.reset(new R1P_ ## GadgetType(pb, name1, name2)); \ + } else { \ + GADGETLIB_FATAL("Attempted to create gadget of undefined Protoboard type."); \ + } \ + pGadget->init(); \ + return pGadget; \ + } \ +private: \ + DISALLOW_CONSTRUCTION(GadgetType); \ + DISALLOW_COPY_AND_ASSIGN(GadgetType); \ +}; // class GadgetType + +#define CREATE_GADGET_FACTORY_CLASS_3(GadgetType, Type1, name1, Type2, name2, Type3, name3) \ +class GadgetType { \ +public: \ + static GadgetPtr create(ProtoboardPtr pb, \ + ADD_ELLIPSES_3(Type1, name1, Type2, name2, Type3, name3)) { \ + GadgetPtr pGadget; \ + if (pb->fieldType_ == R1P) { \ + pGadget.reset(new R1P_ ## GadgetType(pb, name1, name2, name3)); \ + } else { \ + GADGETLIB_FATAL("Attempted to create gadget of undefined Protoboard type."); \ + } \ + pGadget->init(); \ + return pGadget; \ + } \ +private: \ + DISALLOW_CONSTRUCTION(GadgetType); \ + DISALLOW_COPY_AND_ASSIGN(GadgetType); \ +}; // class GadgetType + +#define CREATE_GADGET_FACTORY_CLASS_4(GadgetType, Type1, name1, Type2, name2, Type3, name3, \ + Type4, name4) \ +class GadgetType { \ +public: \ + static GadgetPtr create(ProtoboardPtr pb, \ + ADD_ELLIPSES_4(Type1, name1, Type2, name2, Type3, name3, Type4, name4)) { \ + GadgetPtr pGadget; \ + if (pb->fieldType_ == R1P) { \ + pGadget.reset(new R1P_ ## GadgetType(pb, name1, name2, name3, name4)); \ + } else { \ + GADGETLIB_FATAL("Attempted to create gadget of undefined Protoboard type."); \ + } \ + pGadget->init(); \ + return pGadget; \ + } \ +private: \ + DISALLOW_CONSTRUCTION(GadgetType); \ + DISALLOW_COPY_AND_ASSIGN(GadgetType); \ +}; // class GadgetType + +#define CREATE_GADGET_FACTORY_CLASS_5(GadgetType, Type1, name1, Type2, name2, Type3, name3, \ + Type4, name4, Type5, name5) \ +class GadgetType { \ +public: \ + static GadgetPtr create(ProtoboardPtr pb, \ + ADD_ELLIPSES_5(Type1, name1, Type2, name2, Type3, name3, Type4, name4, \ + Type5, name5)) { \ + GadgetPtr pGadget; \ + if (pb->fieldType_ == R1P) { \ + pGadget.reset(new R1P_ ## GadgetType(pb, name1, name2, name3, name4, name5)); \ + } else { \ + GADGETLIB_FATAL("Attempted to create gadget of undefined Protoboard type."); \ + } \ + pGadget->init(); \ + return pGadget; \ + } \ +private: \ + DISALLOW_CONSTRUCTION(GadgetType); \ + DISALLOW_COPY_AND_ASSIGN(GadgetType); \ +}; // class GadgetType + +#define CREATE_GADGET_FACTORY_CLASS_7(GadgetType, Type1, name1, Type2, name2, Type3, name3, \ + Type4, name4, Type5, name5, Type6, name6, Type7, name7) \ +class GadgetType { \ +public: \ + static GadgetPtr create(ProtoboardPtr pb, \ + ADD_ELLIPSES_7(Type1, name1, Type2, name2, Type3, name3, Type4, name4, \ + Type5, name5, Type6, name6, Type7, name7)) { \ + GadgetPtr pGadget; \ + if (pb->fieldType_ == R1P) { \ + pGadget.reset(new R1P_ ## GadgetType(pb, name1, name2, name3, name4, name5, name6, \ + name7)); \ + } else { \ + GADGETLIB_FATAL("Attempted to create gadget of undefined Protoboard type."); \ + } \ + pGadget->init(); \ + return pGadget; \ + } \ +private: \ + DISALLOW_CONSTRUCTION(GadgetType); \ + DISALLOW_COPY_AND_ASSIGN(GadgetType); \ +}; // class GadgetType + + +#define CREATE_GADGET_FACTORY_CLASS_8(GadgetType, Type1, name1, Type2, name2, Type3, name3, \ + Type4, name4, Type5, name5, Type6, name6, Type7, name7, \ + Type8, name8) \ +class GadgetType { \ +public: \ + static GadgetPtr create(ProtoboardPtr pb, \ + ADD_ELLIPSES_8(Type1, name1, Type2, name2, Type3, name3, Type4, name4, \ + Type5, name5, Type6, name6, Type7, name7, Type8, name8)) { \ + GadgetPtr pGadget; \ + if (pb->fieldType_ == R1P) { \ + pGadget.reset(new R1P_ ## GadgetType(pb, name1, name2, name3, name4, name5, name6, \ + name7, name8)); \ + } else { \ + GADGETLIB_FATAL("Attempted to create gadget of undefined Protoboard type."); \ + } \ + pGadget->init(); \ + return pGadget; \ + } \ +private: \ + DISALLOW_CONSTRUCTION(GadgetType); \ + DISALLOW_COPY_AND_ASSIGN(GadgetType); \ +}; // class GadgetType + +#define CREATE_GADGET_FACTORY_CLASS_9(GadgetType, Type1, name1, Type2, name2, Type3, name3, \ + Type4, name4, Type5, name5, Type6, name6, Type7, name7, \ + Type8, name8, Type9, name9) \ +class GadgetType { \ +public: \ + static GadgetPtr create(ProtoboardPtr pb, \ + ADD_ELLIPSES_9(Type1, name1, Type2, name2, Type3, name3, Type4, name4, \ + Type5, name5, Type6, name6, Type7, name7, Type8, name8, \ + Type9, name9)) { \ + GadgetPtr pGadget; \ + if (pb->fieldType_ == R1P) { \ + pGadget.reset(new R1P_ ## GadgetType(pb, name1, name2, name3, name4, name5, name6, \ + name7, name8, name9)); \ + } else { \ + GADGETLIB_FATAL("Attempted to create gadget of undefined Protoboard type."); \ + } \ + pGadget->init(); \ + return pGadget; \ + } \ +private: \ + DISALLOW_CONSTRUCTION(GadgetType); \ + DISALLOW_COPY_AND_ASSIGN(GadgetType); \ +}; // class GadgetType + +#endif // LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_GADGETMACROS_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib2/infrastructure.cpp b/privacy/zsl/zsl/gadgetlib2/infrastructure.cpp new file mode 100644 index 0000000..6df9f95 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/infrastructure.cpp @@ -0,0 +1,120 @@ +/** @file + ***************************************************************************** + Common functionality needed by many components. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "infrastructure.hpp" + +#include +#include +#include +#include +#ifdef __linux__ +#include +#endif +#ifdef __GLIBC__ +#include // backtraces +#endif + +namespace gadgetlib2 { + +/********************************************************/ +/*************** Debug String Formatting ****************/ +/********************************************************/ + +#ifdef DEBUG +const static size_t MAX_FMT = 256; +::std::string GADGETLIB2_FMT(const char* format, ...) { + char buf[MAX_FMT]; + va_list args; + va_start(args, format); +#if defined(_MSC_VER) + const int strChk = vsnprintf_s(buf, MAX_FMT, MAX_FMT, format, args); +#else + const int strChk = vsnprintf(buf, MAX_FMT, format, args); +#endif + va_end(args); + GADGETLIB_ASSERT(strChk >= 0 && strChk < MAX_FMT, "String length larger than buffer. Shorten" + " string or increase buffer size defined in \"MAX_FMT\"."); + return ::std::string(buf); +} +#else // not DEBUG +::std::string GADGETLIB2_FMT(const char* format, ...) {UNUSED(format); return "";} +#endif + +/** Safely converts 64-bit types to 32-bit. */ +long safeConvert(const int64_t num) { + assert(num <= INT_MAX && num >= INT_MIN); + return (long)num; +} + +/*****************************************************************************/ +/*********************** ErrorHandling********** ****************************/ +/*****************************************************************************/ + +/* + TODO add dumping of environment variables and run command to a log file and add log file path + to release mode error message. We don't want people running release version to get any internal + information (variable values, stack trace, etc.) but want to have every data possible to + reproduce assertion. +*/ +void ErrorHandling::fatalError(const ::std::string& msg) { +# ifdef DEBUG + ::std::cerr << "ERROR: " << msg << ::std::endl << ::std::endl; + printStacktrace(); + throw ::std::runtime_error(msg); +# else // not DEBUG + UNUSED(msg); + const ::std::string releaseMsg("Fatal error encoutered. Run debug build for more" + " information and stack trace."); + ::std::cerr << "ERROR: " << releaseMsg << ::std::endl << ::std::endl; + throw ::std::runtime_error(releaseMsg); +# endif +} + +void ErrorHandling::fatalError(const ::std::stringstream& msg) { + fatalError(msg.str()); +} + +void ErrorHandling::printStacktrace() { +#ifdef __GLIBC__ + std::cerr << "Stack trace (pipe through c++filt to demangle identifiers):" << std::endl; + const int maxFrames = 100; + void* frames[maxFrames]; + // Fill array with pointers to stack frames + int numFrames = backtrace(frames, maxFrames); + // Decode frames and print them to stderr + backtrace_symbols_fd(frames, numFrames, STDERR_FILENO); +#else + //TODO make this available for non-glibc platforms (e.g. musl libc on Linux and Windows) + std::cerr << " (stack trace not available on this platform)" << std::endl; +#endif // __GNUC__ +} + +/*****************************************************************************/ +/**************************** Basic Math ***********************************/ +/*****************************************************************************/ + +double Log2( double n ) { + return log(n) / log((double)2); +} + +/// Returns an upper bound on log2(i). Namely, returns the number of binary digits needed to store +/// the value 'i'. When i == 0 returns 0. +unsigned int Log2ceil(uint64_t i) { + int retval = i ? 1 : 0 ; + while (i >>= 1) {++retval;} + return retval; +} + +///Returns true iff x is a power of 2 +bool IsPower2(const long x) { + return ( (x > 0) && ((x & (x - 1)) == 0) ); +} + +} // namespace gadgetlib2 + diff --git a/privacy/zsl/zsl/gadgetlib2/infrastructure.d b/privacy/zsl/zsl/gadgetlib2/infrastructure.d new file mode 100644 index 0000000..05b151b --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/infrastructure.d @@ -0,0 +1,3 @@ +src/gadgetlib2/infrastructure.o: src/gadgetlib2/infrastructure.cpp \ + src/gadgetlib2/infrastructure.hpp src/common/utils.hpp \ + src/common/utils.tcc diff --git a/privacy/zsl/zsl/gadgetlib2/infrastructure.hpp b/privacy/zsl/zsl/gadgetlib2/infrastructure.hpp new file mode 100644 index 0000000..aa5800f --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/infrastructure.hpp @@ -0,0 +1,125 @@ +/** @file + ***************************************************************************** + Common functionality needed by many components. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include "common/utils.hpp" + +#ifndef __infrastructure_HPP +#define __infrastructure_HPP + +#ifndef _MSC_VER // emulate the MSVC-specific sprintf_s using the standard snprintf +#define sprintf_s snprintf //TODO: sprintf_s!=snprintf (http://blog.verg.es/2008/09/sprintfs-is-not-snprintf.html) +#endif + +#ifdef _DEBUG // MSVC Debug build +#define DEBUG // gcc Debug flag +#endif + +/********************************************************/ +/**************** Class Writing Helpers *****************/ +/********************************************************/ +// A macro to disallow any non-defined constructors +// This should be used in the private: declarations for a class +#define DISALLOW_CONSTRUCTION(TypeName) \ + TypeName(); + +// A macro to disallow the copy constructor and operator= functions +// This should be used in the private: declarations for a class +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +/********************************************************/ +/*************** Debug String Formatting ****************/ +/********************************************************/ + +namespace gadgetlib2 { +// someday, if/when MSVC supports C++0x variadic templates, change FMT in release version to the +// following in order to increase efficiency: +// #define GADGETLIB2_FMT(...) "" +::std::string GADGETLIB2_FMT(const char* format, ...); + +/** Safely converts 64-bit types to 32-bit, or from unsigned to signed */ +long safeConvert(const int64_t num); + +/********************************************************/ +/******************* Error Handling *********************/ +/********************************************************/ + +// declare a function as never returning, to quiet down "control reaches end of non-void function" warnings +#if defined(_MSC_VER) // VisualC++ +#define __noreturn _declspec(noreturn) +#elif defined(__GNUC__) +#define __noreturn __attribute__((noreturn)) +#else +#define __noreturn +#endif + + + + /** + * The ErrorHandling class containimplements the functionality of displaying the content of error + * messages (including content of call stack when error happened), and exiting the program. + */ + class ErrorHandling { + public: + static void __noreturn fatalError(const ::std::string& msg); + static void __noreturn fatalError(const std::stringstream& msg); + static void printStacktrace(); + + }; + +#define GADGETLIB_FATAL(msg) do { \ + ::std::stringstream msgStream; \ + msgStream << msg << " (In file " << __FILE__ << " line " << __LINE__ << ".)"; \ + ErrorHandling::fatalError(msgStream.str()); \ + } while (0) + +// TODO change GADGETLIB_ASSERT to not run in debug +#define GADGETLIB_ASSERT(predicate, msg) if(!(bool(predicate))) GADGETLIB_FATAL(msg); + +/********************************************************/ +/****************** Basic Math **************************/ +/********************************************************/ + +double Log2(double n); + +//Calculates upper bound of Log2 of a number (number of bits needed to represent value) +unsigned int Log2ceil(uint64_t i); + +//Returns true iff the given number is a power of 2. +bool IsPower2(const long x); + + +//Returns a^b when a can be a and b are INTEGERS. +//constexpr int64_t POW(int64_t base, int exponent) { +// return (int64_t) powl((long double)base, (long double)exponent); +//} +//#define POW(a,b) ((int64_t)(pow((float)(a),(int)(b)))) + +// Returns 2^exponent +/*constexpr*/ inline int64_t POW2(int exponent) { + //assert(exponent>=0); + return ((int64_t)1) << exponent; +} + +//Returns the ceiling of a when a is of type double. +/*constexpr*/ inline int64_t CEIL(double a) { + return (int64_t)ceil(a); +} +//#define CEIL(a) ((int64_t)ceil((double)(a))) + +using libsnark::UNUSED; +} // namespace gadgetlib2 + +#endif // __infrastructure_HPP diff --git a/privacy/zsl/zsl/gadgetlib2/integration.cpp b/privacy/zsl/zsl/gadgetlib2/integration.cpp new file mode 100644 index 0000000..e7c22c4 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/integration.cpp @@ -0,0 +1,70 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "gadgetlib2/adapters.hpp" +#include "gadgetlib2/integration.hpp" + +namespace libsnark { + +linear_combination > convert_gadgetlib2_linear_combination(const gadgetlib2::GadgetLibAdapter::linear_combination_t &lc) +{ + typedef Fr FieldT; + typedef gadgetlib2::GadgetLibAdapter GLA; + + linear_combination result = lc.second * variable(0); + for (const GLA::linear_term_t < : lc.first) + { + result = result + lt.second * variable(lt.first+1); + } + + return result; +} + +r1cs_constraint_system > get_constraint_system_from_gadgetlib2(const gadgetlib2::Protoboard &pb) +{ + typedef Fr FieldT; + typedef gadgetlib2::GadgetLibAdapter GLA; + + r1cs_constraint_system result; + const GLA adapter; + + GLA::protoboard_t converted_pb = adapter.convert(pb); + for (const GLA::constraint_t &constr : converted_pb.first) + { + result.constraints.emplace_back(r1cs_constraint(convert_gadgetlib2_linear_combination(std::get<0>(constr)), + convert_gadgetlib2_linear_combination(std::get<1>(constr)), + convert_gadgetlib2_linear_combination(std::get<2>(constr)))); + } + //The numbers of variables is the highest index created. + //TODO: If there are multiple protoboard, or variables not assigned to a protoboard, then getNextFreeIndex() is *not* the number of variables! See also in get_variable_assignment_from_gadgetlib2. + const size_t num_variables = GLA::getNextFreeIndex(); + result.primary_input_size = pb.numInputs(); + result.auxiliary_input_size = num_variables - pb.numInputs(); + return result; +} + +r1cs_variable_assignment > get_variable_assignment_from_gadgetlib2(const gadgetlib2::Protoboard &pb) +{ + typedef Fr FieldT; + typedef gadgetlib2::GadgetLibAdapter GLA; + + //The numbers of variables is the highest index created. This is also the required size for the assignment vector. + //TODO: If there are multiple protoboard, or variables not assigned to a protoboard, then getNextFreeIndex() is *not* the number of variables! See also in get_constraint_system_from_gadgetlib2. + const size_t num_vars = GLA::getNextFreeIndex(); + const GLA adapter; + r1cs_variable_assignment result(num_vars, FieldT::zero()); + VariableAssignment assignment = pb.assignment(); + + //Go over all assigned values of the protoboard, from every variable-value pair, put the value in the variable.index place of the new assignment. + for(VariableAssignment::iterator iter = assignment.begin(); iter != assignment.end(); ++iter){ + result[GLA::getVariableIndex(iter->first)] = adapter.convert(iter->second); + } + + return result; +} + +} diff --git a/privacy/zsl/zsl/gadgetlib2/integration.d b/privacy/zsl/zsl/gadgetlib2/integration.d new file mode 100644 index 0000000..2f3ba64 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/integration.d @@ -0,0 +1,24 @@ +src/gadgetlib2/integration.o: src/gadgetlib2/integration.cpp \ + src/gadgetlib2/adapters.hpp src/gadgetlib2/pp.hpp \ + src/common/default_types/ec_pp.hpp src/algebra/curves/bn128/bn128_pp.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/bn128/bn128_init.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc depinst/include/bn.h \ + depinst/include/zm2.h depinst/include/zm.h \ + src/algebra/curves/bn128/bn128_g1.hpp src/algebra/curves/curve_utils.hpp \ + src/algebra/curves/curve_utils.tcc src/algebra/curves/bn128/bn128_g2.hpp \ + src/algebra/curves/bn128/bn128_gt.hpp \ + src/algebra/curves/bn128/bn128_pairing.hpp src/gadgetlib2/variable.hpp \ + src/gadgetlib2/infrastructure.hpp src/gadgetlib2/variable_operators.hpp \ + src/gadgetlib2/constraint.hpp src/gadgetlib2/protoboard.hpp \ + src/gadgetlib2/integration.hpp \ + src/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp \ + src/relations/variable.hpp src/relations/variable.tcc \ + src/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc \ + src/common/profiling.hpp src/gadgetlib2/protoboard.hpp diff --git a/privacy/zsl/zsl/gadgetlib2/integration.hpp b/privacy/zsl/zsl/gadgetlib2/integration.hpp new file mode 100644 index 0000000..c5dd9e6 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/integration.hpp @@ -0,0 +1,22 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef INTEGRATION_HPP_ +#define INTEGRATION_HPP_ + +#include "common/default_types/ec_pp.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" +#include "gadgetlib2/protoboard.hpp" + +namespace libsnark { + +r1cs_constraint_system > get_constraint_system_from_gadgetlib2(const gadgetlib2::Protoboard &pb); +r1cs_variable_assignment > get_variable_assignment_from_gadgetlib2(const gadgetlib2::Protoboard &pb); + +} // libsnark + +#endif // INTEGRATION_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib2/pp.cpp b/privacy/zsl/zsl/gadgetlib2/pp.cpp new file mode 100644 index 0000000..52d69e1 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/pp.cpp @@ -0,0 +1,30 @@ +/** @file + ***************************************************************************** + Implementation of PublicParams for Fp field arithmetic + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include "pp.hpp" + +namespace gadgetlib2 { + +PublicParams::PublicParams(const std::size_t log_p) : log_p(log_p) {} + +Fp PublicParams::getFp(long x) const { + return Fp(x); +} + +PublicParams::~PublicParams() {} + +PublicParams initPublicParamsFromDefaultPp() { + libsnark::default_ec_pp::init_public_params(); + const std::size_t log_p = libsnark::Fr::size_in_bits(); + return PublicParams(log_p); +} + +} // namespace gadgetlib2 diff --git a/privacy/zsl/zsl/gadgetlib2/pp.d b/privacy/zsl/zsl/gadgetlib2/pp.d new file mode 100644 index 0000000..e61b623 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/pp.d @@ -0,0 +1,16 @@ +src/gadgetlib2/pp.o: src/gadgetlib2/pp.cpp src/gadgetlib2/pp.hpp \ + src/common/default_types/ec_pp.hpp src/algebra/curves/bn128/bn128_pp.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/bn128/bn128_init.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc depinst/include/bn.h \ + depinst/include/zm2.h depinst/include/zm.h \ + src/algebra/curves/bn128/bn128_g1.hpp src/algebra/curves/curve_utils.hpp \ + src/algebra/curves/curve_utils.tcc src/algebra/curves/bn128/bn128_g2.hpp \ + src/algebra/curves/bn128/bn128_gt.hpp \ + src/algebra/curves/bn128/bn128_pairing.hpp diff --git a/privacy/zsl/zsl/gadgetlib2/pp.hpp b/privacy/zsl/zsl/gadgetlib2/pp.hpp new file mode 100644 index 0000000..046207e --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/pp.hpp @@ -0,0 +1,44 @@ +/** @file + ***************************************************************************** + Declaration of PublicParams for Fp field arithmetic + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_PP_HPP_ +#define LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_PP_HPP_ + +#include "common/default_types/ec_pp.hpp" + +#include +#include + +namespace gadgetlib2 { + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* R1P World ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* curve-specific public parameters */ +typedef libsnark::Fr Fp; + +typedef std::vector FpVector; + +class PublicParams { +public: + size_t log_p; + PublicParams(const std::size_t log_p); + Fp getFp(long x) const; // to_support changes later + ~PublicParams(); +}; + +PublicParams initPublicParamsFromDefaultPp(); + +} // namespace gadgetlib2 +#endif // LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_PP_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib2/protoboard.cpp b/privacy/zsl/zsl/gadgetlib2/protoboard.cpp new file mode 100644 index 0000000..e1d0b33 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/protoboard.cpp @@ -0,0 +1,211 @@ +/** @file + ***************************************************************************** + Implementation of Protoboard, a "memory manager" for building arithmetic constraints + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include "protoboard.hpp" + +using ::std::string; +using ::std::cout; +using ::std::endl; + +namespace gadgetlib2 { + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Protoboard ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +Protoboard::Protoboard(const FieldType& fieldType, ParamsCPtr pParams) + : numInputs_(0), pParams_(pParams), fieldType_(fieldType) {} + + +FElem& Protoboard::val(const Variable &var) { + FElem& retval = assignment_[var]; + GADGETLIB_ASSERT(retval.fieldType() == fieldType_ || retval.fieldType() == AGNOSTIC, + GADGETLIB2_FMT("Assigned field element of incorrect field type in Variable \"%s\"", + var.name().c_str())); + return retval; +} + +FElem Protoboard::val(const LinearCombination& lc) const { + return lc.eval(assignment_); +} + +void Protoboard::setValuesAsBitArray(const VariableArray& varArray, const size_t srcValue) { + GADGETLIB_ASSERT(varArray.size() >= Log2ceil(srcValue), + GADGETLIB2_FMT("Variable array of size %u to small to hold value %u. Array must be of size " + "at least %u", varArray.size(), srcValue, Log2ceil(srcValue))); + size_t i = 0; + for(i = 0; i < Log2ceil(srcValue); ++i) { + val(varArray[i]) = srcValue & (1u<>= 1; + } + if (expectedValueCopy != 0) { + retval = false; + } + if (expectedToPrintValues(retval, printOption)) { + cout << "Expected value for unpacked word \"" << unpackedWord.name() + << "\" is: " << expectedValue << endl; + cout << "Actual values are: " << endl; + for(size_t i = 0; i < unpackedWord.size(); ++i) { + cout << "bit " << i << ": " << val(unpackedWord[i]) << endl; + } + } + return retval; +} + + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +ProtoboardParams::~ProtoboardParams() {} + +} // namespace gadgetlib2 diff --git a/privacy/zsl/zsl/gadgetlib2/protoboard.d b/privacy/zsl/zsl/gadgetlib2/protoboard.d new file mode 100644 index 0000000..6a0a9df --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/protoboard.d @@ -0,0 +1,19 @@ +src/gadgetlib2/protoboard.o: src/gadgetlib2/protoboard.cpp \ + src/gadgetlib2/protoboard.hpp src/gadgetlib2/pp.hpp \ + src/common/default_types/ec_pp.hpp src/algebra/curves/bn128/bn128_pp.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/bn128/bn128_init.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc depinst/include/bn.h \ + depinst/include/zm2.h depinst/include/zm.h \ + src/algebra/curves/bn128/bn128_g1.hpp src/algebra/curves/curve_utils.hpp \ + src/algebra/curves/curve_utils.tcc src/algebra/curves/bn128/bn128_g2.hpp \ + src/algebra/curves/bn128/bn128_gt.hpp \ + src/algebra/curves/bn128/bn128_pairing.hpp src/gadgetlib2/variable.hpp \ + src/gadgetlib2/infrastructure.hpp src/gadgetlib2/variable_operators.hpp \ + src/gadgetlib2/constraint.hpp diff --git a/privacy/zsl/zsl/gadgetlib2/protoboard.hpp b/privacy/zsl/zsl/gadgetlib2/protoboard.hpp new file mode 100644 index 0000000..53aac52 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/protoboard.hpp @@ -0,0 +1,119 @@ +/** @file + ***************************************************************************** + Definition of Protoboard, a "memory manager" for building arithmetic constraints + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_PROTOBOARD_HPP_ +#define LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_PROTOBOARD_HPP_ + +#include +#include "pp.hpp" +#include "variable.hpp" +#include "constraint.hpp" + +#define ASSERT_CONSTRAINTS_SATISFIED(pb) \ + ASSERT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)) + +#define ASSERT_CONSTRAINTS_NOT_SATISFIED(pb) \ + ASSERT_FALSE(pb->isSatisfied(PrintOptions::NO_DBG_PRINT)) + +namespace gadgetlib2 { + +class ProtoboardParams; // Forward declaration +typedef ::std::shared_ptr ParamsCPtr; + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Protoboard ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +class Protoboard { +protected: + VariableAssignment assignment_; + ConstraintSystem constraintSystem_; + size_t numInputs_; + ParamsCPtr pParams_; // TODO try to refactor this out and use inheritance for different types + // of protoboards, for instance TinyRAMProtoboard : public Protoboard + // This may not be trivial because of Gadget multiple inheritance scheme + + Protoboard(const FieldType& fieldType, ParamsCPtr pParams); +public: + const FieldType fieldType_; + static ProtoboardPtr create(const FieldType& fieldType, ParamsCPtr pParams = NULL) { + return ProtoboardPtr(new Protoboard(fieldType, pParams)); + } + size_t numVars() const {return assignment_.size();} // TODO change to take num from constraintSys_ + //size_t numVars() const {return constraintSystem_.getUsedVariables().size();} // TODO change to take num from constraintSys_ + + size_t numInputs() const {return numInputs_;} // TODO Madars How do we book keep this? + ParamsCPtr params() const {return pParams_;} + FElem& val(const Variable& var); + FElem val(const LinearCombination& lc) const; + void setValuesAsBitArray(const VariableArray& varArray, const size_t srcValue); + void setDualWordValue(const DualWord& dualWord, const size_t srcValue); + void setMultipackedWordValue(const MultiPackedWord& multipackedWord, const size_t srcValue); + + // The following 3 methods are purposely not overloaded to the same name in order to reduce + // programmer error. We want the programmer to explicitly code what type of constraint + // she wants. + void addRank1Constraint(const LinearCombination& a, + const LinearCombination& b, + const LinearCombination& c, + const ::std::string& name); + void addGeneralConstraint(const Polynomial& a, + const Polynomial& b, + const ::std::string& name); + /// adds a constraint of the form (a == 0) + void addUnaryConstraint(const LinearCombination& a, const ::std::string& name); + bool isSatisfied(const PrintOptions& printOnFail = PrintOptions::NO_DBG_PRINT); + bool flagIsSet(const FlagVariable& flag) const {return val(flag) == 1;} + void setFlag(const FlagVariable& flag, bool newFlagState = true); + void clearFlag(const FlagVariable& flag) {val(flag) = 0;} + void flipFlag(const FlagVariable& flag) {val(flag) = 1 - val(flag);} + void enforceBooleanity(const Variable& var); + ::std::string annotation() const; + ConstraintSystem constraintSystem() const {return constraintSystem_;} + VariableAssignment assignment() const {return assignment_;} + bool dualWordAssignmentEqualsValue( + const DualWord& dualWord, + const size_t expectedValue, + const PrintOptions& printOption = PrintOptions::NO_DBG_PRINT) const; + bool multipackedWordAssignmentEqualsValue( + const MultiPackedWord& multipackedWord, + const size_t expectedValue, + const PrintOptions& printOption = PrintOptions::NO_DBG_PRINT) const; + bool unpackedWordAssignmentEqualsValue( + const UnpackedWord& unpackedWord, + const size_t expectedValue, + const PrintOptions& printOption = PrintOptions::NO_DBG_PRINT) const; +}; +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class ProtoboardParams ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* + An abstract class to hold any additional information needed by a specific Protoboard. For + example a Protoboard specific to TinyRAM will have a class ArchParams which will inherit from + this class. +*/ +class ProtoboardParams { +public: + virtual ~ProtoboardParams() = 0; +}; + +} // namespace gadgetlib2 + +#endif // LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_PROTOBOARD_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib2/tests/adapters_UTEST.cpp b/privacy/zsl/zsl/gadgetlib2/tests/adapters_UTEST.cpp new file mode 100644 index 0000000..dd34df3 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/tests/adapters_UTEST.cpp @@ -0,0 +1,105 @@ +/** @file + ***************************************************************************** + Unit tests for gadgetlib2 + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include + +using namespace gadgetlib2; + +namespace { + +TEST(GadgetLibAdapter, LinearTerm) { + initPublicParamsFromDefaultPp(); + const GadgetLibAdapter adapter; + adapter.resetVariableIndex(); + const Variable x("x"); + const LinearTerm lt = 5 * x; + const auto new_lt = adapter.convert(lt); + EXPECT_EQ(new_lt.first, 0u); + EXPECT_EQ(new_lt.second, Fp(5)); +} + +TEST(GadgetLibAdapter, LinearCombination) { + initPublicParamsFromDefaultPp(); + const GadgetLibAdapter adapter; + const Variable x("x"); + const Variable y("y"); + const LinearCombination lc = 5*x + 3*y + 42; + const auto new_lc = adapter.convert(lc); + EXPECT_EQ(new_lc.second, Fp(42)); + EXPECT_EQ(new_lc.first.size(), 2u); + EXPECT_EQ(new_lc.first[0], adapter.convert(5 * x)); + EXPECT_EQ(new_lc.first[1], adapter.convert(3 * y)); +} + +TEST(GadgetLibAdapter, Constraint) { + using ::std::get; + initPublicParamsFromDefaultPp(); + const GadgetLibAdapter adapter; + const Variable x("x"); + const Variable y("y"); + const Rank1Constraint constraint(x + y, 5 * x, 0, "(x + y) * (5 * x) == 0"); + const auto new_constraint = adapter.convert(constraint); + EXPECT_EQ(get<0>(new_constraint), adapter.convert(x + y)); + EXPECT_EQ(get<1>(new_constraint), adapter.convert(5 * x + 0)); + EXPECT_EQ(get<2>(new_constraint), adapter.convert(LinearCombination(0))); +} + +TEST(GadgetLibAdapter, ConstraintSystem) { + initPublicParamsFromDefaultPp(); + const GadgetLibAdapter adapter; + const Variable x("x"); + const Variable y("y"); + const Rank1Constraint constraint0(x + y, 5 * x, 0, "(x + y) * (5*x) == 0"); + const Rank1Constraint constraint1(x, y, 3, "x * y == 3"); + ConstraintSystem system; + system.addConstraint(constraint0); + system.addConstraint(constraint1); + const auto new_constraint_sys = adapter.convert(system); + EXPECT_EQ(new_constraint_sys.size(), 2u); + EXPECT_EQ(new_constraint_sys.at(0), adapter.convert(constraint0)); + EXPECT_EQ(new_constraint_sys.at(1), adapter.convert(constraint1)); +} + +TEST(GadgetLibAdapter, VariableAssignment) { + initPublicParamsFromDefaultPp(); + const GadgetLibAdapter adapter; + adapter.resetVariableIndex(); + const VariableArray varArray(10, "x"); + VariableAssignment assignment; + for (size_t i = 0; i < varArray.size(); ++i) { + assignment[varArray[i]] = i; + } + const auto new_assignment = adapter.convert(assignment); + ASSERT_EQ(assignment.size(), new_assignment.size()); + for (size_t i = 0; i < new_assignment.size(); ++i) { + const GadgetLibAdapter::variable_index_t var = i; + EXPECT_EQ(new_assignment.at(var), Fp(i)); + } +} + +TEST(GadgetLibAdapter, Protoboard) { + initPublicParamsFromDefaultPp(); + const GadgetLibAdapter adapter; + adapter.resetVariableIndex(); + const Variable x("x"); + const Variable y("y"); + ProtoboardPtr pb = Protoboard::create(R1P); + pb->addRank1Constraint(x + y, 5 * x, 0, "(x + y) * (5*x) == 0"); + pb->addRank1Constraint(x, y, 3, "x * y == 3"); + pb->val(x) = 1; + pb->val(y) = 2; + const auto new_pb = adapter.convert(*pb); + EXPECT_EQ(new_pb.first, adapter.convert(pb->constraintSystem())); + EXPECT_EQ(new_pb.second, adapter.convert(pb->assignment())); +} + + +} // namespace diff --git a/privacy/zsl/zsl/gadgetlib2/tests/constraint_UTEST.cpp b/privacy/zsl/zsl/gadgetlib2/tests/constraint_UTEST.cpp new file mode 100644 index 0000000..8daf2e5 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/tests/constraint_UTEST.cpp @@ -0,0 +1,50 @@ +/** @file + ***************************************************************************** + Unit tests for gadgetlib2 - test rank + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include +#include + +using ::std::set; +using namespace gadgetlib2; + +namespace { + +TEST(gadgetLib2, Rank1Constraint) { + initPublicParamsFromDefaultPp(); + VariableArray x(10,"x"); + VariableAssignment assignment; + for(int i = 0; i < 10; ++i) { + assignment[x[i]] = Fp(i); + } + LinearCombination a = x[0] + x[1] + 2; // = 0+1+2=3 + LinearCombination b = 2*x[2] - 3*x[3] + 4; // = 2*2-3*3+4=-1 + LinearCombination c = x[5]; // = 5 + Rank1Constraint c1(a,b,c,"c1"); + EXPECT_EQ(c1.a().eval(assignment), a.eval(assignment)); + EXPECT_EQ(c1.b().eval(assignment), b.eval(assignment)); + EXPECT_EQ(c1.c().eval(assignment), c.eval(assignment)); + EXPECT_FALSE(c1.isSatisfied(assignment)); + EXPECT_FALSE(c1.isSatisfied(assignment, PrintOptions::NO_DBG_PRINT)); + assignment[x[5]] = -3; + EXPECT_TRUE(c1.isSatisfied(assignment)); + EXPECT_TRUE(c1.isSatisfied(assignment, PrintOptions::NO_DBG_PRINT)); + const Variable::set varSet = c1.getUsedVariables(); + EXPECT_EQ(varSet.size(), 5u); + EXPECT_TRUE(varSet.find(x[0]) != varSet.end()); + EXPECT_TRUE(varSet.find(x[1]) != varSet.end()); + EXPECT_TRUE(varSet.find(x[2]) != varSet.end()); + EXPECT_TRUE(varSet.find(x[3]) != varSet.end()); + EXPECT_TRUE(varSet.find(x[4]) == varSet.end()); + EXPECT_TRUE(varSet.find(x[5]) != varSet.end()); +} + + +} // namespace diff --git a/privacy/zsl/zsl/gadgetlib2/tests/gadget_UTEST.cpp b/privacy/zsl/zsl/gadgetlib2/tests/gadget_UTEST.cpp new file mode 100644 index 0000000..44aaf01 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/tests/gadget_UTEST.cpp @@ -0,0 +1,409 @@ +/** @file + ***************************************************************************** + Unit tests for gadgetlib2 - tests for specific gadgets + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +using ::std::cerr; +using ::std::cout; +using ::std::endl; +using ::std::stringstream; +using namespace gadgetlib2; + +#define EXHAUSTIVE_N 4 + +namespace { + +TEST(gadgetLib2,R1P_AND_Gadget_SimpleTest) { + initPublicParamsFromDefaultPp(); + auto pb = Protoboard::create(R1P); + + VariableArray x(3, "x"); + Variable y("y"); + auto andGadget = AND_Gadget::create(pb, x, y); + andGadget->generateConstraints(); + + pb->val(x[0]) = 0; + pb->val(x[1]) = 1; + pb->val(x[2]) = 1; + andGadget->generateWitness(); + EXPECT_TRUE(pb->val(y) == 0); + EXPECT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + pb->val(y) = 1; + EXPECT_FALSE(pb->isSatisfied()); + + pb->val(x[0]) = 1; + andGadget->generateWitness(); + EXPECT_TRUE(pb->val(y) == 1); + EXPECT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + + pb->val(y) = 0; + EXPECT_FALSE(pb->isSatisfied()); +} + +class LogicGadgetExhaustiveTester { +protected: + ProtoboardPtr pb; + const size_t numInputs; + const VariableArray inputs; + const Variable output; + GadgetPtr logicGadget; + size_t currentInputValues; + + LogicGadgetExhaustiveTester(ProtoboardPtr pb, size_t numInputs); + void setInputValsTo(const size_t val); + void runCompletenessCheck(); + virtual void ruinOutputVal() = 0; + void runSoundnessCheck(); + + DISALLOW_COPY_AND_ASSIGN(LogicGadgetExhaustiveTester); +public: + void runExhaustiveTest(); +}; + +class AndGadgetExhaustiveTester : public LogicGadgetExhaustiveTester { +private: virtual void ruinOutputVal(); +public: AndGadgetExhaustiveTester(ProtoboardPtr pb, size_t numInputs); +}; + +class OrGadgetExhaustiveTester : public LogicGadgetExhaustiveTester { +private: virtual void ruinOutputVal(); +public: OrGadgetExhaustiveTester(ProtoboardPtr pb, size_t numInputs); +}; + + +TEST(gadgetLib2,R1P_ANDGadget_ExhaustiveTest) { + initPublicParamsFromDefaultPp(); + for(int inputSize = 1; inputSize <= EXHAUSTIVE_N; ++inputSize) { + SCOPED_TRACE(GADGETLIB2_FMT("n = %u \n", inputSize)); + auto pb = Protoboard::create(R1P); + AndGadgetExhaustiveTester tester(pb, inputSize); + tester.runExhaustiveTest(); + } +} + +TEST(gadgetLib2,BinaryAND_Gadget) { + auto pb = Protoboard::create(R1P); + Variable input1("input1"); + Variable input2("input2"); + Variable result("result"); + auto andGadget = AND_Gadget::create(pb, input1, input2, result); + andGadget->generateConstraints(); + pb->val(input1) = pb->val(input2) = 0; + andGadget->generateWitness(); + ASSERT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + ASSERT_EQ(pb->val(result), 0); + pb->val(result) = 1; + ASSERT_FALSE(pb->isSatisfied()); + pb->val(result) = 0; + pb->val(input1) = 1; + ASSERT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + pb->val(input2) = 1; + ASSERT_FALSE(pb->isSatisfied()); + andGadget->generateWitness(); + ASSERT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + ASSERT_EQ(pb->val(result), 1); +} + +TEST(gadgetLib2,R1P_ORGadget_Exhaustive) { + initPublicParamsFromDefaultPp(); + for(int n = 1; n <= EXHAUSTIVE_N; ++n) { + SCOPED_TRACE(GADGETLIB2_FMT("n = %u \n", n)); + auto pb = Protoboard::create(R1P); + OrGadgetExhaustiveTester tester(pb, n); + tester.runExhaustiveTest(); + } +} + +TEST(gadgetLib2,BinaryOR_Gadget) { + auto pb = Protoboard::create(R1P); + Variable input1("input1"); + Variable input2("input2"); + Variable result("result"); + auto orGadget = OR_Gadget::create(pb, input1, input2, result); + orGadget->generateConstraints(); + pb->val(input1) = pb->val(input2) = 0; + orGadget->generateWitness(); + ASSERT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + ASSERT_EQ(pb->val(result), 0); + pb->val(result) = 1; + ASSERT_FALSE(pb->isSatisfied()); + pb->val(result) = 0; + pb->val(input1) = 1; + ASSERT_FALSE(pb->isSatisfied()); + pb->val(result) = 1; + ASSERT_CONSTRAINTS_SATISFIED(pb); + pb->val(input2) = 1; + orGadget->generateWitness(); + ASSERT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + ASSERT_EQ(pb->val(result), 1); +} + +// TODO refactor this test --Shaul +TEST(gadgetLib2,R1P_InnerProductGadget_Exhaustive) { + initPublicParamsFromDefaultPp(); + const size_t n = EXHAUSTIVE_N; + auto pb = Protoboard::create(R1P); + VariableArray A(n, "A"); + VariableArray B(n, "B"); + Variable result("result"); + auto g = InnerProduct_Gadget::create(pb, A, B, result); + g->generateConstraints(); + for (size_t i = 0; i < 1u<val(A[k]) = i & (1u<val(B[k]) = j & (1u<generateWitness(); + EXPECT_EQ(pb->val(result) , FElem(correct)); + EXPECT_TRUE(pb->isSatisfied()); + // negative test + pb->val(result) = 100*n+19; + EXPECT_FALSE(pb->isSatisfied()); + } + } +} + +// TODO refactor this test --Shaul +TEST(gadgetLib2,R1P_LooseMUX_Gadget_Exhaustive) { +initPublicParamsFromDefaultPp(); +const size_t n = EXHAUSTIVE_N; + auto pb = Protoboard::create(R1P); + VariableArray arr(1<generateConstraints(); + for (size_t i = 0; i < 1u<val(arr[i]) = (19*i) % (1u<val(index) = idx; + g->generateWitness(); + if (0 <= idx && idx <= (1<val(result) , (19*idx) % (1u<val(success_flag) , 1); + EXPECT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + pb->val(result) -= 1; + EXPECT_FALSE(pb->isSatisfied()); + } + else { + EXPECT_EQ(pb->val(success_flag) , 0); + EXPECT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + pb->val(success_flag) = 1; + EXPECT_FALSE(pb->isSatisfied()); + } + } +} + +// Forward declaration +void packing_Gadget_R1P_ExhaustiveTest(ProtoboardPtr unpackingPB, ProtoboardPtr packingPB, + const int n, VariableArray packed, VariableArray unpacked, + GadgetPtr packingGadget, GadgetPtr unpackingGadget); + +// TODO refactor this test --Shaul +TEST(gadgetLib2,R1P_Packing_Gadgets) { + initPublicParamsFromDefaultPp(); + auto unpackingPB = Protoboard::create(R1P); + auto packingPB = Protoboard::create(R1P); + const int n = EXHAUSTIVE_N; + { // test CompressionPacking_Gadget + SCOPED_TRACE("testing CompressionPacking_Gadget"); + VariableArray packed(1, "packed"); + VariableArray unpacked(n, "unpacked"); + auto packingGadget = CompressionPacking_Gadget::create(packingPB, unpacked, packed, + PackingMode::PACK); + auto unpackingGadget = CompressionPacking_Gadget::create(unpackingPB, unpacked, packed, + PackingMode::UNPACK); + packing_Gadget_R1P_ExhaustiveTest(unpackingPB, packingPB, n, packed, unpacked, packingGadget, + unpackingGadget); + } + { // test IntegerPacking_Gadget + SCOPED_TRACE("testing IntegerPacking_Gadget"); + VariableArray packed(1, "packed"); + VariableArray unpacked(n, "unpacked"); + auto packingGadget = IntegerPacking_Gadget::create(packingPB, unpacked, packed, + PackingMode::PACK); + auto unpackingGadget = IntegerPacking_Gadget::create(unpackingPB, unpacked, packed, + PackingMode::UNPACK); + packing_Gadget_R1P_ExhaustiveTest(unpackingPB, packingPB, n, packed, unpacked, packingGadget, + unpackingGadget); + } +} + +TEST(gadgetLib2,R1P_EqualsConst_Gadget) { + initPublicParamsFromDefaultPp(); + auto pb = Protoboard::create(R1P); + Variable input("input"); + Variable result("result"); + auto gadget = EqualsConst_Gadget::create(pb, 0, input, result); + gadget->generateConstraints(); + pb->val(input) = 0; + gadget->generateWitness(); + // Positive test for input == n + EXPECT_EQ(pb->val(result), 1); + EXPECT_TRUE(pb->isSatisfied()); + // Negative test + pb->val(result) = 0; + EXPECT_FALSE(pb->isSatisfied()); + // Positive test for input != n + pb->val(input) = 1; + gadget->generateWitness(); + EXPECT_EQ(pb->val(result), 0); + EXPECT_TRUE(pb->isSatisfied()); + // Negative test + pb->val(input) = 0; + EXPECT_FALSE(pb->isSatisfied()); +} + +TEST(gadgetLib2,ConditionalFlag_Gadget) { + initPublicParamsFromDefaultPp(); + auto pb = Protoboard::create(R1P); + FlagVariable flag; + Variable condition("condition"); + auto cfGadget = ConditionalFlag_Gadget::create(pb, condition, flag); + cfGadget->generateConstraints(); + pb->val(condition) = 1; + cfGadget->generateWitness(); + ASSERT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + pb->val(condition) = 42; + cfGadget->generateWitness(); + ASSERT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + ASSERT_EQ(pb->val(flag),1); + pb->val(condition) = 0; + ASSERT_FALSE(pb->isSatisfied()); + cfGadget->generateWitness(); + ASSERT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + ASSERT_EQ(pb->val(flag),0); + pb->val(flag) = 1; + ASSERT_FALSE(pb->isSatisfied()); +} + +TEST(gadgetLib2,LogicImplication_Gadget) { + auto pb = Protoboard::create(R1P); + FlagVariable flag; + Variable condition("condition"); + auto implyGadget = LogicImplication_Gadget::create(pb, condition, flag); + implyGadget->generateConstraints(); + pb->val(condition) = 1; + pb->val(flag) = 0; + ASSERT_FALSE(pb->isSatisfied()); + implyGadget->generateWitness(); + ASSERT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + ASSERT_EQ(pb->val(flag), 1); + pb->val(condition) = 0; + ASSERT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + implyGadget->generateWitness(); + ASSERT_EQ(pb->val(flag), 1); + pb->val(flag) = 0; + ASSERT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); +} + +// TODO refactor this test --Shaul +void packing_Gadget_R1P_ExhaustiveTest(ProtoboardPtr unpackingPB, ProtoboardPtr packingPB, + const int n, VariableArray packed, VariableArray unpacked, + GadgetPtr packingGadget, GadgetPtr unpackingGadget) { + packingGadget->generateConstraints(); + unpackingGadget->generateConstraints(); + for(int i = 0; i < 1l< bits(n); + for(int j = 0; j < n; ++j) { + bits[j] = i & 1u<val(unpacked[j]) = bits[j]; // set unpacked bits in the packing protoboard + } + unpackingPB->val(packed[0]) = i; // set the packed value in the unpacking protoboard + unpackingGadget->generateWitness(); + packingGadget->generateWitness(); + ASSERT_TRUE(unpackingPB->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + ASSERT_TRUE(packingPB->isSatisfied()); + ASSERT_EQ(packingPB->val(packed[0]), i); // check packed value is correct + for(int j = 0; j < n; ++j) { + // Tests for unpacking gadget + SCOPED_TRACE(GADGETLIB2_FMT("\nValue being packed/unpacked: %u, bits[%u] = %u" , i, j, bits[j])); + ASSERT_EQ(unpackingPB->val(unpacked[j]), bits[j]); // check bit correctness + packingPB->val(unpacked[j]) = unpackingPB->val(unpacked[j]) = 1-bits[j]; // flip bit + ASSERT_FALSE(unpackingPB->isSatisfied()); + ASSERT_FALSE(packingPB->isSatisfied()); + packingPB->val(unpacked[j]) = unpackingPB->val(unpacked[j]) = bits[j]; // restore bit + // special case to test booleanity checks. Cause arithmetic constraints to stay + // satisfied while ruining Booleanity + if (j > 0 && bits[j]==1 && bits[j-1]==0 ) { + packingPB->val(unpacked[j-1]) = unpackingPB->val(unpacked[j-1]) = 2; + packingPB->val(unpacked[j]) = unpackingPB->val(unpacked[j]) = 0; + ASSERT_FALSE(unpackingPB->isSatisfied()); + ASSERT_TRUE(packingPB->isSatisfied()); // packing should not enforce Booleanity + // restore correct state + packingPB->val(unpacked[j-1]) = unpackingPB->val(unpacked[j-1]) = 0; + packingPB->val(unpacked[j]) = unpackingPB->val(unpacked[j]) = 1; + } + } + } +} + + +void LogicGadgetExhaustiveTester::setInputValsTo(const size_t val) { + for (size_t maskBit = 0; maskBit < numInputs; ++maskBit) { + pb->val(inputs[maskBit]) = (val & (1u << maskBit)) ? 1 : 0; + } +} + +void LogicGadgetExhaustiveTester::runCompletenessCheck() { + SCOPED_TRACE(GADGETLIB2_FMT("Positive (completeness) test failed. curInput: %u", currentInputValues)); + EXPECT_TRUE(pb->isSatisfied()); +} + +void LogicGadgetExhaustiveTester::runSoundnessCheck() { + SCOPED_TRACE(pb->annotation()); + SCOPED_TRACE(GADGETLIB2_FMT("Negative (soundness) test failed. curInput: %u, Constraints " + "are:", currentInputValues)); + EXPECT_FALSE(pb->isSatisfied()); +} +LogicGadgetExhaustiveTester::LogicGadgetExhaustiveTester(ProtoboardPtr pb, size_t numInputs) + : pb(pb), numInputs(numInputs), inputs(numInputs, "inputs"), output("output"), + currentInputValues(0) {} + +void LogicGadgetExhaustiveTester::runExhaustiveTest() { + logicGadget->generateConstraints(); + for (currentInputValues = 0; currentInputValues < (1u << numInputs); ++currentInputValues) { + setInputValsTo(currentInputValues); + logicGadget->generateWitness(); + runCompletenessCheck(); + ruinOutputVal(); + runSoundnessCheck(); + } +} + +void AndGadgetExhaustiveTester::ruinOutputVal() { + pb->val(output) = (currentInputValues == ((1u << numInputs) - 1)) ? 0 : 1; +} + +AndGadgetExhaustiveTester::AndGadgetExhaustiveTester(ProtoboardPtr pb, size_t numInputs) + : LogicGadgetExhaustiveTester(pb, numInputs) { + logicGadget = AND_Gadget::create(pb, inputs, output); +} + +void OrGadgetExhaustiveTester::ruinOutputVal() { + pb->val(output) = (currentInputValues == 0) ? 1 : 0; +} + +OrGadgetExhaustiveTester::OrGadgetExhaustiveTester(ProtoboardPtr pb, size_t numInputs) + : LogicGadgetExhaustiveTester(pb, numInputs) { + logicGadget = OR_Gadget::create(pb, inputs, output); +} + + +} // namespace diff --git a/privacy/zsl/zsl/gadgetlib2/tests/gadgetlib2_test.cpp b/privacy/zsl/zsl/gadgetlib2/tests/gadgetlib2_test.cpp new file mode 100644 index 0000000..a625592 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/tests/gadgetlib2_test.cpp @@ -0,0 +1,15 @@ +/** @file + ***************************************************************************** + Unit tests for gadgetlib2 - main() for running all tests + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/privacy/zsl/zsl/gadgetlib2/tests/integration_UTEST.cpp b/privacy/zsl/zsl/gadgetlib2/tests/integration_UTEST.cpp new file mode 100644 index 0000000..abe7b2f --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/tests/integration_UTEST.cpp @@ -0,0 +1,35 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "common/default_types/r1cs_ppzksnark_pp.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" +#include "gadgetlib2/examples/simple_example.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp" + +using namespace gadgetlib2; + +namespace { + +TEST(gadgetLib2,Integration) { + using namespace libsnark; + + initPublicParamsFromDefaultPp(); + const r1cs_example > example = gen_r1cs_example_from_gadgetlib2_protoboard(100); + const bool test_serialization = false; + + const bool bit = run_r1cs_ppzksnark(example, test_serialization); + EXPECT_TRUE(bit); +}; + +} diff --git a/privacy/zsl/zsl/gadgetlib2/tests/protoboard_UTEST.cpp b/privacy/zsl/zsl/gadgetlib2/tests/protoboard_UTEST.cpp new file mode 100644 index 0000000..3cad068 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/tests/protoboard_UTEST.cpp @@ -0,0 +1,63 @@ +/** @file + ***************************************************************************** + Unit tests for gadgetlib2 protoboard + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include + +using namespace gadgetlib2; + +namespace { + +TEST(gadgetLib2,R1P_enforceBooleanity) { + initPublicParamsFromDefaultPp(); + auto pb = Protoboard::create(R1P); + Variable x; + pb->enforceBooleanity(x); + pb->val(x) = 0; + EXPECT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + pb->val(x) = 1; + EXPECT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + pb->val(x) = Fp(2); + EXPECT_FALSE(pb->isSatisfied()); +} + +TEST(gadgetLib2, Protoboard_unpackedWordAssignmentEqualsValue_R1P) { + initPublicParamsFromDefaultPp(); + auto pb = Protoboard::create(R1P); + const UnpackedWord unpacked(8, "unpacked"); + pb->setValuesAsBitArray(unpacked, 42); + ASSERT_TRUE(pb->unpackedWordAssignmentEqualsValue(unpacked, 42)); + ASSERT_FALSE(pb->unpackedWordAssignmentEqualsValue(unpacked, 43)); + ASSERT_FALSE(pb->unpackedWordAssignmentEqualsValue(unpacked, 1024 + 42)); +} + +TEST(gadgetLib2, Protoboard_multipackedWordAssignmentEqualsValue_R1P) { + initPublicParamsFromDefaultPp(); + auto pb = Protoboard::create(R1P); + const MultiPackedWord multipacked(8, R1P, "multipacked"); + pb->val(multipacked[0]) = 42; + ASSERT_TRUE(pb->multipackedWordAssignmentEqualsValue(multipacked, 42)); + ASSERT_FALSE(pb->multipackedWordAssignmentEqualsValue(multipacked, 43)); + const MultiPackedWord multipackedAgnostic(AGNOSTIC); + ASSERT_THROW(pb->multipackedWordAssignmentEqualsValue(multipackedAgnostic, 43), + ::std::runtime_error); +} + +TEST(gadgetLib2, Protoboard_dualWordAssignmentEqualsValue_R1P) { + initPublicParamsFromDefaultPp(); + auto pb = Protoboard::create(R1P); + const DualWord dualword(8, R1P, "dualword"); + pb->setDualWordValue(dualword, 42); + ASSERT_TRUE(pb->dualWordAssignmentEqualsValue(dualword, 42)); + ASSERT_FALSE(pb->dualWordAssignmentEqualsValue(dualword, 43)); + ASSERT_FALSE(pb->dualWordAssignmentEqualsValue(dualword, 42 + 1024)); +} + +} // namespace diff --git a/privacy/zsl/zsl/gadgetlib2/tests/variable_UTEST.cpp b/privacy/zsl/zsl/gadgetlib2/tests/variable_UTEST.cpp new file mode 100644 index 0000000..b70fded --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/tests/variable_UTEST.cpp @@ -0,0 +1,701 @@ +/** @file + ***************************************************************************** + Unit tests for gadgetlib2 variables + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include +#include + +using ::std::set; +using namespace gadgetlib2; + +namespace { + +TEST(gadgetLib2, VariableNaming) { + Variable v1; + EXPECT_EQ(v1.name(), ""); + Variable v2("foo"); +# ifdef DEBUG + EXPECT_EQ(v2.name(), "foo"); +# endif + v2 = v1; + EXPECT_EQ(v2.name(), ""); +} + +TEST(gadgetLib2, VariableStrictOrdering) { + Variable v1; + Variable v2; + Variable::VariableStrictOrder orderFunc; + EXPECT_TRUE(orderFunc(v1, v2) || orderFunc(v2, v1)); // check strict ordering + v2 = v1; + EXPECT_FALSE(orderFunc(v1, v2) || orderFunc(v2, v1)); +} + + +TEST(gadgetLib2, VariableSet) { + Variable v1; + Variable::set s1; + s1.insert(v1); + EXPECT_EQ(s1.size(), 1u); + Variable v2; + v2 = v1; + s1.insert(v2); + EXPECT_EQ(s1.size(), 1u); + Variable v3; + s1.insert(v3); + EXPECT_EQ(s1.size(), 2u); + Variable v4; + s1.erase(v4); + EXPECT_EQ(s1.size(), 2u); + v4 = v1; + s1.erase(v4); + EXPECT_EQ(s1.size(), 1u); +} + +TEST(gadgetLib2, VariableArray) { + Variable v1; + Variable v2("v2"); + VariableArray vArr; + vArr.push_back(v1); + vArr.push_back(v2); + EXPECT_EQ(vArr.size(),2u); + Variable::VariableStrictOrder orderFunc; + EXPECT_TRUE(orderFunc(vArr[0],vArr[1]) || orderFunc(vArr[1],vArr[0])); // check strict ordering + vArr[1] = vArr[0]; + EXPECT_FALSE(orderFunc(vArr[0],vArr[1]) || orderFunc(vArr[1],vArr[0])); // check strict ordering + EXPECT_THROW(vArr.at(2) = v1, ::std::out_of_range); +} + +TEST(gadgetLib2, VariableEval) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + VariableAssignment ass; + ass[x[0]] = Fp(42); + EXPECT_EQ(x[0].eval(ass), 42); + EXPECT_NE(x[0].eval(ass), 17); +} + +TEST(gadgetLib2, FElem_FConst_fromLong) { + initPublicParamsFromDefaultPp(); + FElem e0(long(0)); + EXPECT_TRUE(e0 == 0); +} + +TEST(gadgetLib2, FElem_FConst_fromInt) { + initPublicParamsFromDefaultPp(); + FElem e1(int(1)); + EXPECT_TRUE(e1 == 1); + FElem e2(2); + EXPECT_EQ(e2, FElem(2)); +} + +TEST(gadgetLib2, FElem_FConst_copy) { + initPublicParamsFromDefaultPp(); + FElem e0(long(0)); + FElem e1(int(1)); + FElem e3(e1); + EXPECT_TRUE(e3 == 1); + e3 = 0; + EXPECT_TRUE(e3 == 0); + ASSERT_EQ(e1, 1); + e0 = e1; + EXPECT_EQ(e0, e1); + e0 = 0; + EXPECT_NE(e0, e1); +} + +TEST(gadgetLib2, FElem_FConst_move) { + initPublicParamsFromDefaultPp(); + FElem e4(FElem(4)); + EXPECT_EQ(e4, FElem(4)); +} + +TEST(gadgetLib2, FElem_FConst_assignment) { + initPublicParamsFromDefaultPp(); + FElem e0(0); + FElem e1(0); + e0 = e1 = 42; + EXPECT_EQ(e1, FElem(42)); + EXPECT_EQ(e0, e1); +} + +TEST(gadgetLib2, FElem_FConst_asString) { + initPublicParamsFromDefaultPp(); + FElem e0(42); + #ifdef DEBUG + EXPECT_EQ(e0.asString(), "42"); + #else + EXPECT_EQ(e0.asString(), ""); + #endif +} + +TEST(gadgetLib2, FElem_FConst_fieldType) { + initPublicParamsFromDefaultPp(); + FElem e0(42); + EXPECT_EQ(e0.fieldType(), AGNOSTIC); + e0 = Fp(42); + EXPECT_NE(e0.fieldType(), AGNOSTIC); +} + +TEST(gadgetLib2, FElem_FConst_operatorEquals) { + initPublicParamsFromDefaultPp(); + FElem e0(long(0)); + FElem e1(int(1)); + FElem e2(FElem(2)); + e0 = e1 = 42; + //bool operator==(const FElem& other) const {return *elem_ == *other.elem_;} + EXPECT_TRUE(e1 == e0); + EXPECT_FALSE(e1 == e2); + FElem eR1P = Fp(42); + EXPECT_TRUE(e1 == eR1P); + EXPECT_TRUE(eR1P == e1); + //bool operator==(const FElem& first, const long second); + FElem e3(FElem(4)); + EXPECT_TRUE(e3 == 4); + //bool operator==(const long first, const FElem& second); + EXPECT_TRUE(4 == e3); +} + +TEST(gadgetLib2, FElem_FConst_operatorPlus) { + initPublicParamsFromDefaultPp(); + //FElem& operator+=(const FElem& other) {*elem_ += *other.elem_; return *this;} + FElem e0(0); + FElem e1(0); + e0 = e1 = 42; + e1 = e0 += e1; + EXPECT_EQ(e0, FElem(84)); + EXPECT_TRUE(e1 == 84); +} + +TEST(gadgetLib2, FElem_FConst_operatorMinus) { + initPublicParamsFromDefaultPp(); + //FElem& operator+=(const FElem& other) {*elem_ += *other.elem_; return *this;} + FElem e0(0); + FElem e1(0); + e0 = e1 = 42; + e1 = e0 -= e1; + EXPECT_TRUE(e0 == 0); + EXPECT_TRUE(e1 == 0); + e0 = 21; + e1 = 2; + EXPECT_EQ(e0, FElem(21)); + EXPECT_TRUE(e1 == 2); +} + +TEST(gadgetLib2, FElem_FConst_operatorTimes) { + initPublicParamsFromDefaultPp(); + //FElem& operator+=(const FElem& other) {*elem_ += *other.elem_; return *this;} + FElem e0 = 21; + FElem e1 = 2; + e1 = e0 *= e1; + EXPECT_TRUE(e0 == 42); + EXPECT_TRUE(e1 == 42); + EXPECT_TRUE(e0 == e1); + EXPECT_TRUE(e0 == 42); + EXPECT_TRUE(42 == e0); +} + +TEST(gadgetLib2, FElem_FConst_operatorUnaryMinus) { + initPublicParamsFromDefaultPp(); + FElem e4(FElem(4)); + EXPECT_EQ(-e4, FElem(-4)); +} + +TEST(gadgetLib2, FElem_FConst_operatorNotEquals) { + initPublicParamsFromDefaultPp(); + FElem e0 = 21; + FElem e4(FElem(4)); + //bool operator!=(const FElem& first, const FElem& second); + EXPECT_TRUE(e4 != e0); + //bool operator!=(const FElem& first, const long second); + EXPECT_TRUE(e4 != 5); + //bool operator!=(const long first, const FElem& second); + EXPECT_TRUE(5 != e4); +} + +TEST(gadgetLib2, FElem_FConst_inverse) { + initPublicParamsFromDefaultPp(); + FElem e4 = 4; + FElem eInv = e4.inverse(R1P); + EXPECT_EQ(eInv, FElem(Fp(e4.asLong()).inverse())); +} + + +TEST(gadgetLib2, FElem_R1P_Elem_constructor) { + initPublicParamsFromDefaultPp(); + FElem e0(Fp(0)); + EXPECT_EQ(e0, 0); + EXPECT_NE(e0, 1); +} + +TEST(gadgetLib2, FElem_R1P_Elem_copy) { + initPublicParamsFromDefaultPp(); + FElem e0(Fp(0)); + FElem e1(e0); + EXPECT_EQ(e1, 0); +} + +TEST(gadgetLib2, FElem_R1P_Elem_assignment) { + initPublicParamsFromDefaultPp(); + initPublicParamsFromDefaultPp(); + FElem e0(Fp(0)); + FElem e1(e0); + FElem e2 = Fp(2); + e1 = e2; + EXPECT_EQ(e1, 2); + FElem e3 = 3; + e1 = e3; + EXPECT_EQ(e1, 3); +} + +TEST(gadgetLib2, FElem_R1P_Elem_move) { + initPublicParamsFromDefaultPp(); + FElem e1 = 1; + e1 = FElem(Fp(2)); + EXPECT_EQ(e1, 2); + e1 = FElem(1); + EXPECT_EQ(e1, 1); +} + +TEST(gadgetLib2, FElem_R1P_Elem_assignFromLong) { + initPublicParamsFromDefaultPp(); + FElem e1 = FElem(1); + e1 = long(42); + EXPECT_EQ(e1, 42); +} + +TEST(gadgetLib2, FElem_R1P_Elem_asString) { + initPublicParamsFromDefaultPp(); + FElem e1 = long(42); + #ifdef DEBUG + EXPECT_EQ(e1.asString(), "42"); + #else + EXPECT_EQ(e1.asString(), ""); + #endif +} + +TEST(gadgetLib2, FElem_R1P_Elem_fieldType) { + initPublicParamsFromDefaultPp(); + FElem e1 = Fp(42); + EXPECT_EQ(e1.fieldType(), R1P); +} + +TEST(gadgetLib2, FElem_R1P_Elem_operatorEquals) { + initPublicParamsFromDefaultPp(); + FElem e0 = 42; + FElem e1 = long(42); + FElem e2 = Fp(2); + EXPECT_TRUE(e0 == e1); + EXPECT_FALSE(e0 == e2); + EXPECT_FALSE(e0 != e1); + EXPECT_TRUE(e0 == 42); + EXPECT_FALSE(e0 == 41); + EXPECT_TRUE(e0 != 41); + EXPECT_TRUE(42 == e0); + EXPECT_TRUE(41 != e0); +} + +TEST(gadgetLib2, FElem_R1P_Elem_negativeNums) { + initPublicParamsFromDefaultPp(); + FElem e1 = long(42); + FElem e2 = Fp(2); + FElem e0 = e1 = -42; + EXPECT_TRUE(e0 == e1); + EXPECT_FALSE(e0 == e2); + EXPECT_FALSE(e0 != e1); + EXPECT_TRUE(e0 == -42); + EXPECT_FALSE(e0 == -41); + EXPECT_TRUE(e0 != -41); + EXPECT_TRUE(-42 == e0); + EXPECT_TRUE(-41 != e0); +} + +TEST(gadgetLib2, FElem_R1P_Elem_operatorTimes) { + initPublicParamsFromDefaultPp(); + FElem e1 = Fp(1); + FElem e2 = Fp(2); + FElem e3 = Fp(3); + EXPECT_TRUE(e1.fieldType() == R1P && e2.fieldType() == R1P); + e1 = e2 *= e3; + EXPECT_EQ(e1, 6); + EXPECT_EQ(e2, 6); + EXPECT_EQ(e3, 3); +} + +TEST(gadgetLib2, FElem_R1P_Elem_operatorPlus) { + initPublicParamsFromDefaultPp(); + FElem e1 = Fp(6); + FElem e2 = Fp(6); + FElem e3 = Fp(3); + e1 = e2 += e3; + EXPECT_EQ(e1, 9); + EXPECT_EQ(e2, 9); + EXPECT_EQ(e3, 3); +} + +TEST(gadgetLib2, FElem_R1P_Elem_operatorMinus) { + initPublicParamsFromDefaultPp(); + FElem e1 = Fp(9); + FElem e2 = Fp(9); + FElem e3 = Fp(3); + e1 = e2 -= e3; + EXPECT_EQ(e1, 6); + EXPECT_EQ(e2, 6); + EXPECT_EQ(e3, 3); +} + +TEST(gadgetLib2, FElem_R1P_Elem_operatorUnaryMinus) { + initPublicParamsFromDefaultPp(); + FElem e2 = Fp(6); + FElem e3 = 3; + e3 = -e2; + EXPECT_EQ(e2, 6); + EXPECT_EQ(e3, -6); + EXPECT_TRUE(e3.fieldType() == R1P); +} + +TEST(gadgetLib2, FElem_R1P_Elem_inverse) { + initPublicParamsFromDefaultPp(); + FElem e42 = Fp(42); + EXPECT_EQ(e42.inverse(R1P),Fp(42).inverse()); +} + +TEST(gadgetLib2, LinearTermConstructors) { + initPublicParamsFromDefaultPp(); + //LinearTerm(const Variable& v) : variable_(v), coeff_(1) {} + VariableArray x(10, "x"); + LinearTerm lt0(x[0]); + VariableAssignment ass; + ass[x[0]] = Fp(42); + EXPECT_EQ(lt0.eval(ass), 42); + EXPECT_NE(lt0.eval(ass), 17); + ass[x[0]] = Fp(2); + EXPECT_EQ(lt0.eval(ass), 2); + LinearTerm lt2(x[2]); + ass[x[2]] = 24; + EXPECT_EQ(lt2.eval(ass), 24); + //LinearTerm(const Variable& v, const FElem& coeff) : variable_(v), coeff_(coeff) {} + LinearTerm lt3(x[3], Fp(3)); + ass[x[3]] = Fp(4); + EXPECT_EQ(lt3.eval(ass), 3 * 4); + //LinearTerm(const Variable& v, long n) : variable_(v), coeff_(n) {} + LinearTerm lt5(x[5], long(2)); + ass[x[5]] = 5; + EXPECT_EQ(lt5.eval(ass), 5 * 2); + LinearTerm lt6(x[6], 2); + ass[x[6]] = 6; + EXPECT_EQ(lt6.eval(ass), 6 * 2); +} + +TEST(gadgetLib2, LinearTermUnaryMinus) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + LinearTerm lt6(x[6], 2); + LinearTerm lt7 = -lt6; + VariableAssignment ass; + ass[x[6]] = 6; + EXPECT_EQ(lt7.eval(ass), -6 * 2); +} + +TEST(gadgetLib2, LinearTermFieldType) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + LinearTerm lt3(x[3], Fp(3)); + LinearTerm lt6(x[6], 2); + VariableAssignment ass; + ass[x[3]] = Fp(4); + ass[x[6]] = 6; + EXPECT_EQ(lt6.fieldtype(), AGNOSTIC); + EXPECT_EQ(lt3.fieldtype(), R1P); +} + +TEST(gadgetLib2, LinearTermAsString) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + VariableAssignment ass; + #ifdef DEBUG + // R1P + LinearTerm lt10(x[0], Fp(-1)); + EXPECT_EQ(lt10.asString(), "-1 * x[0]"); + LinearTerm lt11(x[0], Fp(0)); + EXPECT_EQ(lt11.asString(), "0 * x[0]"); + LinearTerm lt12(x[0], Fp(1)); + EXPECT_EQ(lt12.asString(), "x[0]"); + LinearTerm lt13(x[0], Fp(2)); + EXPECT_EQ(lt13.asString(), "2 * x[0]"); + // AGNOSTIC + LinearTerm lt30(x[0], -1); + EXPECT_EQ(lt30.asString(), "-1 * x[0]"); + LinearTerm lt31(x[0], 0); + EXPECT_EQ(lt31.asString(), "0 * x[0]"); + LinearTerm lt32(x[0], Fp(1)); + EXPECT_EQ(lt32.asString(), "x[0]"); + LinearTerm lt33(x[0], Fp(2)); + EXPECT_EQ(lt33.asString(), "2 * x[0]"); + #endif // DEBUG +} + +TEST(gadgetLib2, LinearTermOperatorTimes) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + VariableAssignment ass; + ass[x[0]] = Fp(2); + LinearTerm lt42(x[0], Fp(1)); + LinearTerm lt43(x[0], Fp(2)); + lt42 = lt43 *= FElem(4); + EXPECT_EQ(lt42.eval(ass), 8*2); + EXPECT_EQ(lt43.eval(ass), 8*2); +} + +// TODO refactor this test +TEST(gadgetLib2, LinearCombination) { + initPublicParamsFromDefaultPp(); +// LinearCombination() : linearTerms_(), constant_(0) {} + LinearCombination lc0; + VariableAssignment assignment; + EXPECT_EQ(lc0.eval(assignment),0); +// LinearCombination(const Variable& var) : linearTerms_(1,var), constant_(0) {} + VariableArray x(10,"x"); + LinearCombination lc1(x[1]); + assignment[x[1]] = 42; + EXPECT_EQ(lc1.eval(assignment),42); +// LinearCombination(const LinearTerm& linTerm) : linearTerms_(1,linTerm), constant_(0) {} + LinearTerm lt(x[2], Fp(2)); + LinearCombination lc2 = lt; + assignment[x[2]] = 2; + EXPECT_EQ(lc2.eval(assignment),4); +// LinearCombination(long i) : linearTerms_(), constant_(i) {} + LinearCombination lc3 = 3; + EXPECT_EQ(lc3.eval(assignment),3); +// LinearCombination(const FElem& elem) : linearTerms_(), constant_(elem) {} + FElem elem = Fp(4); + LinearCombination lc4 = elem; + EXPECT_EQ(lc4.eval(assignment),4); +// LinearCombination& operator+=(const LinearCombination& other); + lc1 = lc4 += lc2; + EXPECT_EQ(lc4.eval(assignment),4+4); + EXPECT_EQ(lc1.eval(assignment),4+4); + EXPECT_EQ(lc2.eval(assignment),4); +// LinearCombination& operator-=(const LinearCombination& other); + lc1 = lc4 -= lc3; + EXPECT_EQ(lc4.eval(assignment),4+4-3); + EXPECT_EQ(lc1.eval(assignment),4+4-3); + EXPECT_EQ(lc3.eval(assignment),3); +// ::std::string asString() const; +# ifdef DEBUG + EXPECT_EQ(lc1.asString(), "2 * x[2] + 1"); +# else // ifdef DEBUG + EXPECT_EQ(lc1.asString(), ""); +# endif // ifdef DEBUG +// Variable::set getUsedVariables() const; + Variable::set sVar = lc1.getUsedVariables(); + EXPECT_EQ(sVar.size(),1u); + assignment[x[2]] = 83; + EXPECT_EQ(assignment[*sVar.begin()], 83); + assignment[x[2]] = 2; +// LinearCombination operator-(const LinearCombination& lc); + lc2 = -lc1; + EXPECT_EQ(lc2.eval(assignment),-5); + lc2 = lc1 *= FElem(4); + EXPECT_EQ(lc1.eval(assignment),5*4); + EXPECT_EQ(lc2.eval(assignment),5*4); +} + +TEST(gadgetLib2, MonomialConstructors) { + initPublicParamsFromDefaultPp(); + //Monomial(const Variable& var) : coeff_(1), variables_(1, var) {} + VariableArray x(10, "x"); + Monomial m0 = x[0]; + VariableAssignment assignment; + assignment[x[0]] = 42; + EXPECT_EQ(m0.eval(assignment), 42); + //Monomial(const Variable& var, const FElem& coeff) : coeff_(coeff), variables_(1, var) {} + Monomial m1(x[1], Fp(3)); + assignment[x[1]] = 2; + EXPECT_EQ(m1.eval(assignment), 6); + //Monomial(const LinearTerm& linearTerm); + LinearTerm lt(x[3], 3); + Monomial m3 = lt; + assignment[x[3]] = 3; + EXPECT_EQ(m3.eval(assignment), 9); +} + +TEST(gadgetLib2, MonomialUnaryMinus) { + initPublicParamsFromDefaultPp(); + Variable x("x"); + Monomial m3 = 3 * x; + Monomial m4 = -m3; + VariableAssignment assignment; + assignment[x] = 3; + EXPECT_EQ(m4.eval(assignment), -9); +} + +TEST(gadgetLib2, MonomialOperatorTimes) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + Monomial m0 = x[0]; + Monomial m4 = -3 * x[3]; + Monomial m3 = m4 *= m0; + VariableAssignment assignment; + assignment[x[0]] = 42; + assignment[x[3]] = 3; + EXPECT_EQ(m3.eval(assignment), -9 * 42); + EXPECT_EQ(m4.eval(assignment), -9 * 42); + EXPECT_EQ(m0.eval(assignment), 42); +} + +TEST(gadgetLib2, MonomialUsedVariables) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + Monomial m0 = x[0]; + Monomial m4 = -3 * x[3]; + Monomial m3 = m4 *= m0; + Variable::set varSet = m3.getUsedVariables(); + ASSERT_EQ(varSet.size(), 2u); + EXPECT_TRUE(varSet.find(x[0]) != varSet.end()); + EXPECT_TRUE(varSet.find(x[3]) != varSet.end()); + EXPECT_TRUE(varSet.find(x[4]) == varSet.end()); +} + +TEST(gadgetLib2, MonomialAsString) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + Monomial m0 = x[0]; + Monomial m4 = x[3] * -3; + Monomial m3 = m4 *= m0; +# ifdef DEBUG + EXPECT_EQ(m3.asString(), "-3*x[0]*x[3]"); +# else + EXPECT_EQ(m3.asString(), ""); +# endif +} + +TEST(gadgetLib2, PolynomialConstructors) { + initPublicParamsFromDefaultPp(); + //Polynomial(); + Polynomial p0; + VariableAssignment assignment; + EXPECT_EQ(p0.eval(assignment), 0); + //Polynomial(const Monomial& monomial); + VariableArray x(10, "x"); + Monomial m0(x[0], 3); + Polynomial p1 = m0; + assignment[x[0]] = 2; + EXPECT_EQ(p1.eval(assignment), 6); + //Polynomial(const Variable& var); + Polynomial p2 = x[2]; + assignment[x[2]] = 2; + EXPECT_EQ(p2.eval(assignment), 2); + //Polynomial(const FElem& val); + Polynomial p3 = FElem(Fp(3)); + EXPECT_EQ(p3.eval(assignment), 3); + //Polynomial(const LinearCombination& linearCombination); + LinearCombination lc(x[0]); + lc += x[2]; + Polynomial p4 = lc; + EXPECT_EQ(p4.eval(assignment), 4); + //Polynomial(const LinearTerm& linearTerm); + const LinearTerm lt5 = 5 * x[5]; + Polynomial p5 = lt5; + assignment[x[5]] = 5; + EXPECT_EQ(p5.eval(assignment), 25); +} + +TEST(gadgetLib2, PolynomialUsedVariables) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + Polynomial p4 = x[0] + x[2]; + const Variable::set varSet = p4.getUsedVariables(); + EXPECT_EQ(varSet.size(), 2u); + EXPECT_TRUE(varSet.find(x[0]) != varSet.end()); + EXPECT_TRUE(varSet.find(x[2]) != varSet.end()); +} + +TEST(gadgetLib2, PolynomialOperatorPlus) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + Polynomial p3 = FElem(Fp(3)); + Polynomial p4 = x[0] + x[2]; + Polynomial p5 = p4 += p3; + VariableAssignment assignment; + assignment[x[0]] = 2; + assignment[x[2]] = 2; + EXPECT_EQ(p5.eval(assignment), 7); +} + +TEST(gadgetLib2, PolynomialAsString) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + Polynomial p0; + Polynomial p1 = 3 * x[0]; + Polynomial p2 = x[2]; + Polynomial p3 = FElem(Fp(3)); + Polynomial p4 = x[0] + x[2]; + Polynomial p5 = p4 += p3; +# ifdef DEBUG + EXPECT_EQ(p0.asString(), "0"); + EXPECT_EQ(p1.asString(), "3*x[0]"); + EXPECT_EQ(p2.asString(), "x[2]"); + EXPECT_EQ(p3.asString(), "3"); + EXPECT_EQ(p4.asString(), "x[0] + x[2] + 3"); + EXPECT_EQ(p5.asString(), "x[0] + x[2] + 3"); +# else // DEBUG + EXPECT_EQ(p0.asString(), ""); + EXPECT_EQ(p1.asString(), ""); + EXPECT_EQ(p2.asString(), ""); + EXPECT_EQ(p3.asString(), ""); + EXPECT_EQ(p4.asString(), ""); + EXPECT_EQ(p5.asString(), ""); +# endif // DEBUG +} + +TEST(gadgetLib2, PolynomialOperatorTimes) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + VariableAssignment assignment; + assignment[x[0]] = 2; + assignment[x[2]] = 2; + Polynomial p4 = x[0] + x[2]; + Polynomial p5 = p4 += 3; + Polynomial p0 = p4 *= p5; + EXPECT_EQ(p0.eval(assignment), 7 * 7); + EXPECT_EQ(p4.eval(assignment), 7 * 7); + EXPECT_EQ(p5.eval(assignment), 7); +} + +TEST(gadgetLib2, PolynomialOperatorMinus) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + Polynomial p0 = x[0]; + Polynomial p1 = x[1]; + Polynomial p2 = 2 * x[2]; + VariableAssignment assignment; + assignment[x[0]] = 0; + assignment[x[1]] = 1; + assignment[x[2]] = 2; + p0 = p1 -= p2; // = x[1] - 2 * x[2] = 1 - 2 * 2 + EXPECT_EQ(p0.eval(assignment), 1 - 2 * 2); + EXPECT_EQ(p1.eval(assignment), 1 - 2 * 2); + EXPECT_EQ(p2.eval(assignment), 2 * 2); +} + +TEST(gadgetLib2, PolynomialUnaryMinus) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + Polynomial p0 = x[0]; + Polynomial p1 = x[1]; + VariableAssignment assignment; + assignment[x[0]] = 0; + assignment[x[1]] = 1; + p0 = -p1; + EXPECT_EQ(p0.eval(assignment), -1); + EXPECT_EQ(p1.eval(assignment), 1); +} + +} // namespace diff --git a/privacy/zsl/zsl/gadgetlib2/variable.cpp b/privacy/zsl/zsl/gadgetlib2/variable.cpp new file mode 100644 index 0000000..89e501f --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/variable.cpp @@ -0,0 +1,685 @@ +/** @file + ***************************************************************************** + Implementation of the low level objects needed for field arithmetization. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include "variable.hpp" +#include "pp.hpp" +#include "infrastructure.hpp" + +using ::std::string; +using ::std::stringstream; +using ::std::set; +using ::std::vector; +using ::std::shared_ptr; +using ::std::cout; +using ::std::endl; +using ::std::dynamic_pointer_cast; + +namespace gadgetlib2 { + + +// Optimization: In the future we may want to port most of the member functions from this file to +// the .hpp files in order to allow for compiler inlining. As inlining has tradeoffs this should be +// profiled before doing so. + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class FElem ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +FElem::FElem(const FElemInterface& elem) : elem_(elem.clone()) {} +FElem::FElem() : elem_(new FConst(0)) {} +FElem::FElem(const long n) : elem_(new FConst(n)) {} +FElem::FElem(const int i) : elem_(new FConst(i)) {} +FElem::FElem(const size_t n) : elem_(new FConst(n)) {} +FElem::FElem(const Fp& elem) : elem_(new R1P_Elem(elem)) {} +FElem::FElem(const FElem& src) : elem_(src.elem_->clone()) {} + + +FElem& FElem::operator=(const FElem& other) { + if (fieldType() == other.fieldType() || fieldType() == AGNOSTIC) { + elem_ = other.elem_->clone(); + } else if (other.fieldType() != AGNOSTIC) { + GADGETLIB_FATAL("Attempted to assign field element of incorrect type"); + } else { + *elem_ = dynamic_cast(other.elem_.get())->asLong(); + } + return *this; +} + +FElem& FElem::operator=(FElem&& other) { + if (fieldType() == other.fieldType() || fieldType() == AGNOSTIC) { + elem_ = ::std::move(other.elem_); + } else if (other.elem_->fieldType() != AGNOSTIC) { + GADGETLIB_FATAL("Attempted to move assign field element of incorrect type"); + } else { + *elem_ = dynamic_cast(other.elem_.get())->asLong(); + } + return *this; +} + +bool fieldMustBePromotedForArithmetic(const FieldType& lhsField, const FieldType& rhsField) { + if (lhsField == rhsField) return false; + if (rhsField == AGNOSTIC) return false; + return true; +} + +void FElem::promoteToFieldType(FieldType type) { + if (!fieldMustBePromotedForArithmetic(this->fieldType(), type)) { + return; + } + if(type == R1P) { + const FConst* fConst = dynamic_cast(elem_.get()); + GADGETLIB_ASSERT(fConst != NULL, "Cannot convert between specialized field types."); + elem_.reset(new R1P_Elem(fConst->asLong())); + } else { + GADGETLIB_FATAL("Attempted to promote to unknown field type"); + } +} + +FElem& FElem::operator*=(const FElem& other) { + promoteToFieldType(other.fieldType()); + *elem_ *= *other.elem_; + return *this; +} + +FElem& FElem::operator+=(const FElem& other) { + promoteToFieldType(other.fieldType()); + *elem_ += *other.elem_; + return *this; +} + +FElem& FElem::operator-=(const FElem& other) { + promoteToFieldType(other.fieldType()); + *elem_ -= *other.elem_; return *this; +} + +FElem FElem::inverse(const FieldType& fieldType) { + promoteToFieldType(fieldType); + return FElem(*(elem_->inverse())); +} + +int FElem::getBit(unsigned int i, const FieldType& fieldType) { + promoteToFieldType(fieldType); + if (this->fieldType() == fieldType) { + return elem_->getBit(i); + } else { + GADGETLIB_FATAL("Attempted to extract bits from incompatible field type."); + } +} + +FElem power(const FElem& base, long exponent) { // TODO .cpp + FElem retval(base); + retval.elem_->power(exponent); + return retval; +} + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class FConst ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +FConst& FConst::operator+=(const FElemInterface& other) { + contents_ += dynamic_cast(other).contents_; + return *this; +} + +FConst& FConst::operator-=(const FElemInterface& other) { + contents_ -= dynamic_cast(other).contents_; + return *this; +} + +FConst& FConst::operator*=(const FElemInterface& other) { + contents_ *= dynamic_cast(other).contents_; + return *this; +} + +FElemInterfacePtr FConst::inverse() const { + GADGETLIB_FATAL("Attempted to invert an FConst element."); +} + +FElemInterface& FConst::power(long exponent) { + contents_ = 0.5 + ::std::pow(double(contents_), double(exponent)); + return *this; +} + + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class R1P_Elem ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +R1P_Elem& R1P_Elem::operator+=(const FElemInterface& other) { + if (other.fieldType() == R1P) { + elem_ += dynamic_cast(other).elem_; + } else if (other.fieldType() == AGNOSTIC) { + elem_ += dynamic_cast(other).asLong(); + } else { + GADGETLIB_FATAL("Attempted to add incompatible type to R1P_Elem."); + } + return *this; +} + +R1P_Elem& R1P_Elem::operator-=(const FElemInterface& other) { + if (other.fieldType() == R1P) { + elem_ -= dynamic_cast(other).elem_; + } else if (other.fieldType() == AGNOSTIC) { + elem_ -= dynamic_cast(other).asLong(); + } else { + GADGETLIB_FATAL("Attempted to add incompatible type to R1P_Elem."); + } + return *this; +} + +R1P_Elem& R1P_Elem::operator*=(const FElemInterface& other) { + if (other.fieldType() == R1P) { + elem_ *= dynamic_cast(other).elem_; + } else if (other.fieldType() == AGNOSTIC) { + elem_ *= dynamic_cast(other).asLong(); + } else { + GADGETLIB_FATAL("Attempted to add incompatible type to R1P_Elem."); + } + return *this; +} + +bool R1P_Elem::operator==(const FElemInterface& other) const { + const R1P_Elem* pOther = dynamic_cast(&other); + if (pOther) { + return elem_ == pOther->elem_; + } + const FConst* pConst = dynamic_cast(&other); + if (pConst) { + return *this == *pConst; + } + GADGETLIB_FATAL("Attempted to Compare R1P_Elem with incompatible type."); +} + +FElemInterfacePtr R1P_Elem::inverse() const { + return FElemInterfacePtr(new R1P_Elem(elem_.inverse())); +} + +long R1P_Elem::asLong() const { + //GADGETLIB_ASSERT(elem_.as_ulong() <= LONG_MAX, "long overflow occured."); + return long(elem_.as_ulong()); +} + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Variable ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +VarIndex_t Variable::nextFreeIndex_ = 0; + +#ifdef DEBUG +Variable::Variable(const string& name) : index_(nextFreeIndex_++), name_(name) { + GADGETLIB_ASSERT(nextFreeIndex_ > 0, GADGETLIB2_FMT("Variable index overflow has occured, maximum number of " + "Variables is %lu", ULONG_MAX)); +} +#else +Variable::Variable(const string& name) : index_(nextFreeIndex_++) { + UNUSED(name); + GADGETLIB_ASSERT(nextFreeIndex_ > 0, GADGETLIB2_FMT("Variable index overflow has occured, maximum number of " + "Variables is %lu", ULONG_MAX)); +} +#endif + +Variable::~Variable() {}; + +string Variable::name() const { +# ifdef DEBUG + return name_; +# else + return ""; +# endif +} + +FElem Variable::eval(const VariableAssignment& assignment) const { + try { + return assignment.at(*this); + } catch (::std::out_of_range) { + GADGETLIB_FATAL(GADGETLIB2_FMT("Attempted to evaluate unassigned Variable \"%s\", idx:%lu", name().c_str(), + index_)); + } +} + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class VariableArray ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +#ifdef DEBUG +VariableArray::VariableArray(const string& name) : VariableArrayContents(), name_(name) {} +VariableArray::VariableArray(const int size, const ::std::string& name) : VariableArrayContents() { + for (int i = 0; i < size; ++i) { + push_back(Variable(GADGETLIB2_FMT("%s[%d]", name.c_str(), i))); + } +} +VariableArray::VariableArray(const size_t size, const ::std::string& name) : VariableArrayContents() { + for (size_t i = 0; i < size; ++i) { + push_back(Variable(GADGETLIB2_FMT("%s[%d]", name.c_str(), i))); + } +} +::std::string VariableArray::name() const { + return name_; +} + +#else +::std::string VariableArray::name() const { + return ""; +} + +VariableArray::VariableArray(const string& name) : VariableArrayContents() { UNUSED(name); } +VariableArray::VariableArray(const size_t size, const ::std::string& name) + : VariableArrayContents(size) { UNUSED(name); } +VariableArray::VariableArray(const int size, const ::std::string& name) + : VariableArrayContents(size) { UNUSED(name); } +#endif + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* Custom Variable classes ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +MultiPackedWord::MultiPackedWord(const FieldType& fieldType) + : VariableArray(), numBits_(0), fieldType_(fieldType) {} + +MultiPackedWord::MultiPackedWord(const size_t numBits, + const FieldType& fieldType, + const ::std::string& name) + : VariableArray(), numBits_(numBits), fieldType_(fieldType) { + size_t packedSize = getMultipackedSize(); + VariableArray varArray(packedSize, name); + VariableArray::swap(varArray); +} + +void MultiPackedWord::resize(const size_t numBits) { + numBits_ = numBits; + size_t packedSize = getMultipackedSize(); + VariableArray::resize(packedSize); +} + +size_t MultiPackedWord::getMultipackedSize() const { + size_t packedSize = 0; + if (fieldType_ == R1P) { + packedSize = 1; // TODO add assertion that numBits can fit in the field characteristic + } else { + GADGETLIB_FATAL("Unknown field type for packed variable."); + } + return packedSize; +} + +DualWord::DualWord(const size_t numBits, + const FieldType& fieldType, + const ::std::string& name) + : multipacked_(numBits, fieldType, name + "_p"), + unpacked_(numBits, name + "_u") {} + +DualWord::DualWord(const MultiPackedWord& multipacked, const UnpackedWord& unpacked) + : multipacked_(multipacked), unpacked_(unpacked) {} + +void DualWord::resize(size_t newSize) { + multipacked_.resize(newSize); + unpacked_.resize(newSize); +} + +DualWordArray::DualWordArray(const FieldType& fieldType) + : multipackedContents_(0, MultiPackedWord(fieldType)), unpackedContents_(0), + numElements_(0) {} + +DualWordArray::DualWordArray(const MultiPackedWordArray& multipackedContents, // TODO delete, for dev + const UnpackedWordArray& unpackedContents) + : multipackedContents_(multipackedContents), unpackedContents_(unpackedContents), + numElements_(multipackedContents_.size()) { + GADGETLIB_ASSERT(multipackedContents_.size() == numElements_, + "Dual Variable multipacked contents size mismatch"); + GADGETLIB_ASSERT(unpackedContents_.size() == numElements_, + "Dual Variable packed contents size mismatch"); +} + +MultiPackedWordArray DualWordArray::multipacked() const {return multipackedContents_;} +UnpackedWordArray DualWordArray::unpacked() const {return unpackedContents_;} +PackedWordArray DualWordArray::packed() const { + GADGETLIB_ASSERT(numElements_ == multipackedContents_.size(), "multipacked contents size mismatch") + PackedWordArray retval(numElements_); + for(size_t i = 0; i < numElements_; ++i) { + const auto element = multipackedContents_[i]; + GADGETLIB_ASSERT(element.size() == 1, "Cannot convert from multipacked to packed"); + retval[i] = element[0]; + } + return retval; +} + +void DualWordArray::push_back(const DualWord& dualWord) { + multipackedContents_.push_back(dualWord.multipacked()); + unpackedContents_.push_back(dualWord.unpacked()); + ++numElements_; +} + +DualWord DualWordArray::at(size_t i) const { + //const MultiPackedWord multipackedRep = multipacked()[i]; + //const UnpackedWord unpackedRep = unpacked()[i]; + //const DualWord retval(multipackedRep, unpackedRep); + //return retval; + return DualWord(multipacked()[i], unpacked()[i]); +} + +size_t DualWordArray::size() const { + GADGETLIB_ASSERT(multipackedContents_.size() == numElements_, + "Dual Variable multipacked contents size mismatch"); + GADGETLIB_ASSERT(unpackedContents_.size() == numElements_, + "Dual Variable packed contents size mismatch"); + return numElements_; +} + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class LinearTerm ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +::std::string LinearTerm::asString() const { + if (coeff_ == 1) { return variable_.name();} + else if (coeff_ == -1) {return GADGETLIB2_FMT("-1 * %s", variable_.name().c_str());} + else if (coeff_ == 0) {return GADGETLIB2_FMT("0 * %s", variable_.name().c_str());} + else {return GADGETLIB2_FMT("%s * %s", coeff_.asString().c_str(), variable_.name().c_str());} +} + +FElem LinearTerm::eval(const VariableAssignment& assignment) const { + return FElem(coeff_) *= variable_.eval(assignment); +} + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class LinearCombination ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +LinearCombination& LinearCombination::operator+=(const LinearCombination& other) { + linearTerms_.insert(linearTerms_.end(), other.linearTerms_.cbegin(), other.linearTerms_.cend()); + constant_ += other.constant_; + return *this; +} + +LinearCombination& LinearCombination::operator-=(const LinearCombination& other) { + for(const LinearTerm& lt : other.linearTerms_) { + linearTerms_.push_back(-lt); + } + constant_ -= other.constant_; + return *this; +} + +LinearCombination& LinearCombination::operator*=(const FElem& other) { + constant_ *= other; + for (LinearTerm& lt : linearTerms_) { + lt *= other; + } + return *this; +} + +FElem LinearCombination::eval(const VariableAssignment& assignment) const { + FElem evaluation = constant_; + for(const LinearTerm& lt : linearTerms_) { + evaluation += lt.eval(assignment); + } + return evaluation; +} + +::std::string LinearCombination::asString() const { +#ifdef DEBUG + ::std::string retval; + auto it = linearTerms_.begin(); + if (it == linearTerms_.end()) { + return constant_.asString(); + } else { + retval += it->asString(); + } + for(++it; it != linearTerms_.end(); ++it) { + retval += " + " + it->asString(); + } + if (constant_ != 0) { + retval += " + " + constant_.asString(); + } + return retval; +#else // ifdef DEBUG + return ""; +#endif // ifdef DEBUG +} + +const Variable::set LinearCombination::getUsedVariables() const { + Variable::set retSet; + for(const LinearTerm& lt : linearTerms_) { + retSet.insert(lt.variable()); + } + return retSet; +} + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +LinearCombination sum(const VariableArray& inputs) { + LinearCombination retval(0); + for(const Variable& var : inputs) { + retval += var; + } + return retval; +} + +LinearCombination negate(const LinearCombination& lc) { + return (1 - lc); +} + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Monomial ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +Monomial::Monomial(const LinearTerm& linearTerm) + : coeff_(linearTerm.coeff_), variables_() {variables_.insert(linearTerm.variable_);} + +FElem Monomial::eval(const VariableAssignment& assignment) const { + FElem retval = coeff_; + for(const Variable& var : variables_) { + retval *= var.eval(assignment); + } + return retval; +} + +const Variable::set Monomial::getUsedVariables() const { + return Variable::set(variables_.begin(), variables_.end()); +} + +const FElem Monomial::getCoefficient() const{ + return coeff_; +} + +::std::string Monomial::asString() const { +#ifdef DEBUG + if (variables_.size() == 0) { + return coeff_.asString(); + } + string retval; + if (coeff_ != 1) { + retval += coeff_.asString() + "*"; + } + auto iter = variables_.begin(); + retval += iter->name(); + for(++iter; iter != variables_.end(); ++iter) { + retval += "*" + iter->name(); + } + return retval; +#else // ifdef DEBUG + return ""; +#endif // ifdef DEBUG +} + +Monomial Monomial::operator-() const { + Monomial retval = *this; + retval.coeff_ = -retval.coeff_; + return retval; +} + +Monomial& Monomial::operator*=(const Monomial& other) { + coeff_ *= other.coeff_; + variables_.insert(other.variables_.begin(), other.variables_.end()); + return *this; +} + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Polynomial ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +Polynomial::Polynomial(const LinearCombination& linearCombination) + : monomials_(), constant_(linearCombination.constant_) { + for (const LinearTerm& linearTerm : linearCombination.linearTerms_) { + monomials_.push_back(Monomial(linearTerm)); + } +} + +FElem Polynomial::eval(const VariableAssignment& assignment) const { + FElem retval = constant_; + for(const Monomial& monomial : monomials_) { + retval += monomial.eval(assignment); + } + return retval; +} + +const Variable::set Polynomial::getUsedVariables() const { + Variable::set retset; + for(const Monomial& monomial : monomials_) { + const Variable::set curSet = monomial.getUsedVariables(); + retset.insert(curSet.begin(), curSet.end()); + } + return retset; +} + +const vector& Polynomial::getMonomials()const{ + return monomials_; +} + +const FElem Polynomial::getConstant()const{ + return constant_; +} + +::std::string Polynomial::asString() const { +# ifndef DEBUG + return ""; +# endif + if (monomials_.size() == 0) { + return constant_.asString(); + } + string retval; + auto iter = monomials_.begin(); + retval += iter->asString(); + for(++iter; iter != monomials_.end(); ++iter) { + retval += " + " + iter->asString(); + } + if (constant_ != 0) { + retval += " + " + constant_.asString(); + } + return retval; +} + +Polynomial& Polynomial::operator+=(const Polynomial& other) { + constant_ += other.constant_; + monomials_.insert(monomials_.end(), other.monomials_.begin(), other.monomials_.end()); + return *this; +} + +Polynomial& Polynomial::operator*=(const Polynomial& other) { + vector newMonomials; + for(const Monomial& thisMonomial : monomials_) { + for (const Monomial& otherMonomial : other.monomials_) { + newMonomials.push_back(thisMonomial * otherMonomial); + } + newMonomials.push_back(thisMonomial * other.constant_); + } + for (const Monomial& otherMonomial : other.monomials_) { + newMonomials.push_back(otherMonomial * this->constant_); + } + constant_ *= other.constant_; + monomials_ = ::std::move(newMonomials); + return *this; +} + +Polynomial& Polynomial::operator-=(const Polynomial& other) { + constant_ -= other.constant_; + for(const Monomial& otherMonomial : other.monomials_) { + monomials_.push_back(-otherMonomial); + } + return *this; +} + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +} // namespace gadgetlib2 diff --git a/privacy/zsl/zsl/gadgetlib2/variable.d b/privacy/zsl/zsl/gadgetlib2/variable.d new file mode 100644 index 0000000..470a5e6 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/variable.d @@ -0,0 +1,18 @@ +src/gadgetlib2/variable.o: src/gadgetlib2/variable.cpp \ + src/gadgetlib2/variable.hpp src/gadgetlib2/pp.hpp \ + src/common/default_types/ec_pp.hpp src/algebra/curves/bn128/bn128_pp.hpp \ + src/algebra/curves/public_params.hpp \ + src/algebra/curves/bn128/bn128_init.hpp src/algebra/fields/fp.hpp \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/common/utils.hpp src/common/utils.tcc \ + src/algebra/fields/bigint.tcc \ + src/algebra/exponentiation/exponentiation.hpp \ + src/algebra/exponentiation/exponentiation.tcc src/algebra/fields/fp.tcc \ + src/algebra/fields/fp_aux.tcc src/algebra/fields/field_utils.hpp \ + src/algebra/fields/field_utils.tcc depinst/include/bn.h \ + depinst/include/zm2.h depinst/include/zm.h \ + src/algebra/curves/bn128/bn128_g1.hpp src/algebra/curves/curve_utils.hpp \ + src/algebra/curves/curve_utils.tcc src/algebra/curves/bn128/bn128_g2.hpp \ + src/algebra/curves/bn128/bn128_gt.hpp \ + src/algebra/curves/bn128/bn128_pairing.hpp \ + src/gadgetlib2/infrastructure.hpp src/gadgetlib2/variable_operators.hpp diff --git a/privacy/zsl/zsl/gadgetlib2/variable.hpp b/privacy/zsl/zsl/gadgetlib2/variable.hpp new file mode 100644 index 0000000..a09e913 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/variable.hpp @@ -0,0 +1,572 @@ +/** @file + ***************************************************************************** + Declaration of the low level objects needed for field arithmetization. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_VARIABLE_HPP_ +#define LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_VARIABLE_HPP_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "pp.hpp" +#include "infrastructure.hpp" + +namespace gadgetlib2 { + +class GadgetLibAdapter; + +// Forward declarations +class Protoboard; +class FElemInterface; +class FElem; +class FConst; +class Variable; +class VariableArray; + +typedef enum {R1P, AGNOSTIC} FieldType; + +typedef ::std::shared_ptr VariablePtr; +typedef ::std::shared_ptr VariableArrayPtr; +typedef ::std::unique_ptr FElemInterfacePtr; +typedef ::std::shared_ptr ProtoboardPtr; +typedef unsigned long VarIndex_t; + +// Naming Conventions: +// R1P == Rank 1 Prime characteristic + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class FElemInterface ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/** + An interface class for field elements. + Currently 2 classes will derive from this interface: + R1P_Elem - Elements of a field of prime characteristic + FConst - Formally not a field, only placeholders for field agnostic constants, such as 0 and 1. + Can be used for -1 or any other constant which makes semantic sense in all fields. + */ +class FElemInterface { +public: + virtual FElemInterface& operator=(const long n) = 0; + /// FConst will be field agnostic, allowing us to hold values such as 0 and 1 without knowing + /// the underlying field. This assignment operator will convert to the correct field element. + virtual FElemInterface& operator=(const FConst& src) = 0; + virtual ::std::string asString() const = 0; + virtual FieldType fieldType() const = 0; + virtual FElemInterface& operator+=(const FElemInterface& other) = 0; + virtual FElemInterface& operator-=(const FElemInterface& other) = 0; + virtual FElemInterface& operator*=(const FElemInterface& other) = 0; + virtual bool operator==(const FElemInterface& other) const = 0; + virtual bool operator==(const FConst& other) const = 0; + /// This operator is not always mathematically well defined. 'n' will be checked in runtime + /// for fields in which integer values are not well defined. + virtual bool operator==(const long n) const = 0; + /// @returns a unique_ptr to a copy of the current element. + virtual FElemInterfacePtr clone() const = 0; + virtual FElemInterfacePtr inverse() const = 0; + virtual long asLong() const = 0; + virtual int getBit(unsigned int i) const = 0; + virtual FElemInterface& power(long exponent) = 0; + virtual ~FElemInterface(){}; +}; // class FElemInterface + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +inline bool operator==(const long first, const FElemInterface& second) {return second == first;} +inline bool operator!=(const long first, const FElemInterface& second) {return !(first == second);} +inline bool operator!=(const FElemInterface& first, const long second) {return !(first == second);} +inline bool operator!=(const FElemInterface& first, const FElemInterface& second) { + return !(first == second); +} + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class FElem ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/// A wrapper class for field elements. Can hold any derived type of FieldElementInterface +class FElem { +private: + FElemInterfacePtr elem_; + +public: + explicit FElem(const FElemInterface& elem); + /// Helper method. When doing arithmetic between a constant and a field specific element + /// we want to "promote" the constant to the same field. This function changes the unique_ptr + /// to point to a field specific element with the same value as the constant which it held. + void promoteToFieldType(FieldType type); + FElem(); + FElem(const long n); + FElem(const int i); + FElem(const size_t n); + FElem(const Fp& elem); + FElem(const FElem& src); + + FElem& operator=(const FElem& other); + FElem& operator=(FElem&& other); + FElem& operator=(const long i) { *elem_ = i; return *this;} + ::std::string asString() const {return elem_->asString();} + FieldType fieldType() const {return elem_->fieldType();} + bool operator==(const FElem& other) const {return *elem_ == *other.elem_;} + FElem& operator*=(const FElem& other); + FElem& operator+=(const FElem& other); + FElem& operator-=(const FElem& other); + FElem operator-() const {FElem retval(0); retval -= FElem(*elem_); return retval;} + FElem inverse(const FieldType& fieldType); + long asLong() const {return elem_->asLong();} + int getBit(unsigned int i, const FieldType& fieldType); + friend FElem power(const FElem& base, long exponent); + + inline friend ::std::ostream& operator<<(::std::ostream& os, const FElem& elem) { + return os << elem.elem_->asString(); + } + + friend class GadgetLibAdapter; +}; // class FElem + +inline bool operator!=(const FElem& first, const FElem& second) {return !(first == second);} + +/// These operators are not always mathematically well defined. The long will be checked in runtime +/// for fields in which values other than 0 and 1 are not well defined. +inline bool operator==(const FElem& first, const long second) {return first == FElem(second);} +inline bool operator==(const long first, const FElem& second) {return second == first;} +inline bool operator!=(const FElem& first, const long second) {return !(first == second);} +inline bool operator!=(const long first, const FElem& second) {return !(first == second);} + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class FConst ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/** + A field agnostic constant. All fields have constants 1 and 0 and this class allows us to hold + an element agnostically while the context field is not known. For example, when given the + very useful expression '1 - x' where x is a field agnostic formal variable, we must store the + constant '1' without knowing over which field this expression will be evaluated. + Constants can also hold integer values, which will be evaluated if possible, in runtime. For + instance the expression '42 + x' will be evaluated in runtime in the trivial way when working + over the prime characteristic Galois Field GF_43 but will cause a runtime error when evaluated + over a GF2 extension field in which '42' has no obvious meaning, other than being the answer to + life, the universe and everything. +*/ +class FConst : public FElemInterface { +private: + long contents_; + explicit FConst(const long n) : contents_(n) {} +public: + virtual FConst& operator=(const long n) {contents_ = n; return *this;} + virtual FConst& operator=(const FConst& src) {contents_ = src.contents_; return *this;} + virtual ::std::string asString() const {return GADGETLIB2_FMT("%ld",contents_);} + virtual FieldType fieldType() const {return AGNOSTIC;} + virtual FConst& operator+=(const FElemInterface& other); + virtual FConst& operator-=(const FElemInterface& other); + virtual FConst& operator*=(const FElemInterface& other); + virtual bool operator==(const FElemInterface& other) const {return other == *this;} + virtual bool operator==(const FConst& other) const {return contents_ == other.contents_;} + virtual bool operator==(const long n) const {return contents_ == n;} + /// @return a unique_ptr to a new copy of the element + virtual FElemInterfacePtr clone() const {return FElemInterfacePtr(new FConst(*this));} + /// @return a unique_ptr to a new copy of the element's multiplicative inverse + virtual FElemInterfacePtr inverse() const; + long asLong() const {return contents_;} + int getBit(unsigned int i) const { UNUSED(i); GADGETLIB_FATAL("Cannot get bit from FConst."); } + virtual FElemInterface& power(long exponent); + + friend class FElem; // allow constructor call +}; // class FConst + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class R1P_Elem ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/** + Holds elements of a prime characteristic field. Currently implemented using the gmp (linux) and + mpir (windows) libraries. + */ +class R1P_Elem : public FElemInterface { +private: + Fp elem_; +public: + + explicit R1P_Elem(const Fp& elem) : elem_(elem) {} + virtual R1P_Elem& operator=(const FConst& src) {elem_ = src.asLong(); return *this;} + virtual R1P_Elem& operator=(const long n) {elem_ = Fp(n); return *this;} + virtual ::std::string asString() const {return GADGETLIB2_FMT("%u", elem_.as_ulong());} + virtual FieldType fieldType() const {return R1P;} + virtual R1P_Elem& operator+=(const FElemInterface& other); + virtual R1P_Elem& operator-=(const FElemInterface& other); + virtual R1P_Elem& operator*=(const FElemInterface& other); + virtual bool operator==(const FElemInterface& other) const; + virtual bool operator==(const FConst& other) const {return elem_ == Fp(other.asLong());} + virtual bool operator==(const long n) const {return elem_ == Fp(n);} + /// @return a unique_ptr to a new copy of the element + virtual FElemInterfacePtr clone() const {return FElemInterfacePtr(new R1P_Elem(*this));} + /// @return a unique_ptr to a new copy of the element's multiplicative inverse + virtual FElemInterfacePtr inverse() const; + long asLong() const; + int getBit(unsigned int i) const {return elem_.as_bigint().test_bit(i);} + virtual FElemInterface& power(long exponent) {elem_^= exponent; return *this;} + + friend class FElem; // allow constructor call + friend class GadgetLibAdapter; +}; + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Variable ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/** + @brief A formal variable, field agnostic. + + Each variable is specified by an index. This can be imagined as the index in x_1, x_2,..., x_i + These are formal variables and do not hold an assignment, later the class VariableAssignment + will give each formal variable its own assignment. + Variables have no comparison and assignment operators as evaluating (x_1 == x_2) has no sense + without specific assignments. + Variables are field agnostic, this means they can be used regardless of the context field, + which will also be determined by the assignment. + */ +class Variable { +private: + VarIndex_t index_; ///< This index differentiates and identifies Variable instances. + static VarIndex_t nextFreeIndex_; ///< Monotonically-increasing counter to allocate disinct indices. +#ifdef DEBUG + ::std::string name_; +#endif + + /** + * @brief allocates the variable + */ +public: + explicit Variable(const ::std::string& name = ""); + virtual ~Variable(); + + ::std::string name() const; + + /// A functor for strict ordering of Variables. Needed for STL containers. + /// This is not an ordering of Variable assignments and has no semantic meaning. + struct VariableStrictOrder { + bool operator()(const Variable& first, const Variable& second)const { + return first.index_ < second.index_; + } + }; + + typedef ::std::map VariableAssignment; + FElem eval(const VariableAssignment& assignment) const; + + /// A set of Variables should be declared as follows: Variable::set s1; + typedef ::std::set set; + typedef ::std::multiset multiset; + + friend class GadgetLibAdapter; +}; // class Variable +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +typedef ::std::map VariableAssignment; + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class VariableArray ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +typedef ::std::vector VariableArrayContents; + +class VariableArray : public VariableArrayContents { +private: +# ifdef DEBUG + ::std::string name_; +# endif +public: + explicit VariableArray(const ::std::string& name = ""); + explicit VariableArray(const int size, const ::std::string& name = ""); + explicit VariableArray(const size_t size, const ::std::string& name = ""); + explicit VariableArray(const size_t size, const Variable& contents) + : VariableArrayContents(size, contents) {} + + using VariableArrayContents::operator[]; + using VariableArrayContents::at; + using VariableArrayContents::push_back; + using VariableArrayContents::size; + + ::std::string name() const; +}; // class VariableArray + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* Custom Variable classes ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +typedef Variable FlagVariable; ///< Holds variable whos purpose is to be populated with a boolean + ///< value, Field(0) or Field(1) +typedef VariableArray FlagVariableArray; +typedef Variable PackedWord; ///< Represents a packed word that can fit in a field element. + ///< For a word representing an unsigned integer for instance this + ///< means we require (int < fieldSize) +typedef VariableArray PackedWordArray; + +/// Holds variables whos purpose is to be populated with the unpacked form of some word, bit by bit +class UnpackedWord : public VariableArray { +public: + UnpackedWord() : VariableArray() {} + UnpackedWord(const size_t numBits, const ::std::string& name) : VariableArray(numBits, name) {} +}; // class UnpackedWord + +typedef ::std::vector UnpackedWordArray; + +/// Holds variables whos purpose is to be populated with the packed form of some word. +/// word representation can be larger than a single field element in small enough fields +class MultiPackedWord : public VariableArray { +private: + size_t numBits_; + FieldType fieldType_; + size_t getMultipackedSize() const; +public: + MultiPackedWord(const FieldType& fieldType = AGNOSTIC); + MultiPackedWord(const size_t numBits, const FieldType& fieldType, const ::std::string& name); + void resize(const size_t numBits); + ::std::string name() const {return VariableArray::name();} +}; // class MultiPackedWord + +typedef ::std::vector MultiPackedWordArray; + +/// Holds both representations of a word, both multipacked and unpacked +class DualWord { +private: + MultiPackedWord multipacked_; + UnpackedWord unpacked_; +public: + DualWord(const FieldType& fieldType) : multipacked_(fieldType), unpacked_() {} + DualWord(const size_t numBits, const FieldType& fieldType, const ::std::string& name); + DualWord(const MultiPackedWord& multipacked, const UnpackedWord& unpacked); + MultiPackedWord multipacked() const {return multipacked_;} + UnpackedWord unpacked() const {return unpacked_;} + FlagVariable bit(size_t i) const {return unpacked_[i];} //syntactic sugar, same as unpacked()[i] + size_t numBits() const { return unpacked_.size(); } + void resize(size_t newSize); +}; // class DualWord + +class DualWordArray { +private: + // kept as 2 seperate arrays because the more common usecase will be to request one of these, + // and not dereference a specific DualWord + MultiPackedWordArray multipackedContents_; + UnpackedWordArray unpackedContents_; + size_t numElements_; +public: + DualWordArray(const FieldType& fieldType); + DualWordArray(const MultiPackedWordArray& multipackedContents, // TODO delete, for dev + const UnpackedWordArray& unpackedContents); + MultiPackedWordArray multipacked() const; + UnpackedWordArray unpacked() const; + PackedWordArray packed() const; //< For cases in which we can assume each unpacked value fits + //< in 1 packed Variable + void push_back(const DualWord& dualWord); + DualWord at(size_t i) const; + size_t size() const; +}; // class DualWordArray + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class LinearTerm ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +class LinearTerm { +private: + Variable variable_; + FElem coeff_; +public: + LinearTerm(const Variable& v) : variable_(v), coeff_(1) {} + LinearTerm(const Variable& v, const FElem& coeff) : variable_(v), coeff_(coeff) {} + LinearTerm(const Variable& v, long n) : variable_(v), coeff_(n) {} + LinearTerm operator-() const {return LinearTerm(variable_, -coeff_);} + LinearTerm& operator*=(const FElem& other) {coeff_ *= other; return *this;} + FieldType fieldtype() const {return coeff_.fieldType();} + ::std::string asString() const; + FElem eval(const VariableAssignment& assignment) const; + Variable variable() const {return variable_;} + + friend class Monomial; + friend class GadgetLibAdapter; +}; // class LinearTerm + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class LinearCombination ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +class LinearCombination { +protected: + ::std::vector linearTerms_; + FElem constant_; + typedef ::std::vector::size_type size_type; +public: + LinearCombination() : linearTerms_(), constant_(0) {} + LinearCombination(const Variable& var) : linearTerms_(1,var), constant_(0) {} + LinearCombination(const LinearTerm& linTerm) : linearTerms_(1,linTerm), constant_(0) {} + LinearCombination(long i) : linearTerms_(), constant_(i) {} + LinearCombination(const FElem& elem) : linearTerms_(), constant_(elem) {} + + LinearCombination& operator+=(const LinearCombination& other); + LinearCombination& operator-=(const LinearCombination& other); + LinearCombination& operator*=(const FElem& other); + FElem eval(const VariableAssignment& assignment) const; + ::std::string asString() const; + const Variable::set getUsedVariables() const; + + friend class Polynomial; + friend class GadgetLibAdapter; +}; // class LinearCombination + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +inline LinearCombination operator-(const LinearCombination& lc){return LinearCombination(0) -= lc;} + +LinearCombination sum(const VariableArray& inputs); +//TODO : change this to member function +LinearCombination negate(const LinearCombination& lc); + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Monomial ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +class Monomial { +private: + FElem coeff_; + Variable::multiset variables_; // currently just a vector of variables. This can + // surely be optimized e.g. hold a variable-degree pair + // but is not needed for concrete efficiency as we will + // only be invoking degree 2 constraints in the near + // future. +public: + Monomial(const Variable& var) : coeff_(1), variables_() {variables_.insert(var);} + Monomial(const Variable& var, const FElem& coeff) : coeff_(coeff), variables_() {variables_.insert(var);} + Monomial(const FElem& val) : coeff_(val), variables_() {} + Monomial(const LinearTerm& linearTerm); + + FElem eval(const VariableAssignment& assignment) const; + const Variable::set getUsedVariables() const; + const FElem getCoefficient() const; + ::std::string asString() const; + Monomial operator-() const; + Monomial& operator*=(const Monomial& other); +}; // class Monomial + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Polynomial ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +class Polynomial { +private: + ::std::vector monomials_; + FElem constant_; +public: + Polynomial() : monomials_(), constant_(0) {} + Polynomial(const Monomial& monomial) : monomials_(1, monomial), constant_(0) {} + Polynomial(const Variable& var) : monomials_(1, Monomial(var)), constant_(0) {} + Polynomial(const FElem& val) : monomials_(), constant_(val) {} + Polynomial(const LinearCombination& linearCombination); + Polynomial(const LinearTerm& linearTerm) : monomials_(1, Monomial(linearTerm)), constant_(0) {} + Polynomial(int i) : monomials_(), constant_(i) {} + + FElem eval(const VariableAssignment& assignment) const; + const Variable::set getUsedVariables() const; + const std::vector& getMonomials()const; + const FElem getConstant()const; + ::std::string asString() const; + Polynomial& operator+=(const Polynomial& other); + Polynomial& operator*=(const Polynomial& other); + Polynomial& operator-=(const Polynomial& other); + Polynomial& operator+=(const LinearTerm& other) {return *this += Polynomial(Monomial(other));} +}; // class Polynomial + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +inline Polynomial operator-(const Polynomial& src) {return Polynomial(FElem(0)) -= src;} + +} // namespace gadgetlib2 + +#include "variable_operators.hpp" + +#endif // LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_VARIABLE_HPP_ diff --git a/privacy/zsl/zsl/gadgetlib2/variable_operators.hpp b/privacy/zsl/zsl/gadgetlib2/variable_operators.hpp new file mode 100644 index 0000000..87f2343 --- /dev/null +++ b/privacy/zsl/zsl/gadgetlib2/variable_operators.hpp @@ -0,0 +1,225 @@ +/** @file + ***************************************************************************** + Holds all of the arithmetic operators for the classes declared in variable.hpp . + + This take clutter out of variable.hpp while leaving the * operators in a header file, + thus allowing them to be inlined, for optimization purposes. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_VARIABLEOPERATORS_HPP_ +#define LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_VARIABLEOPERATORS_HPP_ + +#include "variable.hpp" + +namespace gadgetlib2 { + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* lots o' operators ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/***********************************/ +/*** operator+ ***/ +/***********************************/ + +// Polynomial +inline Polynomial operator+(const Polynomial& first, const Polynomial& second) {auto retval = first; return retval += second;} + +// Monomial +inline Polynomial operator+(const Monomial& first, const Polynomial& second) {return Polynomial(first) + second;} +inline Polynomial operator+(const Monomial& first, const Monomial& second) {return Polynomial(first) + Polynomial(second);} + +// LinearCombination +inline Polynomial operator+(const LinearCombination& first, const Polynomial& second) {return Polynomial(first) + second;} +inline Polynomial operator+(const LinearCombination& first, const Monomial& second) {return Polynomial(first) + second;} +inline LinearCombination operator+(const LinearCombination& first, const LinearCombination& second) {auto retval = first; return retval += second;} + +// LinearTerm +inline Polynomial operator+(const LinearTerm& first, const Polynomial& second) {return LinearCombination(first) + second;} +inline Polynomial operator+(const LinearTerm& first, const Monomial& second) {return LinearCombination(first) + second;} +inline LinearCombination operator+(const LinearTerm& first, const LinearCombination& second) {return LinearCombination(first) + second;} +inline LinearCombination operator+(const LinearTerm& first, const LinearTerm& second) {return LinearCombination(first) + LinearCombination(second);} + +// Variable +inline Polynomial operator+(const Variable& first, const Polynomial& second) {return LinearTerm(first) + second;} +inline Polynomial operator+(const Variable& first, const Monomial& second) {return LinearTerm(first) + second;} +inline LinearCombination operator+(const Variable& first, const LinearCombination& second) {return LinearTerm(first) + second;} +inline LinearCombination operator+(const Variable& first, const LinearTerm& second) {return LinearTerm(first) + second;} +inline LinearCombination operator+(const Variable& first, const Variable& second) {return LinearTerm(first) + LinearTerm(second);} + +// FElem +inline Polynomial operator+(const FElem& first, const Polynomial& second) {return LinearCombination(first) + second;} +inline Polynomial operator+(const FElem& first, const Monomial& second) {return LinearCombination(first) + second;} +inline LinearCombination operator+(const FElem& first, const LinearCombination& second) {return LinearCombination(first) + second;} +inline LinearCombination operator+(const FElem& first, const LinearTerm& second) {return LinearCombination(first) + LinearCombination(second);} +inline LinearCombination operator+(const FElem& first, const Variable& second) {return LinearCombination(first) + LinearCombination(second);} +inline FElem operator+(const FElem& first, const FElem& second) {auto retval = first; return retval += second;} + +// int +inline FElem operator+(const int first, const FElem& second) {return FElem(first) + second;} +inline LinearCombination operator+(const int first, const Variable& second) {return FElem(first) + second;} +inline LinearCombination operator+(const int first, const LinearTerm& second) {return FElem(first) + second;} +inline LinearCombination operator+(const int first, const LinearCombination& second) {return FElem(first) + second;} +inline Polynomial operator+(const int first, const Monomial& second) {return FElem(first) + second;} +inline Polynomial operator+(const int first, const Polynomial& second) {return FElem(first) + second;} + +// symetrical operators +inline Polynomial operator+(const Polynomial& first, const Monomial& second) {return second + first;} +inline Polynomial operator+(const Monomial& first, const LinearCombination& second) {return second + first;} +inline Polynomial operator+(const Polynomial& first, const LinearCombination& second) {return second + first;} +inline LinearCombination operator+(const LinearCombination& first, const LinearTerm& second) {return second + first;} +inline Polynomial operator+(const Monomial& first, const LinearTerm& second) {return second + first;} +inline Polynomial operator+(const Polynomial& first, const LinearTerm& second) {return second + first;} +inline LinearCombination operator+(const LinearTerm& first, const Variable& second) {return second + first;} +inline LinearCombination operator+(const LinearCombination& first, const Variable& second) {return second + first;} +inline Polynomial operator+(const Monomial& first, const Variable& second) {return second + first;} +inline Polynomial operator+(const Polynomial& first, const Variable& second) {return second + first;} +inline LinearCombination operator+(const Variable& first, const FElem& second) {return second + first;} +inline LinearCombination operator+(const LinearTerm& first, const FElem& second) {return second + first;} +inline LinearCombination operator+(const LinearCombination& first, const FElem& second) {return second + first;} +inline Polynomial operator+(const Monomial& first, const FElem& second) {return second + first;} +inline Polynomial operator+(const Polynomial& first, const FElem& second) {return second + first;} +inline FElem operator+(const FElem& first, const int second) {return second + first;} +inline LinearCombination operator+(const Variable& first, const int second) {return second + first;} +inline LinearCombination operator+(const LinearTerm& first, const int second) {return second + first;} +inline LinearCombination operator+(const LinearCombination& first, const int second) {return second + first;} +inline Polynomial operator+(const Monomial& first, const int second) {return second + first;} +inline Polynomial operator+(const Polynomial& first, const int second) {return second + first;} + +/***********************************/ +/*** operator- ***/ +/***********************************/ +inline LinearTerm operator-(const Variable& src) {return LinearTerm(src, -1);} + +inline Polynomial operator-(const Polynomial& first, const Polynomial& second) {return first + (-second);} +inline Polynomial operator-(const Monomial& first, const Polynomial& second) {return first + (-second);} +inline Polynomial operator-(const Monomial& first, const Monomial& second) {return first + (-second);} +inline Polynomial operator-(const LinearCombination& first, const Polynomial& second) {return first + (-second);} +inline Polynomial operator-(const LinearCombination& first, const Monomial& second) {return first + (-second);} +inline LinearCombination operator-(const LinearCombination& first, const LinearCombination& second) {return first + (-second);} +inline Polynomial operator-(const LinearTerm& first, const Polynomial& second) {return first + (-second);} +inline Polynomial operator-(const LinearTerm& first, const Monomial& second) {return first + (-second);} +inline LinearCombination operator-(const LinearTerm& first, const LinearCombination& second) {return first + (-second);} +inline LinearCombination operator-(const LinearTerm& first, const LinearTerm& second) {return first + (-second);} +inline Polynomial operator-(const Variable& first, const Polynomial& second) {return first + (-second);} +inline Polynomial operator-(const Variable& first, const Monomial& second) {return first + (-second);} +inline LinearCombination operator-(const Variable& first, const LinearCombination& second) {return first + (-second);} +inline LinearCombination operator-(const Variable& first, const LinearTerm& second) {return first + (-second);} +inline LinearCombination operator-(const Variable& first, const Variable& second) {return first + (-second);} +inline Polynomial operator-(const FElem& first, const Polynomial& second) {return first + (-second);} +inline Polynomial operator-(const FElem& first, const Monomial& second) {return first + (-second);} +inline LinearCombination operator-(const FElem& first, const LinearCombination& second) {return first + (-second);} +inline LinearCombination operator-(const FElem& first, const LinearTerm& second) {return first + (-second);} +inline LinearCombination operator-(const FElem& first, const Variable& second) {return first + (-second);} +inline FElem operator-(const FElem& first, const FElem& second) {return first + (-second);} +inline FElem operator-(const int first, const FElem& second) {return first + (-second);} +inline LinearCombination operator-(const int first, const Variable& second) {return first + (-second);} +inline LinearCombination operator-(const int first, const LinearTerm& second) {return first + (-second);} +inline LinearCombination operator-(const int first, const LinearCombination& second) {return first + (-second);} +inline Polynomial operator-(const int first, const Monomial& second) {return first + (-second);} +inline Polynomial operator-(const int first, const Polynomial& second) {return first + (-second);} +inline Polynomial operator-(const Polynomial& first, const Monomial& second) {return first + (-second);} +inline Polynomial operator-(const Monomial& first, const LinearCombination& second) {return first + (-second);} +inline Polynomial operator-(const Polynomial& first, const LinearCombination& second) {return first + (-second);} +inline LinearCombination operator-(const LinearCombination& first, const LinearTerm& second) {return first + (-second);} +inline Polynomial operator-(const Monomial& first, const LinearTerm& second) {return first + (-second);} +inline Polynomial operator-(const Polynomial& first, const LinearTerm& second) {return first + (-second);} +inline LinearCombination operator-(const LinearTerm& first, const Variable& second) {return first + (-second);} +inline LinearCombination operator-(const LinearCombination& first, const Variable& second) {return first + (-second);} +inline Polynomial operator-(const Monomial& first, const Variable& second) {return first + (-second);} +inline Polynomial operator-(const Polynomial& first, const Variable& second) {return first + (-second);} +inline LinearCombination operator-(const Variable& first, const FElem& second) {return first + (-second);} +inline LinearCombination operator-(const LinearTerm& first, const FElem& second) {return first + (-second);} +inline LinearCombination operator-(const LinearCombination& first, const FElem& second) {return first + (-second);} +inline Polynomial operator-(const Monomial& first, const FElem& second) {return first + (-second);} +inline Polynomial operator-(const Polynomial& first, const FElem& second) {return first + (-second);} +inline FElem operator-(const FElem& first, const int second) {return first + (-second);} +inline LinearCombination operator-(const Variable& first, const int second) {return first + (-second);} +inline LinearCombination operator-(const LinearTerm& first, const int second) {return first + (-second);} +inline LinearCombination operator-(const LinearCombination& first, const int second) {return first + (-second);} +inline Polynomial operator-(const Monomial& first, const int second) {return first + (-second);} +inline Polynomial operator-(const Polynomial& first, const int second) {return first + (-second);} + +/***********************************/ +/*** operator* ***/ +/***********************************/ + +// Polynomial +inline Polynomial operator*(const Polynomial& first, const Polynomial& second) {auto retval = first; return retval *= second;} + +// Monomial +inline Polynomial operator*(const Monomial& first, const Polynomial& second) {return Polynomial(first) * second;} +inline Monomial operator*(const Monomial& first, const Monomial& second) {auto retval = first; return retval *= second;} + +// LinearCombination +inline Polynomial operator*(const LinearCombination& first, const Polynomial& second) {return Polynomial(first) * second;} +inline Polynomial operator*(const LinearCombination& first, const Monomial& second) {return first * Polynomial(second);} +inline Polynomial operator*(const LinearCombination& first, const LinearCombination& second) {return first * Polynomial(second);} + +// LinearTerm +inline Polynomial operator*(const LinearTerm& first, const Polynomial& second) {return LinearCombination(first) * second;} +inline Monomial operator*(const LinearTerm& first, const Monomial& second) {return Monomial(first) * second;} +inline Polynomial operator*(const LinearTerm& first, const LinearCombination& second) {return LinearCombination(first) * second;} +inline Monomial operator*(const LinearTerm& first, const LinearTerm& second) {return Monomial(first) * Monomial(second);} + +// Variable +inline Polynomial operator*(const Variable& first, const Polynomial& second) {return LinearTerm(first) * second;} +inline Monomial operator*(const Variable& first, const Monomial& second) {return Monomial(first) * second;} +inline Polynomial operator*(const Variable& first, const LinearCombination& second) {return LinearTerm(first) * second;} +inline Monomial operator*(const Variable& first, const LinearTerm& second) {return LinearTerm(first) * second;} +inline Monomial operator*(const Variable& first, const Variable& second) {return LinearTerm(first) * LinearTerm(second);} + +// FElem +inline Polynomial operator*(const FElem& first, const Polynomial& second) {return LinearCombination(first) * second;} +inline Monomial operator*(const FElem& first, const Monomial& second) {return Monomial(first) * second;} +inline LinearCombination operator*(const FElem& first, const LinearCombination& second) {auto retval = second; return retval *= first;} +inline LinearTerm operator*(const FElem& first, const LinearTerm& second) {auto retval = second; return retval *= first;} +inline LinearTerm operator*(const FElem& first, const Variable& second) {return LinearTerm(second) *= first;} +inline FElem operator*(const FElem& first, const FElem& second) {auto retval = first; return retval *= second;} + +// int +inline FElem operator*(const int first, const FElem& second) {return FElem(first) * second;} +inline LinearTerm operator*(const int first, const Variable& second) {return FElem(first) * second;} +inline LinearTerm operator*(const int first, const LinearTerm& second) {return FElem(first) * second;} +inline LinearCombination operator*(const int first, const LinearCombination& second) {return FElem(first) * second;} +inline Monomial operator*(const int first, const Monomial& second) {return FElem(first) * second;} +inline Polynomial operator*(const int first, const Polynomial& second) {return FElem(first) * second;} + +// symetrical operators +inline Polynomial operator*(const Polynomial& first, const Monomial& second) {return second * first;} +inline Polynomial operator*(const Monomial& first, const LinearCombination& second) {return second * first;} +inline Polynomial operator*(const Polynomial& first, const LinearCombination& second) {return second * first;} +inline Polynomial operator*(const LinearCombination& first, const LinearTerm& second) {return second * first;} +inline Monomial operator*(const Monomial& first, const LinearTerm& second) {return second * first;} +inline Polynomial operator*(const Polynomial& first, const LinearTerm& second) {return second * first;} +inline Monomial operator*(const LinearTerm& first, const Variable& second) {return second * first;} +inline Polynomial operator*(const LinearCombination& first, const Variable& second) {return second * first;} +inline Monomial operator*(const Monomial& first, const Variable& second) {return second * first;} +inline Polynomial operator*(const Polynomial& first, const Variable& second) {return second * first;} +inline LinearTerm operator*(const Variable& first, const FElem& second) {return second * first;} +inline LinearTerm operator*(const LinearTerm& first, const FElem& second) {return second * first;} +inline LinearCombination operator*(const LinearCombination& first, const FElem& second) {return second * first;} +inline Monomial operator*(const Monomial& first, const FElem& second) {return second * first;} +inline Polynomial operator*(const Polynomial& first, const FElem& second) {return second * first;} +inline FElem operator*(const FElem& first, const int second) {return second * first;} +inline LinearTerm operator*(const Variable& first, const int second) {return second * first;} +inline LinearTerm operator*(const LinearTerm& first, const int second) {return second * first;} +inline LinearCombination operator*(const LinearCombination& first, const int second) {return second * first;} +inline Monomial operator*(const Monomial& first, const int second) {return second * first;} +inline Polynomial operator*(const Polynomial& first, const int second) {return second * first;} + + +/***********************************/ +/*** END OF OPERATORS ***/ +/***********************************/ + +} // namespace gadgetlib2 + +#endif // LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_VARIABLEOPERATORS_HPP_ diff --git a/privacy/zsl/zsl/gadgets.tcc b/privacy/zsl/zsl/gadgets.tcc new file mode 100644 index 0000000..6b12b74 --- /dev/null +++ b/privacy/zsl/zsl/gadgets.tcc @@ -0,0 +1,1253 @@ +// Copyright 2017 Zerocoin Electric Coin Company LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "common/default_types/r1cs_ppzksnark_pp.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" +#include "gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp" +#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp" + +#include + +template +pb_variable_array from_bits(std::vector bits, pb_variable& ZERO) { + pb_variable_array acc; + + BOOST_FOREACH(bool bit, bits) { + acc.emplace_back(bit ? ONE : ZERO); + } + + return acc; +} + +std::vector convertIntToVectorLE(const uint64_t val_int) { + std::vector bytes; + + for(size_t i = 0; i < 8; i++) { + bytes.push_back(val_int >> (i * 8)); + } + + return bytes; +} + +// Convert bytes into boolean vector. (MSB to LSB) +std::vector convertBytesVectorToVector(const std::vector& bytes) { + std::vector ret; + ret.resize(bytes.size() * 8); + + unsigned char c; + for (size_t i = 0; i < bytes.size(); i++) { + c = bytes.at(i); + for (size_t j = 0; j < 8; j++) { + ret.at((i*8)+j) = (c >> (7-j)) & 1; + } + } + + return ret; +} + +// Convert boolean vector (big endian) to integer +uint64_t convertVectorToInt(const std::vector& v) { + if (v.size() > 64) { + throw std::length_error ("boolean vector can't be larger than 64 bits"); + } + + uint64_t result = 0; + for (size_t i=0; i uint64_to_bool_vector(uint64_t input) { + auto num_bv = convertIntToVectorLE(input); + + return convertBytesVectorToVector(num_bv); +} + +template +class KeyHasher : gadget { +private: + std::shared_ptr> block; + std::shared_ptr> hasher; + +public: + KeyHasher( + protoboard &pb, + pb_variable& ZERO, + pb_variable_array sk, + std::shared_ptr> pk + ) : gadget(pb) { + pb_linear_combination_array IV = SHA256_default_IV(pb); + + pb_variable_array length_padding = + from_bits({ + // padding + 1,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,1, + 0,0,0,0,0,0,0,0 + }, ZERO); + + block.reset(new block_variable(pb, { + sk, + length_padding + }, "")); + + hasher.reset(new sha256_compression_function_gadget( + pb, + IV, + block->bits, + *pk, + "")); + } + + void generate_r1cs_constraints() { + hasher->generate_r1cs_constraints(); + } + + void generate_r1cs_witness() { + hasher->generate_r1cs_witness(); + } +}; + +template +class SendNullifier : gadget { +private: + std::shared_ptr> block; + std::shared_ptr> hasher; + +public: + SendNullifier( + protoboard &pb, + pb_variable& ZERO, + pb_variable_array rho, + std::shared_ptr> result + ) : gadget(pb) { + pb_linear_combination_array IV = SHA256_default_IV(pb); + + pb_variable_array discriminants; + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + + pb_variable_array length_padding = + from_bits({ + // padding + 1,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,1, + 0,0,0,0,1,0,0,0 + }, ZERO); + + block.reset(new block_variable(pb, { + discriminants, + rho, + length_padding + }, "")); + + hasher.reset(new sha256_compression_function_gadget( + pb, + IV, + block->bits, + *result, + "")); + } + + void generate_r1cs_constraints() { + hasher->generate_r1cs_constraints(); + } + + void generate_r1cs_witness() { + hasher->generate_r1cs_witness(); + } +}; + +template +class SpendNullifier : gadget { +private: + std::shared_ptr> block1; + std::shared_ptr> hasher1; + std::shared_ptr> intermediate; + std::shared_ptr> block2; + std::shared_ptr> hasher2; + +public: + SpendNullifier( + protoboard &pb, + pb_variable& ZERO, + pb_variable_array rho, + pb_variable_array sk, + std::shared_ptr> result + ) : gadget(pb) { + pb_linear_combination_array IV = SHA256_default_IV(pb); + + pb_variable_array discriminants; + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ONE); + + block1.reset(new block_variable(pb, { + discriminants, + rho, + pb_variable_array(sk.begin(), sk.begin() + 248) + }, "")); + + intermediate.reset(new digest_variable(pb, 256, "")); + + hasher1.reset(new sha256_compression_function_gadget( + pb, + IV, + block1->bits, + *intermediate, + "")); + + pb_variable_array length_padding = + from_bits({ + // padding + 1,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,1,0, + 0,0,0,0,1,0,0,0 + }, ZERO); + + block2.reset(new block_variable(pb, { + pb_variable_array(sk.begin() + 248, sk.end()), + length_padding + }, "")); + + pb_linear_combination_array IV2(intermediate->bits); + + hasher2.reset(new sha256_compression_function_gadget( + pb, + IV2, + block2->bits, + *result, + "")); + } + + void generate_r1cs_constraints() { + hasher1->generate_r1cs_constraints(); + hasher2->generate_r1cs_constraints(); + } + + void generate_r1cs_witness() { + hasher1->generate_r1cs_witness(); + hasher2->generate_r1cs_witness(); + } +}; + +template +class NoteCommitment : gadget { +private: + std::shared_ptr> block1; + std::shared_ptr> hasher1; + std::shared_ptr> intermediate; + std::shared_ptr> block2; + std::shared_ptr> hasher2; + +public: + NoteCommitment( + protoboard &pb, + pb_variable& ZERO, + pb_variable_array rho, + pb_variable_array pk, + pb_variable_array value, + std::shared_ptr> result + ) : gadget(pb) { + pb_linear_combination_array IV = SHA256_default_IV(pb); + + block1.reset(new block_variable(pb, { + rho, + pk + }, "")); + + intermediate.reset(new digest_variable(pb, 256, "")); + + hasher1.reset(new sha256_compression_function_gadget( + pb, + IV, + block1->bits, + *intermediate, + "")); + + pb_variable_array length_padding = + from_bits({ + // padding + 1,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,1,0, + 0,1,0,0,0,0,0,0 + }, ZERO); + + block2.reset(new block_variable(pb, { + value, + length_padding + }, "")); + + pb_linear_combination_array IV2(intermediate->bits); + + hasher2.reset(new sha256_compression_function_gadget( + pb, + IV2, + block2->bits, + *result, + "")); + } + + void generate_r1cs_constraints() { + hasher1->generate_r1cs_constraints(); + hasher2->generate_r1cs_constraints(); + } + + void generate_r1cs_witness() { + hasher1->generate_r1cs_witness(); + hasher2->generate_r1cs_witness(); + } +}; + +template +class ShieldingCircuit : gadget { +private: + // Verifier inputs + pb_variable_array zk_packed_inputs; + pb_variable_array zk_unpacked_inputs; + std::shared_ptr> unpacker; + + // SHA256(0x00 | rho) + std::shared_ptr> send_nullifier; + // The note commitment: SHA256(rho | pk | value) + std::shared_ptr> cm; + // 64-bit value + pb_variable_array value; + + // Aux inputs + pb_variable ZERO; + std::shared_ptr> rho; + std::shared_ptr> pk; + + // Note commitment hasher + std::shared_ptr> cm_hasher; + + // Send nullifier hasher + std::shared_ptr> nf_hasher; + +public: + ShieldingCircuit(protoboard &pb) : gadget(pb) { + // Inputs + { + zk_packed_inputs.allocate(pb, verifying_field_element_size()); + pb.set_input_sizes(verifying_field_element_size()); + + send_nullifier.reset(new digest_variable(pb, 256, "")); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), send_nullifier->bits.begin(), send_nullifier->bits.end()); + + cm.reset(new digest_variable(pb, 256, "")); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), cm->bits.begin(), cm->bits.end()); + + value.allocate(pb, 64, ""); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), value.begin(), value.end()); + + assert(zk_unpacked_inputs.size() == verifying_input_bit_size()); + + unpacker.reset(new multipacking_gadget( + pb, + zk_unpacked_inputs, + zk_packed_inputs, + FieldT::capacity(), + "unpacker" + )); + } + + // Aux + ZERO.allocate(pb); + rho.reset(new digest_variable(pb, 256, "")); + pk.reset(new digest_variable(pb, 256, "")); + + cm_hasher.reset(new NoteCommitment(pb, ZERO, rho->bits, pk->bits, value, cm)); + nf_hasher.reset(new SendNullifier(pb, ZERO, rho->bits, send_nullifier)); + } + + void generate_r1cs_constraints() { + unpacker->generate_r1cs_constraints(true); + generate_r1cs_equals_const_constraint(this->pb, ZERO, FieldT::zero(), "ZERO"); + + rho->generate_r1cs_constraints(); + pk->generate_r1cs_constraints(); + + cm_hasher->generate_r1cs_constraints(); + nf_hasher->generate_r1cs_constraints(); + } + + void generate_r1cs_witness( + const std::vector& witness_rho, + const std::vector& witness_pk, + uint64_t witness_value + ) { + this->pb.val(ZERO) = FieldT::zero(); + + rho->bits.fill_with_bits( + this->pb, + convertBytesVectorToVector(witness_rho) + ); + + pk->bits.fill_with_bits( + this->pb, + convertBytesVectorToVector(witness_pk) + ); + + value.fill_with_bits( + this->pb, + uint64_to_bool_vector(witness_value) + ); + + cm_hasher->generate_r1cs_witness(); + nf_hasher->generate_r1cs_witness(); + + unpacker->generate_r1cs_witness_from_bits(); + } + + static r1cs_primary_input witness_map( + const std::vector &witness_nf, + const std::vector &witness_cm, + uint64_t witness_value + ) { + std::vector verify_inputs; + + std::vector nf_bits = convertBytesVectorToVector(witness_nf); + std::vector cm_bits = convertBytesVectorToVector(witness_cm); + std::vector value_bits = uint64_to_bool_vector(witness_value); + + verify_inputs.insert(verify_inputs.end(), nf_bits.begin(), nf_bits.end()); + verify_inputs.insert(verify_inputs.end(), cm_bits.begin(), cm_bits.end()); + verify_inputs.insert(verify_inputs.end(), value_bits.begin(), value_bits.end()); + + assert(verify_inputs.size() == verifying_input_bit_size()); + auto verify_field_elements = pack_bit_vector_into_field_element_vector(verify_inputs); + assert(verify_field_elements.size() == verifying_field_element_size()); + return verify_field_elements; + } + + static size_t verifying_field_element_size() { + return div_ceil(verifying_input_bit_size(), FieldT::capacity()); + } + + static size_t verifying_input_bit_size() { + size_t acc = 0; + + acc += 256; // the nullifier + acc += 256; // the note commitment + acc += 64; // the value of the note + + return acc; + } +}; + +#define INCREMENTAL_MERKLE_TREE_DEPTH 29 + +template +class merkle_tree_gadget : gadget { +private: + typedef sha256_two_to_one_hash_gadget sha256_gadget; + + pb_variable_array positions; + std::shared_ptr> authvars; + std::shared_ptr> auth; + +public: + merkle_tree_gadget( + protoboard& pb, + digest_variable leaf, + digest_variable root, + pb_variable& enforce + ) : gadget(pb) { + positions.allocate(pb, INCREMENTAL_MERKLE_TREE_DEPTH); + authvars.reset(new merkle_authentication_path_variable( + pb, INCREMENTAL_MERKLE_TREE_DEPTH, "auth" + )); + auth.reset(new merkle_tree_check_read_gadget( + pb, + INCREMENTAL_MERKLE_TREE_DEPTH, + positions, + leaf, + root, + *authvars, + enforce, + "" + )); + } + + void generate_r1cs_constraints() { + for (size_t i = 0; i < INCREMENTAL_MERKLE_TREE_DEPTH; i++) { + generate_boolean_r1cs_constraint( + this->pb, + positions[i], + "boolean_positions" + ); + } + + authvars->generate_r1cs_constraints(); + auth->generate_r1cs_constraints(); + } + + void generate_r1cs_witness( + size_t path_index, + const std::vector>& authentication_path + ) { + positions.fill_with_bits_of_ulong(this->pb, path_index); + + authvars->generate_r1cs_witness(path_index, authentication_path); + auth->generate_r1cs_witness(); + } +}; + +template +class UnshieldingCircuit : gadget { +private: + // Verifier inputs + pb_variable_array zk_packed_inputs; + pb_variable_array zk_unpacked_inputs; + std::shared_ptr> unpacker; + + // 64-bit value + pb_variable_array value; + + // Aux inputs + pb_variable ZERO; + std::shared_ptr> cm; // Note commitment + std::shared_ptr> rho; + std::shared_ptr> pk; + std::shared_ptr> sk; + + // Key hasher + std::shared_ptr> key_hasher; + + // Note commitment hasher + std::shared_ptr> cm_hasher; + + // Spend nullifier hasher + std::shared_ptr> nf_hasher; + + // Merkle tree lookup + std::shared_ptr> merkle_lookup; + +public: + // The anchor of the tree + std::shared_ptr> anchor; + + // SHA256(0x01 | rho) + std::shared_ptr> spend_nullifier; + + UnshieldingCircuit(protoboard &pb) : gadget(pb) { + // Inputs + { + zk_packed_inputs.allocate(pb, verifying_field_element_size()); + pb.set_input_sizes(verifying_field_element_size()); + + spend_nullifier.reset(new digest_variable(pb, 256, "")); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), spend_nullifier->bits.begin(), spend_nullifier->bits.end()); + + anchor.reset(new digest_variable(pb, 256, "")); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), anchor->bits.begin(), anchor->bits.end()); + + value.allocate(pb, 64, ""); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), value.begin(), value.end()); + + assert(zk_unpacked_inputs.size() == verifying_input_bit_size()); + + unpacker.reset(new multipacking_gadget( + pb, + zk_unpacked_inputs, + zk_packed_inputs, + FieldT::capacity(), + "unpacker" + )); + } + + // Aux + ZERO.allocate(pb); + rho.reset(new digest_variable(pb, 256, "")); + sk.reset(new digest_variable(pb, 256, "")); + pk.reset(new digest_variable(pb, 256, "")); + cm.reset(new digest_variable(pb, 256, "")); + + key_hasher.reset(new KeyHasher(pb, ZERO, sk->bits, pk)); + cm_hasher.reset(new NoteCommitment(pb, ZERO, rho->bits, pk->bits, value, cm)); + nf_hasher.reset(new SpendNullifier(pb, ZERO, rho->bits, sk->bits, spend_nullifier)); + auto test = ONE; + merkle_lookup.reset(new merkle_tree_gadget(pb, *cm, *anchor, test)); + } + + void generate_r1cs_constraints() { + unpacker->generate_r1cs_constraints(true); + generate_r1cs_equals_const_constraint(this->pb, ZERO, FieldT::zero(), "ZERO"); + + rho->generate_r1cs_constraints(); + sk->generate_r1cs_constraints(); + + key_hasher->generate_r1cs_constraints(); + cm_hasher->generate_r1cs_constraints(); + nf_hasher->generate_r1cs_constraints(); + merkle_lookup->generate_r1cs_constraints(); + } + + void generate_r1cs_witness( + const std::vector& witness_rho, + const std::vector& witness_sk, + uint64_t witness_value, + size_t path_index, + const std::vector>& authentication_path + ) { + this->pb.val(ZERO) = FieldT::zero(); + + rho->bits.fill_with_bits( + this->pb, + convertBytesVectorToVector(witness_rho) + ); + + sk->bits.fill_with_bits( + this->pb, + convertBytesVectorToVector(witness_sk) + ); + + value.fill_with_bits( + this->pb, + uint64_to_bool_vector(witness_value) + ); + + key_hasher->generate_r1cs_witness(); + cm_hasher->generate_r1cs_witness(); + nf_hasher->generate_r1cs_witness(); + merkle_lookup->generate_r1cs_witness(path_index, authentication_path); + + unpacker->generate_r1cs_witness_from_bits(); + } + + static r1cs_primary_input witness_map( + const std::vector &witness_nf, + const std::vector &witness_anchor, + uint64_t witness_value + ) { + std::vector verify_inputs; + + std::vector nf_bits = convertBytesVectorToVector(witness_nf); + std::vector anchor_bits = convertBytesVectorToVector(witness_anchor); + std::vector value_bits = uint64_to_bool_vector(witness_value); + + verify_inputs.insert(verify_inputs.end(), nf_bits.begin(), nf_bits.end()); + verify_inputs.insert(verify_inputs.end(), anchor_bits.begin(), anchor_bits.end()); + verify_inputs.insert(verify_inputs.end(), value_bits.begin(), value_bits.end()); + + assert(verify_inputs.size() == verifying_input_bit_size()); + auto verify_field_elements = pack_bit_vector_into_field_element_vector(verify_inputs); + assert(verify_field_elements.size() == verifying_field_element_size()); + return verify_field_elements; + } + + static size_t verifying_field_element_size() { + return div_ceil(verifying_input_bit_size(), FieldT::capacity()); + } + + static size_t verifying_input_bit_size() { + size_t acc = 0; + + acc += 256; // the nullifier + acc += 256; // the anchor + acc += 64; // the value of the note + + return acc; + } +}; + +template +T swap_endianness_u64(T v) { + if (v.size() != 64) { + throw std::length_error("invalid bit length for 64-bit unsigned integer"); + } + + for (size_t i = 0; i < 4; i++) { + for (size_t j = 0; j < 8; j++) { + std::swap(v[i*8 + j], v[((7-i)*8)+j]); + } + } + + return v; +} + +template +linear_combination packed_addition(pb_variable_array input) { + auto input_swapped = swap_endianness_u64(input); + + return pb_packing_sum(pb_variable_array( + input_swapped.rbegin(), input_swapped.rend() + )); +} + +template +class TransferCircuit : gadget { +private: + // Verifier inputs + pb_variable_array zk_packed_inputs; + pb_variable_array zk_unpacked_inputs; + std::shared_ptr> unpacker; + + // Aux inputs + pb_variable ZERO; + + // Verifier inputs + std::shared_ptr> anchor; + std::shared_ptr> spend_nullifier_input_1; + std::shared_ptr> spend_nullifier_input_2; + std::shared_ptr> send_nullifier_output_1; + std::shared_ptr> send_nullifier_output_2; + + // Input stuff. + std::shared_ptr> input_sk_1; + std::shared_ptr> input_sk_2; + std::shared_ptr> input_pk_1; + std::shared_ptr> input_pk_2; + std::shared_ptr> key_hasher_1; + std::shared_ptr> key_hasher_2; + std::shared_ptr> input_rho_1; + std::shared_ptr> input_rho_2; + std::shared_ptr> input_nf_hasher_1; + std::shared_ptr> input_nf_hasher_2; + pb_variable_array input_value_1; + pb_variable_array input_value_2; + std::shared_ptr> input_cm_1; + std::shared_ptr> input_cm_2; + std::shared_ptr> input_cm_hasher_1; + std::shared_ptr> input_cm_hasher_2; + pb_variable enforce_input_1; + pb_variable enforce_input_2; + std::shared_ptr> merkle_lookup_1; + std::shared_ptr> merkle_lookup_2; + + // Output stuff. + std::shared_ptr> output_cm_1; + pb_variable_array output_value_1; + std::shared_ptr> output_rho_1; + std::shared_ptr> output_pk_1; + std::shared_ptr> output_cm_hasher_1; + std::shared_ptr> output_nf_hasher_1; + + std::shared_ptr> output_cm_2; + pb_variable_array output_value_2; + std::shared_ptr> output_rho_2; + std::shared_ptr> output_pk_2; + std::shared_ptr> output_cm_hasher_2; + std::shared_ptr> output_nf_hasher_2; + +public: + + TransferCircuit(protoboard &pb) : gadget(pb) { + // Inputs + { + zk_packed_inputs.allocate(pb, verifying_field_element_size()); + pb.set_input_sizes(verifying_field_element_size()); + + anchor.reset(new digest_variable(pb, 256, "")); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), anchor->bits.begin(), anchor->bits.end()); + + spend_nullifier_input_1.reset(new digest_variable(pb, 256, "")); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), spend_nullifier_input_1->bits.begin(), spend_nullifier_input_1->bits.end()); + + spend_nullifier_input_2.reset(new digest_variable(pb, 256, "")); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), spend_nullifier_input_2->bits.begin(), spend_nullifier_input_2->bits.end()); + + send_nullifier_output_1.reset(new digest_variable(pb, 256, "")); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), send_nullifier_output_1->bits.begin(), send_nullifier_output_1->bits.end()); + + send_nullifier_output_2.reset(new digest_variable(pb, 256, "")); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), send_nullifier_output_2->bits.begin(), send_nullifier_output_2->bits.end()); + + output_cm_1.reset(new digest_variable(pb, 256, "")); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), output_cm_1->bits.begin(), output_cm_1->bits.end()); + + output_cm_2.reset(new digest_variable(pb, 256, "")); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), output_cm_2->bits.begin(), output_cm_2->bits.end()); + + assert(zk_unpacked_inputs.size() == verifying_input_bit_size()); + + unpacker.reset(new multipacking_gadget( + pb, + zk_unpacked_inputs, + zk_packed_inputs, + FieldT::capacity(), + "unpacker" + )); + } + + // Aux + ZERO.allocate(pb); + input_cm_1.reset(new digest_variable(pb, 256, "")); + input_cm_2.reset(new digest_variable(pb, 256, "")); + input_sk_1.reset(new digest_variable(pb, 256, "")); + input_sk_2.reset(new digest_variable(pb, 256, "")); + input_pk_1.reset(new digest_variable(pb, 256, "")); + input_pk_2.reset(new digest_variable(pb, 256, "")); + input_rho_1.reset(new digest_variable(pb, 256, "")); + input_rho_2.reset(new digest_variable(pb, 256, "")); + key_hasher_1.reset(new KeyHasher(pb, ZERO, input_sk_1->bits, input_pk_1)); + key_hasher_2.reset(new KeyHasher(pb, ZERO, input_sk_2->bits, input_pk_2)); + input_nf_hasher_1.reset(new SpendNullifier(pb, ZERO, input_rho_1->bits, input_sk_1->bits, spend_nullifier_input_1)); + input_nf_hasher_2.reset(new SpendNullifier(pb, ZERO, input_rho_2->bits, input_sk_2->bits, spend_nullifier_input_2)); + + input_value_1.allocate(pb, 64, ""); + input_value_2.allocate(pb, 64, ""); + + input_cm_hasher_1.reset(new NoteCommitment(pb, ZERO, input_rho_1->bits, input_pk_1->bits, input_value_1, input_cm_1)); + input_cm_hasher_2.reset(new NoteCommitment(pb, ZERO, input_rho_2->bits, input_pk_2->bits, input_value_2, input_cm_2)); + + enforce_input_1.allocate(pb); + enforce_input_2.allocate(pb); + + merkle_lookup_1.reset(new merkle_tree_gadget(pb, *input_cm_1, *anchor, enforce_input_1)); + merkle_lookup_2.reset(new merkle_tree_gadget(pb, *input_cm_2, *anchor, enforce_input_2)); + + output_value_1.allocate(pb, 64, ""); + output_value_2.allocate(pb, 64, ""); + + output_rho_1.reset(new digest_variable(pb, 256, "")); + output_rho_2.reset(new digest_variable(pb, 256, "")); + output_pk_1.reset(new digest_variable(pb, 256, "")); + output_pk_2.reset(new digest_variable(pb, 256, "")); + + output_cm_hasher_1.reset(new NoteCommitment(pb, ZERO, output_rho_1->bits, output_pk_1->bits, output_value_1, output_cm_1)); + output_cm_hasher_2.reset(new NoteCommitment(pb, ZERO, output_rho_2->bits, output_pk_2->bits, output_value_2, output_cm_2)); + + output_nf_hasher_1.reset(new SendNullifier(pb, ZERO, output_rho_1->bits, send_nullifier_output_1)); + output_nf_hasher_2.reset(new SendNullifier(pb, ZERO, output_rho_2->bits, send_nullifier_output_2)); + } + + void generate_r1cs_constraints() { + unpacker->generate_r1cs_constraints(true); + generate_r1cs_equals_const_constraint(this->pb, ZERO, FieldT::zero(), "ZERO"); + + input_sk_1->generate_r1cs_constraints(); + input_sk_2->generate_r1cs_constraints(); + input_rho_1->generate_r1cs_constraints(); + input_rho_2->generate_r1cs_constraints(); + key_hasher_1->generate_r1cs_constraints(); + key_hasher_2->generate_r1cs_constraints(); + input_nf_hasher_1->generate_r1cs_constraints(); + input_nf_hasher_2->generate_r1cs_constraints(); + + for (size_t i = 0; i < 64; i++) { + generate_boolean_r1cs_constraint( + this->pb, + input_value_1[i], + "" + ); + generate_boolean_r1cs_constraint( + this->pb, + input_value_2[i], + "" + ); + } + + input_cm_hasher_1->generate_r1cs_constraints(); + input_cm_hasher_2->generate_r1cs_constraints(); + + generate_boolean_r1cs_constraint(this->pb, enforce_input_1, ""); + + this->pb.add_r1cs_constraint(r1cs_constraint( + packed_addition(input_value_1), + (1 - enforce_input_1), + 0 + ), ""); + + generate_boolean_r1cs_constraint(this->pb, enforce_input_2, ""); + + this->pb.add_r1cs_constraint(r1cs_constraint( + packed_addition(input_value_2), + (1 - enforce_input_2), + 0 + ), ""); + + merkle_lookup_1->generate_r1cs_constraints(); + merkle_lookup_2->generate_r1cs_constraints(); + + for (size_t i = 0; i < 64; i++) { + generate_boolean_r1cs_constraint( + this->pb, + output_value_1[i], + "" + ); + generate_boolean_r1cs_constraint( + this->pb, + output_value_2[i], + "" + ); + } + + output_rho_1->generate_r1cs_constraints(); + output_rho_2->generate_r1cs_constraints(); + output_pk_1->generate_r1cs_constraints(); + output_pk_2->generate_r1cs_constraints(); + + output_cm_hasher_1->generate_r1cs_constraints(); + output_cm_hasher_2->generate_r1cs_constraints(); + + output_nf_hasher_1->generate_r1cs_constraints(); + output_nf_hasher_2->generate_r1cs_constraints(); + + { + linear_combination left_side = + packed_addition(input_value_1) + packed_addition(input_value_2); + + linear_combination right_side = + packed_addition(output_value_1) + packed_addition(output_value_2); + + // Ensure that both sides are equal + this->pb.add_r1cs_constraint(r1cs_constraint( + left_side, + 1, + right_side + )); + } + } + + void generate_r1cs_witness( + const std::vector& witness_rho_1, + const std::vector& witness_sk_1, + uint64_t witness_value_1, + size_t path_index_1, + const std::vector>& authentication_path_1, + const std::vector& witness_rho_2, + const std::vector& witness_sk_2, + uint64_t witness_value_2, + size_t path_index_2, + const std::vector>& authentication_path_2, + const std::vector& output_witness_rho_1, + const std::vector& output_witness_pk_1, + uint64_t output_witness_value_1, + const std::vector& output_witness_rho_2, + const std::vector& output_witness_pk_2, + uint64_t output_witness_value_2 + ) { + this->pb.val(ZERO) = FieldT::zero(); + + this->pb.val(enforce_input_1) = (witness_value_1 != 0) ? FieldT::one() : FieldT::zero(); + this->pb.val(enforce_input_2) = (witness_value_2 != 0) ? FieldT::one() : FieldT::zero(); + + input_rho_1->bits.fill_with_bits( + this->pb, + convertBytesVectorToVector(witness_rho_1) + ); + + input_sk_1->bits.fill_with_bits( + this->pb, + convertBytesVectorToVector(witness_sk_1) + ); + + input_value_1.fill_with_bits( + this->pb, + uint64_to_bool_vector(witness_value_1) + ); + + key_hasher_1->generate_r1cs_witness(); + input_cm_hasher_1->generate_r1cs_witness(); + input_nf_hasher_1->generate_r1cs_witness(); + merkle_lookup_1->generate_r1cs_witness(path_index_1, authentication_path_1); + + input_rho_2->bits.fill_with_bits( + this->pb, + convertBytesVectorToVector(witness_rho_2) + ); + + input_sk_2->bits.fill_with_bits( + this->pb, + convertBytesVectorToVector(witness_sk_2) + ); + + input_value_2.fill_with_bits( + this->pb, + uint64_to_bool_vector(witness_value_2) + ); + + key_hasher_2->generate_r1cs_witness(); + input_cm_hasher_2->generate_r1cs_witness(); + input_nf_hasher_2->generate_r1cs_witness(); + merkle_lookup_2->generate_r1cs_witness(path_index_2, authentication_path_2); + + output_rho_1->bits.fill_with_bits( + this->pb, + convertBytesVectorToVector(output_witness_rho_1) + ); + + output_pk_1->bits.fill_with_bits( + this->pb, + convertBytesVectorToVector(output_witness_pk_1) + ); + + output_value_1.fill_with_bits( + this->pb, + uint64_to_bool_vector(output_witness_value_1) + ); + + output_cm_hasher_1->generate_r1cs_witness(); + output_nf_hasher_1->generate_r1cs_witness(); + + output_rho_2->bits.fill_with_bits( + this->pb, + convertBytesVectorToVector(output_witness_rho_2) + ); + + output_pk_2->bits.fill_with_bits( + this->pb, + convertBytesVectorToVector(output_witness_pk_2) + ); + + output_value_2.fill_with_bits( + this->pb, + uint64_to_bool_vector(output_witness_value_2) + ); + + output_cm_hasher_2->generate_r1cs_witness(); + output_nf_hasher_2->generate_r1cs_witness(); + + unpacker->generate_r1cs_witness_from_bits(); + } + + static r1cs_primary_input witness_map( + const std::vector &witness_anchor, + const std::vector &input_nf_1, + const std::vector &input_nf_2, + const std::vector &output_nf_1, + const std::vector &output_nf_2, + const std::vector &output_cm_1, + const std::vector &output_cm_2 + ) + { + std::vector verify_inputs; + + std::vector anchor_bits = convertBytesVectorToVector(witness_anchor); + std::vector input_nf1_bits = convertBytesVectorToVector(input_nf_1); + std::vector input_nf2_bits = convertBytesVectorToVector(input_nf_2); + std::vector output_nf1_bits = convertBytesVectorToVector(output_nf_1); + std::vector output_nf2_bits = convertBytesVectorToVector(output_nf_2); + std::vector output_cm1_bits = convertBytesVectorToVector(output_cm_1); + std::vector output_cm2_bits = convertBytesVectorToVector(output_cm_2); + + verify_inputs.insert(verify_inputs.end(), anchor_bits.begin(), anchor_bits.end()); + verify_inputs.insert(verify_inputs.end(), input_nf1_bits.begin(), input_nf1_bits.end()); + verify_inputs.insert(verify_inputs.end(), input_nf2_bits.begin(), input_nf2_bits.end()); + verify_inputs.insert(verify_inputs.end(), output_nf1_bits.begin(), output_nf1_bits.end()); + verify_inputs.insert(verify_inputs.end(), output_nf2_bits.begin(), output_nf2_bits.end()); + verify_inputs.insert(verify_inputs.end(), output_cm1_bits.begin(), output_cm1_bits.end()); + verify_inputs.insert(verify_inputs.end(), output_cm2_bits.begin(), output_cm2_bits.end()); + + assert(verify_inputs.size() == verifying_input_bit_size()); + auto verify_field_elements = pack_bit_vector_into_field_element_vector(verify_inputs); + assert(verify_field_elements.size() == verifying_field_element_size()); + return verify_field_elements; + } + + static size_t verifying_field_element_size() { + return div_ceil(verifying_input_bit_size(), FieldT::capacity()); + } + + static size_t verifying_input_bit_size() { + size_t acc = 0; + + acc += 256; // the anchor + acc += 256; // input 1 nullifier + acc += 256; // input 2 nullifier + acc += 256; // output 1 nullifier + acc += 256; // output 2 nullifier + acc += 256; // output 1 commitment + acc += 256; // output 2 commitment + + return acc; + } +}; diff --git a/privacy/zsl/zsl/impl.tcc b/privacy/zsl/zsl/impl.tcc new file mode 100644 index 0000000..a26936c --- /dev/null +++ b/privacy/zsl/zsl/impl.tcc @@ -0,0 +1,420 @@ +// Copyright 2017 Zerocoin Electric Coin Company LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "zsl.h" +#include + +#include +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" +#include "common/default_types/r1cs_ppzksnark_pp.hpp" +#include "common/utils.hpp" +#include "common/profiling.hpp" + +using namespace libsnark; +using namespace std; + +#include "gadgets.tcc" + +typedef Fr FieldT; + +#include + +template +void saveToFile(std::string path, T& obj) { + std::stringstream ss; + ss << obj; + std::ofstream fh; + fh.open(path, std::ios::binary); + ss.rdbuf()->pubseekpos(0, std::ios_base::out); + fh << ss.rdbuf(); + fh.flush(); + fh.close(); +} + +template +void loadFromFile(std::string path, T& objIn) { + std::stringstream ss; + std::ifstream fh(path, std::ios::binary); + + ss << fh.rdbuf(); + fh.close(); + + ss.rdbuf()->pubseekpos(0, std::ios_base::in); + + ss >> objIn; +} + +void zsl_initialize() +{ + default_r1cs_ppzksnark_pp::init_public_params(); + inhibit_profiling_info = true; + inhibit_profiling_counters = true; +} + +bool zsl_verify_shielding( + void *proof_ptr, + void *send_nf_ptr, + void *cm_ptr, + uint64_t value +) +{ + unsigned char *send_nf = reinterpret_cast(send_nf_ptr); + unsigned char *cm = reinterpret_cast(cm_ptr); + unsigned char *proof = reinterpret_cast(proof_ptr); + + std::vector proof_v(proof, proof+584); + + std::stringstream proof_data; + for (int i = 0; i < 584; i++) { + proof_data << proof_v[i]; + } + + assert(proof_data.str().size() == 584); + + proof_data.rdbuf()->pubseekpos(0, std::ios_base::in); + + r1cs_ppzksnark_proof proof_obj; + proof_data >> proof_obj; + + auto witness_map = ShieldingCircuit::witness_map( + std::vector(send_nf, send_nf+32), + std::vector(cm, cm+32), + value + ); + + r1cs_ppzksnark_verification_key verification_key; + loadFromFile("shielding.vk", verification_key); + + if (!r1cs_ppzksnark_verifier_strong_IC(verification_key, witness_map, proof_obj)) { + return false; + } else { + return true; + } +} + +bool zsl_verify_unshielding( + void *proof_ptr, + void *spend_nf_ptr, + void *rt_ptr, + uint64_t value +) +{ + unsigned char *spend_nf = reinterpret_cast(spend_nf_ptr); + unsigned char *rt = reinterpret_cast(rt_ptr); + unsigned char *proof = reinterpret_cast(proof_ptr); + + std::vector proof_v(proof, proof+584); + + std::stringstream proof_data; + for (int i = 0; i < 584; i++) { + proof_data << proof_v[i]; + } + + assert(proof_data.str().size() == 584); + + proof_data.rdbuf()->pubseekpos(0, std::ios_base::in); + + r1cs_ppzksnark_proof proof_obj; + proof_data >> proof_obj; + + auto witness_map = UnshieldingCircuit::witness_map( + std::vector(spend_nf, spend_nf+32), + std::vector(rt, rt+32), + value + ); + + r1cs_ppzksnark_verification_key verification_key; + loadFromFile("unshielding.vk", verification_key); + + if (!r1cs_ppzksnark_verifier_strong_IC(verification_key, witness_map, proof_obj)) { + return false; + } else { + return true; + } +} + +void zsl_prove_unshielding( + void *rho_ptr, + void *pk_ptr, + uint64_t value, + uint64_t tree_position, + void *authentication_path_ptr, + void *output_proof_ptr +) +{ + unsigned char *rho = reinterpret_cast(rho_ptr); + unsigned char *pk = reinterpret_cast(pk_ptr); + unsigned char *output_proof = reinterpret_cast(output_proof_ptr); + unsigned char *authentication_path = reinterpret_cast(authentication_path_ptr); + + protoboard pb; + UnshieldingCircuit g(pb); + g.generate_r1cs_constraints(); + + std::vector> auth_path; + for (int i = 0; i < 29; i++) { + auth_path.push_back(convertBytesVectorToVector(std::vector(authentication_path + i*32, authentication_path + i*32 + 32))); + } + + std::reverse(std::begin(auth_path), std::end(auth_path)); + + g.generate_r1cs_witness( + std::vector(rho, rho + 32), + std::vector(pk, pk + 32), + value, + tree_position, + auth_path + ); + pb.constraint_system.swap_AB_if_beneficial(); + assert(pb.is_satisfied()); + + r1cs_ppzksnark_proving_key proving_key; + loadFromFile("unshielding.pk", proving_key); + + auto proof = r1cs_ppzksnark_prover(proving_key, pb.primary_input(), pb.auxiliary_input(), pb.constraint_system); + + std::stringstream proof_data; + proof_data << proof; + auto proof_str = proof_data.str(); + assert(proof_str.size() == 584); + + for (int i = 0; i < 584; i++) { + output_proof[i] = proof_str[i]; + } +} + +void zsl_prove_shielding( + void *rho_ptr, + void *pk_ptr, + uint64_t value, + void *output_proof_ptr +) +{ + unsigned char *rho = reinterpret_cast(rho_ptr); + unsigned char *pk = reinterpret_cast(pk_ptr); + unsigned char *output_proof = reinterpret_cast(output_proof_ptr); + + protoboard pb; + ShieldingCircuit g(pb); + g.generate_r1cs_constraints(); + g.generate_r1cs_witness( + // rho + std::vector(rho, rho + 32), + // pk + std::vector(pk, pk + 32), + // value + value + ); + pb.constraint_system.swap_AB_if_beneficial(); + assert(pb.is_satisfied()); + + r1cs_ppzksnark_proving_key proving_key; + loadFromFile("shielding.pk", proving_key); + + auto proof = r1cs_ppzksnark_prover(proving_key, pb.primary_input(), pb.auxiliary_input(), pb.constraint_system); + + std::stringstream proof_data; + proof_data << proof; + auto proof_str = proof_data.str(); + assert(proof_str.size() == 584); + + for (int i = 0; i < 584; i++) { + output_proof[i] = proof_str[i]; + } +} + +bool zsl_verify_transfer( + void *proof_ptr, + void *anchor_ptr, + void *spend_nf_ptr_1, + void *spend_nf_ptr_2, + void *send_nf_ptr_1, + void *send_nf_ptr_2, + void *cm_ptr_1, + void *cm_ptr_2 +) +{ + unsigned char *anchor = reinterpret_cast(anchor_ptr); + unsigned char *spend_nf_1 = reinterpret_cast(spend_nf_ptr_1); + unsigned char *spend_nf_2 = reinterpret_cast(spend_nf_ptr_2); + unsigned char *send_nf_1 = reinterpret_cast(send_nf_ptr_1); + unsigned char *send_nf_2 = reinterpret_cast(send_nf_ptr_2); + unsigned char *cm_1 = reinterpret_cast(cm_ptr_1); + unsigned char *cm_2 = reinterpret_cast(cm_ptr_2); + unsigned char *proof = reinterpret_cast(proof_ptr); + + std::vector proof_v(proof, proof+584); + + std::stringstream proof_data; + for (int i = 0; i < 584; i++) { + proof_data << proof_v[i]; + } + + assert(proof_data.str().size() == 584); + + proof_data.rdbuf()->pubseekpos(0, std::ios_base::in); + + r1cs_ppzksnark_proof proof_obj; + proof_data >> proof_obj; + + auto witness_map = TransferCircuit::witness_map( + std::vector(anchor, anchor+32), + std::vector(spend_nf_1, spend_nf_1+32), + std::vector(spend_nf_2, spend_nf_2+32), + std::vector(send_nf_1, send_nf_1+32), + std::vector(send_nf_2, send_nf_2+32), + std::vector(cm_1, cm_1+32), + std::vector(cm_2, cm_2+32) + ); + + r1cs_ppzksnark_verification_key verification_key; + loadFromFile("transfer.vk", verification_key); + + if (!r1cs_ppzksnark_verifier_strong_IC(verification_key, witness_map, proof_obj)) { + return false; + } else { + return true; + } +} + +void zsl_prove_transfer( + void *output_proof_ptr, + void *input_rho_ptr_1, + void *input_pk_ptr_1, + uint64_t input_value_1, + uint64_t input_tree_position_1, + void *input_authentication_path_ptr_1, + void *input_rho_ptr_2, + void *input_pk_ptr_2, + uint64_t input_value_2, + uint64_t input_tree_position_2, + void *input_authentication_path_ptr_2, + void *output_rho_ptr_1, + void *output_pk_ptr_1, + uint64_t output_value_1, + void *output_rho_ptr_2, + void *output_pk_ptr_2, + uint64_t output_value_2 +) +{ + unsigned char *output_proof = reinterpret_cast(output_proof_ptr); + + unsigned char *input_rho_1 = reinterpret_cast(input_rho_ptr_1); + unsigned char *input_pk_1 = reinterpret_cast(input_pk_ptr_1); + unsigned char *authentication_path_1 = reinterpret_cast(input_authentication_path_ptr_1); + + unsigned char *input_rho_2 = reinterpret_cast(input_rho_ptr_2); + unsigned char *input_pk_2 = reinterpret_cast(input_pk_ptr_2); + unsigned char *authentication_path_2 = reinterpret_cast(input_authentication_path_ptr_2); + + unsigned char *output_rho_1 = reinterpret_cast(output_rho_ptr_1); + unsigned char *output_pk_1 = reinterpret_cast(output_pk_ptr_1); + unsigned char *output_rho_2 = reinterpret_cast(output_rho_ptr_2); + unsigned char *output_pk_2 = reinterpret_cast(output_pk_ptr_2); + + std::vector> auth_path_1; + for (int i = 0; i < 29; i++) { + auth_path_1.push_back(convertBytesVectorToVector(std::vector(authentication_path_1 + i*32, authentication_path_1 + i*32 + 32))); + } + + std::reverse(std::begin(auth_path_1), std::end(auth_path_1)); + + std::vector> auth_path_2; + for (int i = 0; i < 29; i++) { + auth_path_2.push_back(convertBytesVectorToVector(std::vector(authentication_path_2 + i*32, authentication_path_2 + i*32 + 32))); + } + + std::reverse(std::begin(auth_path_2), std::end(auth_path_2)); + + protoboard pb; + TransferCircuit g(pb); + g.generate_r1cs_constraints(); + g.generate_r1cs_witness( + std::vector(input_rho_1, input_rho_1 + 32), + std::vector(input_pk_1, input_pk_1 + 32), + input_value_1, + input_tree_position_1, + auth_path_1, + std::vector(input_rho_2, input_rho_2 + 32), + std::vector(input_pk_2, input_pk_2 + 32), + input_value_2, + input_tree_position_2, + auth_path_2, + std::vector(output_rho_1, output_rho_1 + 32), + std::vector(output_pk_1, output_pk_1 + 32), + output_value_1, + std::vector(output_rho_2, output_rho_2 + 32), + std::vector(output_pk_2, output_pk_2 + 32), + output_value_2 + ); + pb.constraint_system.swap_AB_if_beneficial(); + assert(pb.is_satisfied()); + + r1cs_ppzksnark_proving_key proving_key; + loadFromFile("transfer.pk", proving_key); + + auto proof = r1cs_ppzksnark_prover(proving_key, pb.primary_input(), pb.auxiliary_input(), pb.constraint_system); + + std::stringstream proof_data; + proof_data << proof; + auto proof_str = proof_data.str(); + assert(proof_str.size() == 584); + + for (int i = 0; i < 584; i++) { + output_proof[i] = proof_str[i]; + } +} + +void zsl_paramgen_transfer() +{ + protoboard pb; + TransferCircuit g(pb); + g.generate_r1cs_constraints(); + + const r1cs_constraint_system constraint_system = pb.get_constraint_system(); + cout << "Number of R1CS constraints: " << constraint_system.num_constraints() << endl; + auto crs = r1cs_ppzksnark_generator(constraint_system); + + saveToFile("transfer.pk", crs.pk); + saveToFile("transfer.vk", crs.vk); +} + +void zsl_paramgen_shielding() +{ + protoboard pb; + ShieldingCircuit g(pb); + g.generate_r1cs_constraints(); + + const r1cs_constraint_system constraint_system = pb.get_constraint_system(); + cout << "Number of R1CS constraints: " << constraint_system.num_constraints() << endl; + auto crs = r1cs_ppzksnark_generator(constraint_system); + + saveToFile("shielding.pk", crs.pk); + saveToFile("shielding.vk", crs.vk); +} + +void zsl_paramgen_unshielding() +{ + protoboard pb; + UnshieldingCircuit g(pb); + g.generate_r1cs_constraints(); + + const r1cs_constraint_system constraint_system = pb.get_constraint_system(); + cout << "Number of R1CS constraints: " << constraint_system.num_constraints() << endl; + auto crs = r1cs_ppzksnark_generator(constraint_system); + + saveToFile("unshielding.pk", crs.pk); + saveToFile("unshielding.vk", crs.vk); +} diff --git a/privacy/zsl/zsl/libzsl.a b/privacy/zsl/zsl/libzsl.a new file mode 100644 index 0000000..202375b Binary files /dev/null and b/privacy/zsl/zsl/libzsl.a differ diff --git a/privacy/zsl/zsl/reductions/bacs_to_r1cs/bacs_to_r1cs.hpp b/privacy/zsl/zsl/reductions/bacs_to_r1cs/bacs_to_r1cs.hpp new file mode 100644 index 0000000..87599ce --- /dev/null +++ b/privacy/zsl/zsl/reductions/bacs_to_r1cs/bacs_to_r1cs.hpp @@ -0,0 +1,44 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a BACS-to-R1CS reduction, that is, constructing + a R1CS ("Rank-1 Constraint System") from a BACS ("Bilinear Arithmetic Circuit Satisfiability"). + + The reduction is straightforward: each bilinear gate gives rises to a + corresponding R1CS constraint that enforces correct computation of the gate; + also, each output gives rise to a corresponding R1CS constraint that enforces + that the output is zero. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BACS_TO_R1CS_HPP_ +#define BACS_TO_R1CS_HPP_ + +#include "relations/circuit_satisfaction_problems/bacs/bacs.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" + +namespace libsnark { + +/** + * Instance map for the BACS-to-R1CS reduction. + */ +template +r1cs_constraint_system bacs_to_r1cs_instance_map(const bacs_circuit &circuit); + +/** + * Witness map for the BACS-to-R1CS reduction. + */ +template +r1cs_variable_assignment bacs_to_r1cs_witness_map(const bacs_circuit &circuit, + const bacs_primary_input &primary_input, + const bacs_auxiliary_input &auxiliary_input); + +} // libsnark + +#include "reductions/bacs_to_r1cs/bacs_to_r1cs.tcc" + +#endif // BACS_TO_R1CS_HPP_ diff --git a/privacy/zsl/zsl/reductions/bacs_to_r1cs/bacs_to_r1cs.tcc b/privacy/zsl/zsl/reductions/bacs_to_r1cs/bacs_to_r1cs.tcc new file mode 100644 index 0000000..45f78a7 --- /dev/null +++ b/privacy/zsl/zsl/reductions/bacs_to_r1cs/bacs_to_r1cs.tcc @@ -0,0 +1,79 @@ +/** @file +***************************************************************************** + +Implementation of interfaces for a BACS-to-R1CS reduction. + +See bacs_to_r1cs.hpp . + +***************************************************************************** +* @author This file is part of libsnark, developed by SCIPR Lab +* and contributors (see AUTHORS). +* @copyright MIT license (see LICENSE file) +*****************************************************************************/ + +#ifndef BACS_TO_R1CS_TCC_ +#define BACS_TO_R1CS_TCC_ + +#include "relations/circuit_satisfaction_problems/bacs/bacs.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" + +namespace libsnark { + +template +r1cs_constraint_system bacs_to_r1cs_instance_map(const bacs_circuit &circuit) +{ + enter_block("Call to bacs_to_r1cs_instance_map"); + assert(circuit.is_valid()); + r1cs_constraint_system result; + +#ifdef DEBUG + result.variable_annotations = circuit.variable_annotations; +#endif + + result.primary_input_size = circuit.primary_input_size; + result.auxiliary_input_size = circuit.auxiliary_input_size + circuit.gates.size(); + + for (auto &g : circuit.gates) + { + result.constraints.emplace_back(r1cs_constraint(g.lhs, g.rhs, g.output)); +#ifdef DEBUG + auto it = circuit.gate_annotations.find(g.output.index); + if (it != circuit.gate_annotations.end()) + { + result.constraint_annotations[result.constraints.size()-1] = it->second; + } +#endif + } + + for (auto &g : circuit.gates) + { + if (g.is_circuit_output) + { + result.constraints.emplace_back(r1cs_constraint(1, g.output, 0)); + +#ifdef DEBUG + result.constraint_annotations[result.constraints.size()-1] = FMT("", "output_%zu_is_circuit_output", g.output.index); +#endif + } + } + + leave_block("Call to bacs_to_r1cs_instance_map"); + + return result; +} + +template +r1cs_variable_assignment bacs_to_r1cs_witness_map(const bacs_circuit &circuit, + const bacs_primary_input &primary_input, + const bacs_auxiliary_input &auxiliary_input) +{ + enter_block("Call to bacs_to_r1cs_witness_map"); + const r1cs_variable_assignment result = circuit.get_all_wires(primary_input, auxiliary_input); + leave_block("Call to bacs_to_r1cs_witness_map"); + + return result; +} + +} // libsnark + +#endif // BACS_TO_R1CS_TCC_ diff --git a/privacy/zsl/zsl/reductions/r1cs_to_qap/r1cs_to_qap.hpp b/privacy/zsl/zsl/reductions/r1cs_to_qap/r1cs_to_qap.hpp new file mode 100644 index 0000000..b3cde71 --- /dev/null +++ b/privacy/zsl/zsl/reductions/r1cs_to_qap/r1cs_to_qap.hpp @@ -0,0 +1,70 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a R1CS-to-QAP reduction, that is, constructing + a QAP ("Quadratic Arithmetic Program") from a R1CS ("Rank-1 Constraint System"). + + QAPs are defined in \[GGPR13], and construced for R1CS also in \[GGPR13]. + + The implementation of the reduction follows, extends, and optimizes + the efficient approach described in Appendix E of \[BCGTV13]. + + References: + + \[BCGTV13] + "SNARKs for C: Verifying Program Executions Succinctly and in Zero Knowledge", + Eli Ben-Sasson, Alessandro Chiesa, Daniel Genkin, Eran Tromer, Madars Virza, + CRYPTO 2013, + + + \[GGPR13]: + "Quadratic span programs and succinct NIZKs without PCPs", + Rosario Gennaro, Craig Gentry, Bryan Parno, Mariana Raykova, + EUROCRYPT 2013, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_TO_QAP_HPP_ +#define R1CS_TO_QAP_HPP_ + +#include "relations/arithmetic_programs/qap/qap.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" + +namespace libsnark { + +/** + * Instance map for the R1CS-to-QAP reduction. + */ +template +qap_instance r1cs_to_qap_instance_map(const r1cs_constraint_system &cs); + +/** + * Instance map for the R1CS-to-QAP reduction followed by evaluation of the resulting QAP instance. + */ +template +qap_instance_evaluation r1cs_to_qap_instance_map_with_evaluation(const r1cs_constraint_system &cs, + const FieldT &t); + +/** + * Witness map for the R1CS-to-QAP reduction. + * + * The witness map takes zero knowledge into account when d1,d2,d3 are random. + */ +template +qap_witness r1cs_to_qap_witness_map(const r1cs_constraint_system &cs, + const r1cs_primary_input &primary_input, + const r1cs_auxiliary_input &auxiliary_input, + const FieldT &d1, + const FieldT &d2, + const FieldT &d3); + +} // libsnark + +#include "reductions/r1cs_to_qap/r1cs_to_qap.tcc" + +#endif // R1CS_TO_QAP_HPP_ diff --git a/privacy/zsl/zsl/reductions/r1cs_to_qap/r1cs_to_qap.tcc b/privacy/zsl/zsl/reductions/r1cs_to_qap/r1cs_to_qap.tcc new file mode 100644 index 0000000..3d0bee2 --- /dev/null +++ b/privacy/zsl/zsl/reductions/r1cs_to_qap/r1cs_to_qap.tcc @@ -0,0 +1,338 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a R1CS-to-QAP reduction. + + See r1cs_to_qap.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_TO_QAP_TCC_ +#define R1CS_TO_QAP_TCC_ + +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "algebra/evaluation_domain/evaluation_domain.hpp" + +namespace libsnark { + +/** + * Instance map for the R1CS-to-QAP reduction. + * + * Namely, given a R1CS constraint system cs, construct a QAP instance for which: + * A := (A_0(z),A_1(z),...,A_m(z)) + * B := (B_0(z),B_1(z),...,B_m(z)) + * C := (C_0(z),C_1(z),...,C_m(z)) + * where + * m = number of variables of the QAP + * and + * each A_i,B_i,C_i is expressed in the Lagrange basis. + */ +template +qap_instance r1cs_to_qap_instance_map(const r1cs_constraint_system &cs) +{ + enter_block("Call to r1cs_to_qap_instance_map"); + + const std::shared_ptr > domain = get_evaluation_domain(cs.num_constraints() + cs.num_inputs() + 1); + + std::vector > A_in_Lagrange_basis(cs.num_variables()+1); + std::vector > B_in_Lagrange_basis(cs.num_variables()+1); + std::vector > C_in_Lagrange_basis(cs.num_variables()+1); + + enter_block("Compute polynomials A, B, C in Lagrange basis"); + /** + * add and process the constraints + * input_i * 0 = 0 + * to ensure soundness of input consistency + */ + for (size_t i = 0; i <= cs.num_inputs(); ++i) + { + A_in_Lagrange_basis[i][cs.num_constraints() + i] = FieldT::one(); + } + /* process all other constraints */ + for (size_t i = 0; i < cs.num_constraints(); ++i) + { + for (size_t j = 0; j < cs.constraints[i].a.terms.size(); ++j) + { + A_in_Lagrange_basis[cs.constraints[i].a.terms[j].index][i] += + cs.constraints[i].a.terms[j].coeff; + } + + for (size_t j = 0; j < cs.constraints[i].b.terms.size(); ++j) + { + B_in_Lagrange_basis[cs.constraints[i].b.terms[j].index][i] += + cs.constraints[i].b.terms[j].coeff; + } + + for (size_t j = 0; j < cs.constraints[i].c.terms.size(); ++j) + { + C_in_Lagrange_basis[cs.constraints[i].c.terms[j].index][i] += + cs.constraints[i].c.terms[j].coeff; + } + } + leave_block("Compute polynomials A, B, C in Lagrange basis"); + + leave_block("Call to r1cs_to_qap_instance_map"); + + return qap_instance(domain, + cs.num_variables(), + domain->m, + cs.num_inputs(), + std::move(A_in_Lagrange_basis), + std::move(B_in_Lagrange_basis), + std::move(C_in_Lagrange_basis)); +} + +/** + * Instance map for the R1CS-to-QAP reduction followed by evaluation of the resulting QAP instance. + * + * Namely, given a R1CS constraint system cs and a field element t, construct + * a QAP instance (evaluated at t) for which: + * At := (A_0(t),A_1(t),...,A_m(t)) + * Bt := (B_0(t),B_1(t),...,B_m(t)) + * Ct := (C_0(t),C_1(t),...,C_m(t)) + * Ht := (1,t,t^2,...,t^n) + * Zt := Z(t) = "vanishing polynomial of a certain set S, evaluated at t" + * where + * m = number of variables of the QAP + * n = degree of the QAP + */ +template +qap_instance_evaluation r1cs_to_qap_instance_map_with_evaluation(const r1cs_constraint_system &cs, + const FieldT &t) +{ + enter_block("Call to r1cs_to_qap_instance_map_with_evaluation"); + + const std::shared_ptr > domain = get_evaluation_domain(cs.num_constraints() + cs.num_inputs() + 1); + + std::vector At, Bt, Ct, Ht; + + At.resize(cs.num_variables()+1, FieldT::zero()); + Bt.resize(cs.num_variables()+1, FieldT::zero()); + Ct.resize(cs.num_variables()+1, FieldT::zero()); + Ht.reserve(domain->m+1); + + const FieldT Zt = domain->compute_Z(t); + + enter_block("Compute evaluations of A, B, C, H at t"); + const std::vector u = domain->lagrange_coeffs(t); + /** + * add and process the constraints + * input_i * 0 = 0 + * to ensure soundness of input consistency + */ + for (size_t i = 0; i <= cs.num_inputs(); ++i) + { + At[i] = u[cs.num_constraints() + i]; + } + /* process all other constraints */ + for (size_t i = 0; i < cs.num_constraints(); ++i) + { + for (size_t j = 0; j < cs.constraints[i].a.terms.size(); ++j) + { + At[cs.constraints[i].a.terms[j].index] += + u[i]*cs.constraints[i].a.terms[j].coeff; + } + + for (size_t j = 0; j < cs.constraints[i].b.terms.size(); ++j) + { + Bt[cs.constraints[i].b.terms[j].index] += + u[i]*cs.constraints[i].b.terms[j].coeff; + } + + for (size_t j = 0; j < cs.constraints[i].c.terms.size(); ++j) + { + Ct[cs.constraints[i].c.terms[j].index] += + u[i]*cs.constraints[i].c.terms[j].coeff; + } + } + + FieldT ti = FieldT::one(); + for (size_t i = 0; i < domain->m+1; ++i) + { + Ht.emplace_back(ti); + ti *= t; + } + leave_block("Compute evaluations of A, B, C, H at t"); + + leave_block("Call to r1cs_to_qap_instance_map_with_evaluation"); + + return qap_instance_evaluation(domain, + cs.num_variables(), + domain->m, + cs.num_inputs(), + t, + std::move(At), + std::move(Bt), + std::move(Ct), + std::move(Ht), + Zt); +} + +/** + * Witness map for the R1CS-to-QAP reduction. + * + * The witness map takes zero knowledge into account when d1,d2,d3 are random. + * + * More precisely, compute the coefficients + * h_0,h_1,...,h_n + * of the polynomial + * H(z) := (A(z)*B(z)-C(z))/Z(z) + * where + * A(z) := A_0(z) + \sum_{k=1}^{m} w_k A_k(z) + d1 * Z(z) + * B(z) := B_0(z) + \sum_{k=1}^{m} w_k B_k(z) + d2 * Z(z) + * C(z) := C_0(z) + \sum_{k=1}^{m} w_k C_k(z) + d3 * Z(z) + * Z(z) := "vanishing polynomial of set S" + * and + * m = number of variables of the QAP + * n = degree of the QAP + * + * This is done as follows: + * (1) compute evaluations of A,B,C on S = {sigma_1,...,sigma_n} + * (2) compute coefficients of A,B,C + * (3) compute evaluations of A,B,C on T = "coset of S" + * (4) compute evaluation of H on T + * (5) compute coefficients of H + * (6) patch H to account for d1,d2,d3 (i.e., add coefficients of the polynomial (A d2 + B d1 - d3) + d1*d2*Z ) + * + * The code below is not as simple as the above high-level description due to + * some reshuffling to save space. + */ +template +qap_witness r1cs_to_qap_witness_map(const r1cs_constraint_system &cs, + const r1cs_primary_input &primary_input, + const r1cs_auxiliary_input &auxiliary_input, + const FieldT &d1, + const FieldT &d2, + const FieldT &d3) +{ + enter_block("Call to r1cs_to_qap_witness_map"); + + /* sanity check */ + assert(cs.is_satisfied(primary_input, auxiliary_input)); + + const std::shared_ptr > domain = get_evaluation_domain(cs.num_constraints() + cs.num_inputs() + 1); + + r1cs_variable_assignment full_variable_assignment = primary_input; + full_variable_assignment.insert(full_variable_assignment.end(), auxiliary_input.begin(), auxiliary_input.end()); + + enter_block("Compute evaluation of polynomials A, B on set S"); + std::vector aA(domain->m, FieldT::zero()), aB(domain->m, FieldT::zero()); + + /* account for the additional constraints input_i * 0 = 0 */ + for (size_t i = 0; i <= cs.num_inputs(); ++i) + { + aA[i+cs.num_constraints()] = (i > 0 ? full_variable_assignment[i-1] : FieldT::one()); + } + /* account for all other constraints */ + for (size_t i = 0; i < cs.num_constraints(); ++i) + { + aA[i] += cs.constraints[i].a.evaluate(full_variable_assignment); + aB[i] += cs.constraints[i].b.evaluate(full_variable_assignment); + } + leave_block("Compute evaluation of polynomials A, B on set S"); + + enter_block("Compute coefficients of polynomial A"); + domain->iFFT(aA); + leave_block("Compute coefficients of polynomial A"); + + enter_block("Compute coefficients of polynomial B"); + domain->iFFT(aB); + leave_block("Compute coefficients of polynomial B"); + + enter_block("Compute ZK-patch"); + std::vector coefficients_for_H(domain->m+1, FieldT::zero()); +#ifdef MULTICORE +#pragma omp parallel for +#endif + /* add coefficients of the polynomial (d2*A + d1*B - d3) + d1*d2*Z */ + for (size_t i = 0; i < domain->m; ++i) + { + coefficients_for_H[i] = d2*aA[i] + d1*aB[i]; + } + coefficients_for_H[0] -= d3; + domain->add_poly_Z(d1*d2, coefficients_for_H); + leave_block("Compute ZK-patch"); + + enter_block("Compute evaluation of polynomial A on set T"); + domain->cosetFFT(aA, FieldT::multiplicative_generator); + leave_block("Compute evaluation of polynomial A on set T"); + + enter_block("Compute evaluation of polynomial B on set T"); + domain->cosetFFT(aB, FieldT::multiplicative_generator); + leave_block("Compute evaluation of polynomial B on set T"); + + enter_block("Compute evaluation of polynomial H on set T"); + std::vector &H_tmp = aA; // can overwrite aA because it is not used later +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < domain->m; ++i) + { + H_tmp[i] = aA[i]*aB[i]; + } + std::vector().swap(aB); // destroy aB + + enter_block("Compute evaluation of polynomial C on set S"); + std::vector aC(domain->m, FieldT::zero()); + for (size_t i = 0; i < cs.num_constraints(); ++i) + { + aC[i] += cs.constraints[i].c.evaluate(full_variable_assignment); + } + leave_block("Compute evaluation of polynomial C on set S"); + + enter_block("Compute coefficients of polynomial C"); + domain->iFFT(aC); + leave_block("Compute coefficients of polynomial C"); + + enter_block("Compute evaluation of polynomial C on set T"); + domain->cosetFFT(aC, FieldT::multiplicative_generator); + leave_block("Compute evaluation of polynomial C on set T"); + +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < domain->m; ++i) + { + H_tmp[i] = (H_tmp[i]-aC[i]); + } + + enter_block("Divide by Z on set T"); + domain->divide_by_Z_on_coset(H_tmp); + leave_block("Divide by Z on set T"); + + leave_block("Compute evaluation of polynomial H on set T"); + + enter_block("Compute coefficients of polynomial H"); + domain->icosetFFT(H_tmp, FieldT::multiplicative_generator); + leave_block("Compute coefficients of polynomial H"); + + enter_block("Compute sum of H and ZK-patch"); +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < domain->m; ++i) + { + coefficients_for_H[i] += H_tmp[i]; + } + leave_block("Compute sum of H and ZK-patch"); + + leave_block("Call to r1cs_to_qap_witness_map"); + + return qap_witness(cs.num_variables(), + domain->m, + cs.num_inputs(), + d1, + d2, + d3, + full_variable_assignment, + std::move(coefficients_for_H)); +} + +} // libsnark + +#endif // R1CS_TO_QAP_TCC_ diff --git a/privacy/zsl/zsl/reductions/ram_to_r1cs/examples/demo_arithmetization.cpp b/privacy/zsl/zsl/reductions/ram_to_r1cs/examples/demo_arithmetization.cpp new file mode 100644 index 0000000..1698301 --- /dev/null +++ b/privacy/zsl/zsl/reductions/ram_to_r1cs/examples/demo_arithmetization.cpp @@ -0,0 +1,144 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include +#include +#include +#include +#ifndef MINDEPS +#include +#endif + +#include "common/default_types/tinyram_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "reductions/ram_to_r1cs/ram_to_r1cs.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_params.hpp" +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.hpp" + +#ifndef MINDEPS +namespace po = boost::program_options; + +bool process_arithm_command_line(const int argc, const char** argv, + std::string &assembly_fn, + std::string &processed_assembly_fn, + std::string &architecture_params_fn, + std::string &computation_bounds_fn, + std::string &primary_input_fn, + std::string &auxiliary_input_fn) +{ + try + { + po::options_description desc("Usage"); + desc.add_options() + ("help", "print this help message") + ("assembly", po::value(&assembly_fn)->required()) + ("processed_assembly", po::value(&processed_assembly_fn)->required()) + ("architecture_params", po::value(&architecture_params_fn)->required()) + ("computation_bounds", po::value(&computation_bounds_fn)->required()) + ("primary_input", po::value(&primary_input_fn)->required()) + ("auxiliary_input", po::value(&auxiliary_input_fn)->required()); + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + + if (vm.count("help")) + { + std::cout << desc << "\n"; + return false; + } + + po::notify(vm); + } + catch(std::exception& e) + { + std::cerr << "Error: " << e.what() << "\n"; + return false; + } + + return true; +} +#endif + +using namespace libsnark; + +int main(int argc, const char * argv[]) +{ + typedef Fr FieldT; + typedef ram_tinyram default_ram; + + default_ec_pp::init_public_params(); + +#ifdef MINDEPS + std::string assembly_fn = "assembly.s"; + std::string processed_assembly_fn = "processed.txt"; + std::string architecture_params_fn = "architecture_params.txt"; + std::string computation_bounds_fn = "computation_bounds.txt"; + std::string primary_input_fn = "primary_input.txt"; + std::string auxiliary_input_fn = "auxiliary_input.txt"; +#else + std::string assembly_fn; + std::string processed_assembly_fn; + std::string architecture_params_fn; + std::string computation_bounds_fn; + std::string primary_input_fn; + std::string auxiliary_input_fn; + + if (!process_arithm_command_line(argc, argv, assembly_fn, processed_assembly_fn, architecture_params_fn, + computation_bounds_fn, primary_input_fn, auxiliary_input_fn)) + { + return 1; + } +#endif + start_profiling(); + + printf("================================================================================\n"); + printf("TinyRAM example loader\n"); + printf("================================================================================\n\n"); + + /* load everything */ + ram_architecture_params ap; + std::ifstream f_ap(architecture_params_fn); + f_ap >> ap; + + printf("Will run on %zu register machine (word size = %zu)\n", ap.k, ap.w); + + std::ifstream f_rp(computation_bounds_fn); + size_t tinyram_input_size_bound, tinyram_program_size_bound, time_bound; + f_rp >> tinyram_input_size_bound >> tinyram_program_size_bound >> time_bound; + + std::ifstream processed(processed_assembly_fn); + std::ifstream raw(assembly_fn); + tinyram_program program = load_preprocessed_program(ap, processed); + printf("Program:\n%s\n", std::string((std::istreambuf_iterator(raw)), + std::istreambuf_iterator()).c_str()); + + std::ifstream f_primary_input(primary_input_fn); + std::ifstream f_auxiliary_input(auxiliary_input_fn); + + enter_block("Loading primary input"); + tinyram_input_tape primary_input(load_tape(f_primary_input)); + leave_block("Loading primary input"); + + enter_block("Loading auxiliary input"); + tinyram_input_tape auxiliary_input = load_tape(f_auxiliary_input); + leave_block("Loading auxiliary input"); + + const size_t boot_trace_size_bound = tinyram_input_size_bound + tinyram_program_size_bound; + const ram_boot_trace boot_trace = tinyram_boot_trace_from_program_and_input(ap, boot_trace_size_bound, program, primary_input); + + typedef ram_ppzksnark_machine_pp default_ram; + + ram_to_r1cs r(ap, boot_trace_size_bound, time_bound); + r.instance_map(); + + const r1cs_primary_input r1cs_primary_input = ram_to_r1cs::primary_input_map(ap, boot_trace_size_bound, boot_trace); + const r1cs_auxiliary_input r1cs_auxiliary_input = r.auxiliary_input_map(boot_trace, auxiliary_input); + const r1cs_constraint_system constraint_system = r.get_constraint_system(); + + r.print_execution_trace(); + assert(constraint_system.is_satisfied(r1cs_primary_input, r1cs_auxiliary_input)); +} diff --git a/privacy/zsl/zsl/reductions/ram_to_r1cs/gadgets/memory_checker_gadget.hpp b/privacy/zsl/zsl/reductions/ram_to_r1cs/gadgets/memory_checker_gadget.hpp new file mode 100644 index 0000000..7ec8fcd --- /dev/null +++ b/privacy/zsl/zsl/reductions/ram_to_r1cs/gadgets/memory_checker_gadget.hpp @@ -0,0 +1,58 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for memory_checker_gadget, a gadget that verifies the + consistency of two accesses to memory that are adjacent in a "memory sort". + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MEMORY_CHECKER_GADGET_HPP_ +#define MEMORY_CHECKER_GADGET_HPP_ + +#include "reductions/ram_to_r1cs/gadgets/trace_lines.hpp" + +namespace libsnark { + +template +class memory_checker_gadget : public ram_gadget_base { +private: + + typedef ram_base_field FieldT; + + pb_variable timestamps_leq; + pb_variable timestamps_less; + std::shared_ptr > compare_timestamps; + + pb_variable addresses_eq; + pb_variable addresses_leq; + pb_variable addresses_less; + std::shared_ptr > compare_addresses; + + pb_variable loose_contents_after1_equals_contents_before2; + pb_variable loose_contents_before2_equals_zero; + pb_variable loose_timestamp2_is_zero; + +public: + + memory_line_variable_gadget line1; + memory_line_variable_gadget line2; + + memory_checker_gadget(ram_protoboard &pb, + const size_t timestamp_size, + const memory_line_variable_gadget &line1, + const memory_line_variable_gadget &line2, + const std::string& annotation_prefix=""); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "reductions/ram_to_r1cs/gadgets/memory_checker_gadget.tcc" + +#endif // MEMORY_CHECKER_GADGET_HPP_ diff --git a/privacy/zsl/zsl/reductions/ram_to_r1cs/gadgets/memory_checker_gadget.tcc b/privacy/zsl/zsl/reductions/ram_to_r1cs/gadgets/memory_checker_gadget.tcc new file mode 100644 index 0000000..f302d44 --- /dev/null +++ b/privacy/zsl/zsl/reductions/ram_to_r1cs/gadgets/memory_checker_gadget.tcc @@ -0,0 +1,134 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for memory_checker_gadget. + + See memory_checker_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MEMORY_CHECKER_GADGET_TCC_ +#define MEMORY_CHECKER_GADGET_TCC_ + +namespace libsnark { + +template +memory_checker_gadget::memory_checker_gadget(ram_protoboard &pb, + const size_t timestamp_size, + const memory_line_variable_gadget &line1, + const memory_line_variable_gadget &line2, + const std::string& annotation_prefix) : + ram_gadget_base(pb, annotation_prefix), line1(line1), line2(line2) +{ + /* compare the two timestamps */ + timestamps_leq.allocate(pb, FMT(this->annotation_prefix, " timestamps_leq")); + timestamps_less.allocate(pb, FMT(this->annotation_prefix, " timestamps_less")); + compare_timestamps.reset(new comparison_gadget(pb, timestamp_size, line1.timestamp->packed, line2.timestamp->packed, timestamps_less, timestamps_leq, + FMT(this->annotation_prefix, " compare_ts"))); + + + /* compare the two addresses */ + const size_t address_size = pb.ap.address_size(); + addresses_eq.allocate(pb, FMT(this->annotation_prefix, " addresses_eq")); + addresses_leq.allocate(pb, FMT(this->annotation_prefix, " addresses_leq")); + addresses_less.allocate(pb, FMT(this->annotation_prefix, " addresses_less")); + compare_addresses.reset(new comparison_gadget(pb, address_size, line1.address->packed, line2.address->packed, addresses_less, addresses_leq, + FMT(this->annotation_prefix, " compare_addresses"))); + + /* + Add variables that will contain flags representing the following relations: + - "line1.contents_after = line2.contents_before" (to check that contents do not change between instructions); + - "line2.contents_before = 0" (for the first access at an address); and + - "line2.timestamp = 0" (for wrap-around checks to ensure only one 'cycle' in the memory sort). + + More precisely, each of the above flags is "loose" (i.e., it equals 0 if + the relation holds, but can be either 0 or 1 if the relation does not hold). + */ + loose_contents_after1_equals_contents_before2.allocate(pb, FMT(this->annotation_prefix, " loose_contents_after1_equals_contents_before2")); + loose_contents_before2_equals_zero.allocate(pb, FMT(this->annotation_prefix, " loose_contents_before2_equals_zero")); + loose_timestamp2_is_zero.allocate(pb, FMT(this->annotation_prefix, " loose_timestamp2_is_zero")); +} + +template +void memory_checker_gadget::generate_r1cs_constraints() +{ + /* compare the two timestamps */ + compare_timestamps->generate_r1cs_constraints(); + + /* compare the two addresses */ + compare_addresses->generate_r1cs_constraints(); + this->pb.add_r1cs_constraint(r1cs_constraint(addresses_leq, 1 - addresses_less, addresses_eq), FMT(this->annotation_prefix, " addresses_eq")); + + /* + Add constraints for the following three flags: + - loose_contents_after1_equals_contents_before2; + - loose_contents_before2_equals_zero; + - loose_timestamp2_is_zero. + */ + this->pb.add_r1cs_constraint(r1cs_constraint(loose_contents_after1_equals_contents_before2, + line1.contents_after->packed - line2.contents_before->packed, 0), + FMT(this->annotation_prefix, " loose_contents_after1_equals_contents_before2")); + generate_boolean_r1cs_constraint(this->pb, loose_contents_after1_equals_contents_before2, FMT(this->annotation_prefix, " loose_contents_after1_equals_contents_before2")); + + this->pb.add_r1cs_constraint(r1cs_constraint(loose_contents_before2_equals_zero, + line2.contents_before->packed, 0), + FMT(this->annotation_prefix, " loose_contents_before2_equals_zero")); + generate_boolean_r1cs_constraint(this->pb, loose_contents_before2_equals_zero, FMT(this->annotation_prefix, " loose_contents_before2_equals_zero")); + + this->pb.add_r1cs_constraint(r1cs_constraint(loose_timestamp2_is_zero, + line2.timestamp->packed, 0), + FMT(this->annotation_prefix, " loose_timestamp2_is_zero")); + generate_boolean_r1cs_constraint(this->pb, loose_timestamp2_is_zero, FMT(this->annotation_prefix, " loose_timestamp2_is_zero")); + + /* + The three cases that need to be checked are: + + line1.address = line2.address => line1.contents_after = line2.contents_before + (i.e. contents do not change between accesses to the same address) + + line1.address < line2.address => line2.contents_before = 0 + (i.e. access to new address has the "before" value set to 0) + + line1.address > line2.address => line2.timestamp = 0 + (i.e. there is only one cycle with non-decreasing addresses, except + for the case where we go back to a unique pre-set timestamp; we choose + timestamp 0 to be the one that touches address 0) + + As usual, we implement "A => B" as "NOT (A AND (NOT B))". + */ + this->pb.add_r1cs_constraint(r1cs_constraint(addresses_eq, 1 - loose_contents_after1_equals_contents_before2, 0), + FMT(this->annotation_prefix, " memory_retains_contents_between_accesses")); + this->pb.add_r1cs_constraint(r1cs_constraint(addresses_less, 1 - loose_contents_before2_equals_zero, 0), + FMT(this->annotation_prefix, " new_address_starts_at_zero")); + this->pb.add_r1cs_constraint(r1cs_constraint(1 - addresses_leq, 1 - loose_timestamp2_is_zero, 0), + FMT(this->annotation_prefix, " only_one_cycle")); +} + +template +void memory_checker_gadget::generate_r1cs_witness() +{ + /* compare the two addresses */ + compare_addresses->generate_r1cs_witness(); + this->pb.val(addresses_eq) = this->pb.val(addresses_leq) * (FieldT::one() - this->pb.val(addresses_less)); + + /* compare the two timestamps */ + compare_timestamps->generate_r1cs_witness(); + + /* + compare the values of: + - loose_contents_after1_equals_contents_before2; + - loose_contents_before2_equals_zero; + - loose_timestamp2_is_zero. + */ + this->pb.val(loose_contents_after1_equals_contents_before2) = (this->pb.val(line1.contents_after->packed) == this->pb.val(line2.contents_before->packed)) ? FieldT::one() : FieldT::zero(); + this->pb.val(loose_contents_before2_equals_zero) = this->pb.val(line2.contents_before->packed).is_zero() ? FieldT::one() : FieldT::zero(); + this->pb.val(loose_timestamp2_is_zero) = (this->pb.val(line2.timestamp->packed) == FieldT::zero() ? FieldT::one() : FieldT::zero()); +} + +} // libsnark + +#endif // MEMORY_CHECKER_GADGET_TCC_ diff --git a/privacy/zsl/zsl/reductions/ram_to_r1cs/gadgets/ram_universal_gadget.hpp b/privacy/zsl/zsl/reductions/ram_to_r1cs/gadgets/ram_universal_gadget.hpp new file mode 100644 index 0000000..c6d05c2 --- /dev/null +++ b/privacy/zsl/zsl/reductions/ram_to_r1cs/gadgets/ram_universal_gadget.hpp @@ -0,0 +1,138 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for ram_universal_gadget. + + Given bounds on a RAM computation size (program size bound, primary input + size bound, and time bound), the "RAM universal gadget" checks the correct + execution of any RAM computation that fits the bounds. + + The implementaiton follows, extends, and optimizes the approach described + in \[BCTV14] (itself building on \[BCGTV13]). The code is parameterized by + the template parameter ramT, in order to support any RAM that fits certain + abstract interfaces. + + Roughly, the gadget has three main components: + - For each time step, a copy of a *execution checker* (which is the RAM CPU checker). + - For each time step, a copy of a *memory checker* (which verifies memory consitency + between two 'memory lines' that are adjacent in a memory sort). + - A single *routing network* (specifically, an arbitrary-size Waksman network), + which is used check that memory accesses are permutated according to some permutation. + + References: + + \[BCGTV13]: + "SNARKs for C: verifying program executions succinctly and in zero knowledge", + Eli Ben-Sasson, Alessandro Chiesa, Daniel Genkin, Eran Tromer, Madars Virza, + CRYPTO 2014, + + + \[BCTV14]: + "Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture", + Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, + USENIX Security 2014, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_UNIVERSAL_GADGET_HPP_ +#define RAM_UNIVERSAL_GADGET_HPP_ + +#include "gadgetlib1/gadgets/routing/as_waksman_routing_gadget.hpp" +#include "reductions/ram_to_r1cs/gadgets/memory_checker_gadget.hpp" +#include "reductions/ram_to_r1cs/gadgets/trace_lines.hpp" +#include "relations/ram_computations/rams/ram_params.hpp" + +namespace libsnark { + +/* + Memory layout for our reduction is as follows: + + (1) An initial execution line carrying the initial state (set + to all zeros) + (2) program_size_bound + primary_input_size_bound memory lines for + storing input and program (boot) + (3) time_bound pairs for (fetch instruction memory line, execute + instruction execution line) + + Memory line stores address, previous value and the next value of the + memory cell specified by the address. An execution line additionally + carries the CPU state. + + Our memory handling technique has a technical requirement that + address 0 must be accessed. We fulfill this by requiring the initial + execution line to act as "store 0 to address 0". + + --- + + As an implementation detail if less than program_size_bound + + primary_input_size_bound are used in the initial memory map, then we + pre-pend (!) them with "store 0 to address 0" lines. This + pre-pending means that memory maps that have non-zero value at + address 0 will still be handled correctly. + + The R1CS input packs the memory map starting from the last entry to + the first. This way, the prepended zeros arrive at the end of R1CS + input and thus can be ignored by the "weak" input consistency R1CS + verifier. +*/ + +template +class ram_universal_gadget : public ram_gadget_base { +public: + typedef ram_base_field FieldT; + + size_t num_memory_lines; + + std::vector > boot_lines; + std::vector > boot_line_bits; + std::vector > unpack_boot_lines; + + std::vector > load_instruction_lines; + std::vector > execution_lines; /* including the initial execution line */ + + std::vector* > unrouted_memory_lines; + std::vector > routed_memory_lines; + + std::vector > execution_checkers; + std::vector > memory_checkers; + + std::vector > routing_inputs; + std::vector > routing_outputs; + + std::shared_ptr > routing_network; + +public: + + size_t boot_trace_size_bound; + size_t time_bound; + pb_variable_array packed_input; + + ram_universal_gadget(ram_protoboard &pb, + const size_t boot_trace_size_bound, + const size_t time_bound, + const pb_variable_array &packed_input, + const std::string &annotation_prefix=""); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(const ram_boot_trace &boot_trace, + const ram_input_tape &auxiliary_input); + + /* both methods assume that generate_r1cs_witness has been called */ + void print_execution_trace() const; + void print_memory_trace() const; + + static size_t packed_input_element_size(const ram_architecture_params &ap); + static size_t packed_input_size(const ram_architecture_params &ap, + const size_t boot_trace_size_bound); +}; + +} // libsnark + +#include "reductions/ram_to_r1cs/gadgets/ram_universal_gadget.tcc" + +#endif // RAM_UNIVERSAL_GADGET_HPP_ diff --git a/privacy/zsl/zsl/reductions/ram_to_r1cs/gadgets/ram_universal_gadget.tcc b/privacy/zsl/zsl/reductions/ram_to_r1cs/gadgets/ram_universal_gadget.tcc new file mode 100644 index 0000000..00d2333 --- /dev/null +++ b/privacy/zsl/zsl/reductions/ram_to_r1cs/gadgets/ram_universal_gadget.tcc @@ -0,0 +1,433 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for ram_universal_gadget. + + See ram_universal_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_UNIVERSAL_GADGET_TCC_ +#define RAM_UNIVERSAL_GADGET_TCC_ + +#include "common/data_structures/integer_permutation.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "algebra/fields/field_utils.hpp" +#include "relations/ram_computations/memory/ra_memory.hpp" + +namespace libsnark { + +template +ram_universal_gadget::ram_universal_gadget(ram_protoboard &pb, + const size_t boot_trace_size_bound, + const size_t time_bound, + const pb_variable_array &packed_input, + const std::string &annotation_prefix) : + ram_gadget_base(pb, annotation_prefix), + boot_trace_size_bound(boot_trace_size_bound), + time_bound(time_bound), + packed_input(packed_input) +{ + num_memory_lines = boot_trace_size_bound + (time_bound + 1) + time_bound; /* boot lines, (time_bound + 1) execution lines (including initial) and time_bound load instruction lines */ + const size_t timestamp_size = log2(num_memory_lines); + + /* allocate all lines on the execution side of the routing network */ + enter_block("Allocate initial state line"); + execution_lines.reserve(1 + time_bound); + execution_lines.emplace_back(execution_line_variable_gadget(pb, timestamp_size, pb.ap, FMT(annotation_prefix, " execution_lines_%zu", 0))); + unrouted_memory_lines.emplace_back(&execution_lines[0]); + leave_block("Allocate initial state line"); + + enter_block("Allocate boot lines"); + boot_lines.reserve(boot_trace_size_bound); + for (size_t i = 0; i < boot_trace_size_bound; ++i) + { + boot_lines.emplace_back(memory_line_variable_gadget(pb, timestamp_size, pb.ap, FMT(annotation_prefix, " boot_lines_%zu", i))); + unrouted_memory_lines.emplace_back(&boot_lines[i]); + } + leave_block("Allocate boot lines"); + + enter_block("Allocate instruction fetch and execution lines"); + load_instruction_lines.reserve(time_bound+1); /* the last line is NOT a memory line, but here just for uniform coding (i.e. the (unusued) result of next PC) */ + for (size_t i = 0; i < time_bound; ++i) + { + load_instruction_lines.emplace_back(memory_line_variable_gadget(pb, timestamp_size, pb.ap, FMT(annotation_prefix, " load_instruction_lines_%zu", i))); + unrouted_memory_lines.emplace_back(&load_instruction_lines[i]); + + execution_lines.emplace_back(execution_line_variable_gadget(pb, timestamp_size, pb.ap, FMT(annotation_prefix, " execution_lines_%zu", i+1))); + unrouted_memory_lines.emplace_back(&execution_lines[i+1]); + } + load_instruction_lines.emplace_back(memory_line_variable_gadget(pb, timestamp_size, pb.ap, FMT(annotation_prefix, " load_instruction_lines_%zu", time_bound))); + leave_block("Allocate instruction fetch and execution lines"); + + /* deal with packing of the input */ + enter_block("Pack input"); + const size_t line_size_bits = pb.ap.address_size() + pb.ap.value_size(); + const size_t max_chunk_size = FieldT::capacity(); + const size_t packed_line_size = div_ceil(line_size_bits, max_chunk_size); + assert(packed_input.size() == packed_line_size * boot_trace_size_bound); + + auto input_it = packed_input.begin(); + for (size_t i = 0; i < boot_trace_size_bound; ++i) + { + /* note the reversed order */ + pb_variable_array boot_line_bits; + boot_line_bits.insert(boot_line_bits.end(), boot_lines[boot_trace_size_bound-1-i].address->bits.begin(), boot_lines[boot_trace_size_bound-1-i].address->bits.end()); + boot_line_bits.insert(boot_line_bits.end(), boot_lines[boot_trace_size_bound-1-i].contents_after->bits.begin(), boot_lines[boot_trace_size_bound-1-i].contents_after->bits.end()); + + pb_variable_array packed_boot_line = pb_variable_array(input_it, input_it + packed_line_size); + std::advance(input_it, packed_line_size); + + unpack_boot_lines.emplace_back(multipacking_gadget(pb, boot_line_bits, packed_boot_line, max_chunk_size, FMT(annotation_prefix, " unpack_boot_lines_%zu", i))); + } + leave_block("Pack input"); + + /* deal with routing */ + enter_block("Allocate routed memory lines"); + for (size_t i = 0; i < num_memory_lines; ++i) + { + routed_memory_lines.emplace_back(memory_line_variable_gadget(pb, timestamp_size, pb.ap, FMT(annotation_prefix, " routed_memory_lines_%zu", i))); + } + leave_block("Allocate routed memory lines"); + + enter_block("Collect inputs/outputs for the routing network"); + routing_inputs.reserve(num_memory_lines); + routing_outputs.reserve(num_memory_lines); + + for (size_t i = 0; i < num_memory_lines; ++i) + { + routing_inputs.emplace_back(unrouted_memory_lines[i]->all_vars()); + routing_outputs.emplace_back(routed_memory_lines[i].all_vars()); + } + leave_block("Collect inputs/outputs for the routing network"); + + enter_block("Allocate routing network"); + routing_network.reset(new as_waksman_routing_gadget(pb, num_memory_lines, routing_inputs, routing_outputs, FMT(this->annotation_prefix, " routing_network"))); + leave_block("Allocate routing network"); + + /* deal with all checkers */ + enter_block("Allocate execution checkers"); + execution_checkers.reserve(time_bound); + for (size_t i = 0; i < time_bound; ++i) + { + execution_checkers.emplace_back(ram_cpu_checker(pb, + load_instruction_lines[i].address->bits, // prev_pc_addr + load_instruction_lines[i].contents_after->bits, // prev_pc_val + execution_lines[i].cpu_state, // prev_state + execution_lines[i+1].address->bits, // ls_addr, + execution_lines[i+1].contents_before->bits, // ls_prev_val + execution_lines[i+1].contents_after->bits, // ls_next_val + execution_lines[i+1].cpu_state, // next_state + load_instruction_lines[i+1].address->bits, // next_pc_addr + execution_lines[i+1].has_accepted, // next_has_accepted + FMT(annotation_prefix, " execution_checkers_%zu", i))); + } + leave_block("Allocate execution checkers"); + + enter_block("Allocate all memory checkers"); + memory_checkers.reserve(num_memory_lines); + for (size_t i = 0; i < num_memory_lines; ++i) + { + memory_checkers.emplace_back(memory_checker_gadget(pb, + timestamp_size, + *unrouted_memory_lines[i], + routed_memory_lines[i], + FMT(this->annotation_prefix, " memory_checkers_%zu", i))); + } + leave_block("Allocate all memory checkers"); + + /* done */ +} + +template +void ram_universal_gadget::generate_r1cs_constraints() +{ + enter_block("Call to generate_r1cs_constraints of ram_universal_gadget"); + for (size_t i = 0; i < boot_trace_size_bound; ++i) + { + unpack_boot_lines[i].generate_r1cs_constraints(false); + } + + /* ensure that we start with all zeros state */ + for (size_t i = 0; i < this->pb.ap.cpu_state_size(); ++i) + { + generate_r1cs_equals_const_constraint(this->pb, execution_lines[0].cpu_state[i], FieldT::zero()); + } + + /* ensure increasing timestamps */ + for (size_t i = 0; i < num_memory_lines; ++i) + { + generate_r1cs_equals_const_constraint(this->pb, unrouted_memory_lines[i]->timestamp->packed, FieldT(i)); + } + + /* ensure bitness of trace lines on the time side */ + for (size_t i = 0; i < boot_trace_size_bound; ++i) + { + boot_lines[i].generate_r1cs_constraints(true); + } + + execution_lines[0].generate_r1cs_constraints(true); + for (size_t i = 0; i < time_bound; ++i) + { + load_instruction_lines[i].generate_r1cs_constraints(true); + execution_lines[i+1].generate_r1cs_constraints(true); + } + + /* ensure bitness of trace lines on the memory side */ + for (size_t i = 0; i < num_memory_lines; ++i) + { + routed_memory_lines[i].generate_r1cs_constraints(); + } + + /* ensure that load instruction lines really do loads */ + for (size_t i = 0; i < time_bound; ++i) + { + this->pb.add_r1cs_constraint(r1cs_constraint(1, load_instruction_lines[i].contents_before->packed, + load_instruction_lines[i].contents_after->packed), + FMT(this->annotation_prefix, " load_instruction_%zu_is_a_load", i)); + } + + /* ensure correct execution */ + for (size_t i = 0; i < time_bound; ++i) + { + execution_checkers[i].generate_r1cs_constraints(); + } + + /* check memory */ + routing_network->generate_r1cs_constraints(); + + for (size_t i = 0; i < num_memory_lines; ++i) + { + memory_checkers[i].generate_r1cs_constraints(); + } + + /* ensure that PC started at the prescribed value */ + generate_r1cs_equals_const_constraint(this->pb, load_instruction_lines[0].address->packed, FieldT(this->pb.ap.initial_pc_addr())); + + /* ensure that the last state was an accepting one */ + generate_r1cs_equals_const_constraint(this->pb, execution_lines[time_bound].has_accepted, FieldT::one(), "last_state_must_be_accepting"); + + /* print constraint profiling */ + const size_t num_constraints = this->pb.num_constraints(); + const size_t num_variables = this->pb.num_variables(); + + if (!inhibit_profiling_info) + { + print_indent(); printf("* Number of constraints: %zu\n", num_constraints); + print_indent(); printf("* Number of constraints / cycle: %0.1f\n", 1.*num_constraints/this->time_bound); + + print_indent(); printf("* Number of variables: %zu\n", num_variables); + print_indent(); printf("* Number of variables / cycle: %0.1f\n", 1.*num_variables/this->time_bound); + } + leave_block("Call to generate_r1cs_constraints of ram_universal_gadget"); +} + +template +void ram_universal_gadget::generate_r1cs_witness(const ram_boot_trace &boot_trace, + const ram_input_tape &auxiliary_input) +{ + /* assign correct timestamps to all lines */ + for (size_t i = 0; i < num_memory_lines; ++i) + { + this->pb.val(unrouted_memory_lines[i]->timestamp->packed) = FieldT(i); + unrouted_memory_lines[i]->timestamp->generate_r1cs_witness_from_packed(); + } + + /* fill in the initial state */ + const ram_cpu_state initial_state = this->pb.ap.initial_cpu_state(); + execution_lines[0].cpu_state.fill_with_bits(this->pb, initial_state); + + /* fill in the boot section */ + memory_contents memory_after_boot; + + for (auto it : boot_trace.get_all_trace_entries()) + { + const size_t boot_pos = it.first; + assert(boot_pos < boot_trace_size_bound); + const size_t address = it.second.first; + const size_t contents = it.second.second; + + this->pb.val(boot_lines[boot_pos].address->packed) = FieldT(address, true); + this->pb.val(boot_lines[boot_pos].contents_after->packed) = FieldT(contents, true); + boot_lines[boot_pos].generate_r1cs_witness_from_packed(); + + memory_after_boot[address] = contents; + } + + /* do the actual execution */ + ra_memory mem_backend(1ul<<(this->pb.ap.address_size()), this->pb.ap.value_size(), memory_after_boot); + typename ram_input_tape::const_iterator auxiliary_input_it = auxiliary_input.begin(); + + this->pb.val(load_instruction_lines[0].address->packed) = FieldT(this->pb.ap.initial_pc_addr(), true); + load_instruction_lines[0].address->generate_r1cs_witness_from_packed(); + + for (size_t i = 0; i < time_bound; ++i) + { + /* load instruction */ + const size_t pc_addr = this->pb.val(load_instruction_lines[i].address->packed).as_ulong(); + const size_t pc_val = mem_backend.get_value(pc_addr); + + this->pb.val(load_instruction_lines[i].contents_before->packed) = FieldT(pc_val, true); + this->pb.val(load_instruction_lines[i].contents_after->packed) = FieldT(pc_val, true); + load_instruction_lines[i].generate_r1cs_witness_from_packed(); + + /* first fetch the address part of the memory */ + execution_checkers[i].generate_r1cs_witness_address(); + execution_lines[i+1].address->generate_r1cs_witness_from_bits(); + + /* fill it in */ + const size_t load_store_addr = this->pb.val(execution_lines[i+1].address->packed).as_ulong(); + const size_t load_store_prev_val = mem_backend.get_value(load_store_addr); + + this->pb.val(execution_lines[i+1].contents_before->packed) = FieldT(load_store_prev_val, true); + execution_lines[i+1].contents_before->generate_r1cs_witness_from_packed(); + + /* then execute the rest of the instruction */ + execution_checkers[i].generate_r1cs_witness_other(auxiliary_input_it, auxiliary_input.end()); + + /* update the memory possibly changed by the CPU checker */ + execution_lines[i+1].contents_after->generate_r1cs_witness_from_bits(); + const size_t load_store_next_val = this->pb.val(execution_lines[i+1].contents_after->packed).as_ulong(); + mem_backend.set_value(load_store_addr, load_store_next_val); + + /* the next PC address was passed in a bit form, so maintain packed form as well */ + load_instruction_lines[i+1].address->generate_r1cs_witness_from_bits(); + } + + /* + Get the correct memory permutation. + + We sort all memory accesses by address breaking ties by + timestamp. In our routing configuration we pair each memory + access with subsequent access in this ordering. + + That way num_memory_pairs of memory checkers will do a full + cycle over all memory accesses, enforced by the proper ordering + property. + */ + + typedef std::pair mem_pair; /* a pair of address, timestamp */ + std::vector mem_pairs; + + for (size_t i = 0; i < this->num_memory_lines; ++i) + { + mem_pairs.emplace_back(std::make_pair(this->pb.val(unrouted_memory_lines[i]->address->packed).as_ulong(), + this->pb.val(unrouted_memory_lines[i]->timestamp->packed).as_ulong())); + } + + std::sort(mem_pairs.begin(), mem_pairs.end()); + + integer_permutation pi(this->num_memory_lines); + for (size_t i = 0; i < this->num_memory_lines; ++i) + { + const size_t timestamp = this->pb.val(unrouted_memory_lines[i]->timestamp->packed).as_ulong(); + const size_t address = this->pb.val(unrouted_memory_lines[i]->address->packed).as_ulong(); + + const auto it = std::upper_bound(mem_pairs.begin(), mem_pairs.end(), std::make_pair(address, timestamp)); + const size_t prev = (it == mem_pairs.end() ? 0 : it->second); + pi.set(prev, i); + } + + /* route according to the memory permutation */ + routing_network->generate_r1cs_witness(pi); + + for (size_t i = 0; i < this->num_memory_lines; ++i) + { + routed_memory_lines[i].generate_r1cs_witness_from_bits(); + } + + /* generate witness for memory checkers */ + for (size_t i = 0; i < this->num_memory_lines; ++i) + { + memory_checkers[i].generate_r1cs_witness(); + } + + /* repack back the input */ + for (size_t i = 0; i < boot_trace_size_bound; ++i) + { + unpack_boot_lines[i].generate_r1cs_witness_from_bits(); + } + + /* print debugging information */ + if (!inhibit_profiling_info) + { + print_indent(); + printf("* Protoboard satisfied: %s\n", (this->pb.is_satisfied() ? "YES" : "no")); + } +} + +template +void ram_universal_gadget::print_execution_trace() const +{ + for (size_t i = 0; i < boot_trace_size_bound; ++i) + { + printf("Boot process at t=#%zu: store %zu at %zu\n", + i, + this->pb.val(boot_lines[i].contents_after->packed).as_ulong(), + this->pb.val(boot_lines[i].address->packed).as_ulong()); + } + + for (size_t i = 0; i < time_bound; ++i) + { + printf("Execution step %zu:\n", i); + printf(" Loaded instruction %zu from address %zu (ts = %zu)\n", + this->pb.val(load_instruction_lines[i].contents_after->packed).as_ulong(), + this->pb.val(load_instruction_lines[i].address->packed).as_ulong(), + this->pb.val(load_instruction_lines[i].timestamp->packed).as_ulong()); + + printf(" Debugging information from the transition function:\n"); + execution_checkers[i].dump(); + + printf(" Memory operation executed: addr = %zu, contents_before = %zu, contents_after = %zu (ts_before = %zu, ts_after = %zu)\n", + this->pb.val(execution_lines[i+1].address->packed).as_ulong(), + this->pb.val(execution_lines[i+1].contents_before->packed).as_ulong(), + this->pb.val(execution_lines[i+1].contents_after->packed).as_ulong(), + this->pb.val(execution_lines[i].timestamp->packed).as_ulong(), + this->pb.val(execution_lines[i+1].timestamp->packed).as_ulong()); + } +} + +template +void ram_universal_gadget::print_memory_trace() const +{ + for (size_t i = 0; i < num_memory_lines; ++i) + { + printf("Memory access #%zu:\n", i); + printf(" Time side : ts = %zu, address = %zu, contents_before = %zu, contents_after = %zu\n", + this->pb.val(unrouted_memory_lines[i]->timestamp->packed).as_ulong(), + this->pb.val(unrouted_memory_lines[i]->address->packed).as_ulong(), + this->pb.val(unrouted_memory_lines[i]->contents_before->packed).as_ulong(), + this->pb.val(unrouted_memory_lines[i]->contents_after->packed).as_ulong()); + printf(" Memory side: ts = %zu, address = %zu, contents_before = %zu, contents_after = %zu\n", + this->pb.val(routed_memory_lines[i].timestamp->packed).as_ulong(), + this->pb.val(routed_memory_lines[i].address->packed).as_ulong(), + this->pb.val(routed_memory_lines[i].contents_before->packed).as_ulong(), + this->pb.val(routed_memory_lines[i].contents_after->packed).as_ulong()); + } +} + +template +size_t ram_universal_gadget::packed_input_element_size(const ram_architecture_params &ap) +{ + const size_t line_size_bits = ap.address_size() + ap.value_size(); + const size_t max_chunk_size = FieldT::capacity(); + const size_t packed_line_size = div_ceil(line_size_bits, max_chunk_size); + + return packed_line_size; +} + +template +size_t ram_universal_gadget::packed_input_size(const ram_architecture_params &ap, + const size_t boot_trace_size_bound) +{ + return packed_input_element_size(ap) * boot_trace_size_bound; +} + +} // libsnark + +#endif // RAM_UNIVERSAL_GADGET_TCC_ diff --git a/privacy/zsl/zsl/reductions/ram_to_r1cs/gadgets/trace_lines.hpp b/privacy/zsl/zsl/reductions/ram_to_r1cs/gadgets/trace_lines.hpp new file mode 100644 index 0000000..f14eceb --- /dev/null +++ b/privacy/zsl/zsl/reductions/ram_to_r1cs/gadgets/trace_lines.hpp @@ -0,0 +1,79 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for trace-line variables. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TRACE_LINES_HPP_ +#define TRACE_LINES_HPP_ + +#include +#include "relations/ram_computations/rams/ram_params.hpp" + +namespace libsnark { + +/** + * A memory line contains variables for the following: + * - timestamp + * - address + * - contents_before + * - contents_after + * + * Memory lines are used by memory_checker_gadget. + */ +template +class memory_line_variable_gadget : public ram_gadget_base { +public: + + typedef ram_base_field FieldT; + + std::shared_ptr > timestamp; + std::shared_ptr > address; + std::shared_ptr > contents_before; + std::shared_ptr > contents_after; + +public: + + memory_line_variable_gadget(ram_protoboard &pb, + const size_t timestamp_size, + const ram_architecture_params &ap, + const std::string &annotation_prefix=""); + + void generate_r1cs_constraints(const bool enforce_bitness=false); + void generate_r1cs_witness_from_bits(); + void generate_r1cs_witness_from_packed(); + + pb_variable_array all_vars() const; +}; + +/** + * An execution line inherits from a memory line and, in addition, contains + * variables for a CPU state and for a flag denoting if the machine has accepted. + * + * Execution lines are used by execution_checker_gadget. + */ +template +class execution_line_variable_gadget : public memory_line_variable_gadget { +public: + + typedef ram_base_field FieldT; + + pb_variable_array cpu_state; + pb_variable has_accepted; + + execution_line_variable_gadget(ram_protoboard &pb, + const size_t timestamp_size, + const ram_architecture_params &ap, + const std::string &annotation_prefix=""); +}; + +} // libsnark + +#include "reductions/ram_to_r1cs/gadgets/trace_lines.tcc" + +#endif // TRACE_LINES_HPP_ diff --git a/privacy/zsl/zsl/reductions/ram_to_r1cs/gadgets/trace_lines.tcc b/privacy/zsl/zsl/reductions/ram_to_r1cs/gadgets/trace_lines.tcc new file mode 100644 index 0000000..39171de --- /dev/null +++ b/privacy/zsl/zsl/reductions/ram_to_r1cs/gadgets/trace_lines.tcc @@ -0,0 +1,90 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for trace-line variables. + + See trace_lines.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TRACE_LINES_TCC_ +#define TRACE_LINES_TCC_ + +namespace libsnark { + +template +memory_line_variable_gadget::memory_line_variable_gadget(ram_protoboard &pb, + const size_t timestamp_size, + const ram_architecture_params &ap, + const std::string &annotation_prefix) : + ram_gadget_base(pb, annotation_prefix) +{ + const size_t address_size = ap.address_size(); + const size_t value_size = ap.value_size(); + + timestamp.reset(new dual_variable_gadget(pb, timestamp_size, FMT(this->annotation_prefix, " timestamp"))); + address.reset(new dual_variable_gadget(pb, address_size, FMT(this->annotation_prefix, " address"))); + contents_before.reset(new dual_variable_gadget(pb, value_size, FMT(this->annotation_prefix, " contents_before"))); + contents_after.reset(new dual_variable_gadget(pb, value_size, FMT(this->annotation_prefix, " contents_after"))); +} + +template +void memory_line_variable_gadget::generate_r1cs_constraints(const bool enforce_bitness) +{ + timestamp->generate_r1cs_constraints(enforce_bitness); + address->generate_r1cs_constraints(enforce_bitness); + contents_before->generate_r1cs_constraints(enforce_bitness); + contents_after->generate_r1cs_constraints(enforce_bitness); +} + +template +void memory_line_variable_gadget::generate_r1cs_witness_from_bits() +{ + timestamp->generate_r1cs_witness_from_bits(); + address->generate_r1cs_witness_from_bits(); + contents_before->generate_r1cs_witness_from_bits(); + contents_after->generate_r1cs_witness_from_bits(); +} + +template +void memory_line_variable_gadget::generate_r1cs_witness_from_packed() +{ + timestamp->generate_r1cs_witness_from_packed(); + address->generate_r1cs_witness_from_packed(); + contents_before->generate_r1cs_witness_from_packed(); + contents_after->generate_r1cs_witness_from_packed(); +} + +template +pb_variable_array > memory_line_variable_gadget::all_vars() const +{ + pb_variable_array r; + r.insert(r.end(), timestamp->bits.begin(), timestamp->bits.end()); + r.insert(r.end(), address->bits.begin(), address->bits.end()); + r.insert(r.end(), contents_before->bits.begin(), contents_before->bits.end()); + r.insert(r.end(), contents_after->bits.begin(), contents_after->bits.end()); + + return r; +} + +template +execution_line_variable_gadget::execution_line_variable_gadget(ram_protoboard &pb, + const size_t timestamp_size, + const ram_architecture_params &ap, + const std::string &annotation_prefix) : + memory_line_variable_gadget(pb, timestamp_size, ap, annotation_prefix) +{ + const size_t cpu_state_size = ap.cpu_state_size(); + + cpu_state.allocate(pb, cpu_state_size, FMT(annotation_prefix, " cpu_state")); + has_accepted.allocate(pb, FMT(annotation_prefix, " has_accepted")); +} + + +} // libsnark + +#endif // TRACE_LINES_TCC_ diff --git a/privacy/zsl/zsl/reductions/ram_to_r1cs/ram_to_r1cs.hpp b/privacy/zsl/zsl/reductions/ram_to_r1cs/ram_to_r1cs.hpp new file mode 100644 index 0000000..df24d5d --- /dev/null +++ b/privacy/zsl/zsl/reductions/ram_to_r1cs/ram_to_r1cs.hpp @@ -0,0 +1,59 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a RAM-to-R1CS reduction, that is, constructing + a R1CS ("Rank-1 Constraint System") from a RAM ("Random-Access Machine"). + + The implementation is a thin layer around a "RAM universal gadget", which is + where most of the work is done. See gadgets/ram_universal_gadget.hpp for details. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_TO_R1CS_HPP_ +#define RAM_TO_R1CS_HPP_ + +#include "reductions/ram_to_r1cs/gadgets/ram_universal_gadget.hpp" + +namespace libsnark { + +template +class ram_to_r1cs { +public: + + typedef ram_base_field FieldT; + + size_t boot_trace_size_bound; + + ram_protoboard main_protoboard; + pb_variable_array r1cs_input; + std::shared_ptr > universal_gadget; + + ram_to_r1cs(const ram_architecture_params &ap, + const size_t boot_trace_size_bound, + const size_t time_bound); + void instance_map(); + r1cs_constraint_system get_constraint_system() const; + r1cs_auxiliary_input auxiliary_input_map(const ram_boot_trace &boot_trace, + const ram_input_tape &auxiliary_input); + + /* both methods assume that auxiliary_input_map has been called */ + void print_execution_trace() const; + void print_memory_trace() const; + + static std::vector > pack_primary_input_address_and_value(const ram_architecture_params &ap, + const address_and_value &av); + + static r1cs_primary_input > primary_input_map(const ram_architecture_params &ap, + const size_t boot_trace_size_bound, + const ram_boot_trace& boot_trace); +}; + +} // libsnark + +#include "reductions/ram_to_r1cs/ram_to_r1cs.tcc" + +#endif // RAM_TO_R1CS_HPP_ diff --git a/privacy/zsl/zsl/reductions/ram_to_r1cs/ram_to_r1cs.tcc b/privacy/zsl/zsl/reductions/ram_to_r1cs/ram_to_r1cs.tcc new file mode 100644 index 0000000..1056313 --- /dev/null +++ b/privacy/zsl/zsl/reductions/ram_to_r1cs/ram_to_r1cs.tcc @@ -0,0 +1,133 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a RAM-to-R1CS reduction, that is, constructing + a R1CS ("Rank-1 Constraint System") from a RAM ("Random-Access Machine"). + + See ram_to_r1cs.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_TO_R1CS_TCC_ +#define RAM_TO_R1CS_TCC_ + +#include + +namespace libsnark { + +template +ram_to_r1cs::ram_to_r1cs(const ram_architecture_params &ap, + const size_t boot_trace_size_bound, + const size_t time_bound) : + boot_trace_size_bound(boot_trace_size_bound), + main_protoboard(ap) +{ + const size_t r1cs_input_size = ram_universal_gadget::packed_input_size(ap, boot_trace_size_bound); + r1cs_input.allocate(main_protoboard, r1cs_input_size, "r1cs_input"); + universal_gadget.reset(new ram_universal_gadget(main_protoboard, + boot_trace_size_bound, + time_bound, + r1cs_input, + "universal_gadget")); + main_protoboard.set_input_sizes(r1cs_input_size); +} + +template +void ram_to_r1cs::instance_map() +{ + enter_block("Call to instance_map of ram_to_r1cs"); + universal_gadget->generate_r1cs_constraints(); + leave_block("Call to instance_map of ram_to_r1cs"); +} + +template +r1cs_constraint_system > ram_to_r1cs::get_constraint_system() const +{ + return main_protoboard.get_constraint_system(); +} + +template +r1cs_primary_input > ram_to_r1cs::auxiliary_input_map(const ram_boot_trace &boot_trace, + const ram_input_tape &auxiliary_input) +{ + enter_block("Call to witness_map of ram_to_r1cs"); + universal_gadget->generate_r1cs_witness(boot_trace, auxiliary_input); +#ifdef DEBUG + const r1cs_primary_input primary_input_from_input_map = ram_to_r1cs::primary_input_map(main_protoboard.ap, boot_trace_size_bound, boot_trace); + const r1cs_primary_input primary_input_from_witness_map = main_protoboard.primary_input(); + assert(primary_input_from_input_map == primary_input_from_witness_map); +#endif + leave_block("Call to witness_map of ram_to_r1cs"); + return main_protoboard.auxiliary_input(); +} + +template +void ram_to_r1cs::print_execution_trace() const +{ + universal_gadget->print_execution_trace(); +} + +template +void ram_to_r1cs::print_memory_trace() const +{ + universal_gadget->print_memory_trace(); +} + +template +std::vector > ram_to_r1cs::pack_primary_input_address_and_value(const ram_architecture_params &ap, + const address_and_value &av) +{ + typedef ram_base_field FieldT; + + const size_t address = av.first; + const size_t contents = av.second; + + const bit_vector address_bits = convert_field_element_to_bit_vector(FieldT(address, true), ap.address_size()); + const bit_vector contents_bits = convert_field_element_to_bit_vector(FieldT(contents, true), ap.value_size()); + + bit_vector trace_element_bits; + trace_element_bits.insert(trace_element_bits.end(), address_bits.begin(), address_bits.end()); + trace_element_bits.insert(trace_element_bits.end(), contents_bits.begin(), contents_bits.end()); + + const std::vector trace_element = pack_bit_vector_into_field_element_vector(trace_element_bits); + + return trace_element; +} + + +template +r1cs_primary_input > ram_to_r1cs::primary_input_map(const ram_architecture_params &ap, + const size_t boot_trace_size_bound, + const ram_boot_trace& boot_trace) +{ + typedef ram_base_field FieldT; + + const size_t packed_input_element_size = ram_universal_gadget::packed_input_element_size(ap); + r1cs_primary_input result(ram_universal_gadget::packed_input_size(ap, boot_trace_size_bound)); + + std::set bound_input_locations; + + for (auto it : boot_trace.get_all_trace_entries()) + { + const size_t input_pos = it.first; + const address_and_value av = it.second; + + assert(input_pos < boot_trace_size_bound); + assert(bound_input_locations.find(input_pos) == bound_input_locations.end()); + + const std::vector packed_input_element = ram_to_r1cs::pack_primary_input_address_and_value(ap, av); + std::copy(packed_input_element.begin(), packed_input_element.end(), result.begin() + packed_input_element_size * (boot_trace_size_bound - 1 - input_pos)); + + bound_input_locations.insert(input_pos); + } + + return result; +} + +} // libsnark + +#endif // RAM_TO_R1CS_TCC_ diff --git a/privacy/zsl/zsl/reductions/tbcs_to_uscs/get_tbcs_reduction.py b/privacy/zsl/zsl/reductions/tbcs_to_uscs/get_tbcs_reduction.py new file mode 100644 index 0000000..efefd3c --- /dev/null +++ b/privacy/zsl/zsl/reductions/tbcs_to_uscs/get_tbcs_reduction.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python +## +# @author This file is part of libsnark, developed by SCIPR Lab +# and contributors (see AUTHORS). +# @copyright MIT license (see LICENSE file) + +from __future__ import division +import itertools + +def valid_formula(truth_table, x_coeff, y_coeff, z_coeff, offset): + for x in [0,1]: + for y in [0,1]: + z = truth_table[2*x + y] + # we require that z can be set to the correct value, but can *not* be set to the incorrect one + if ((x*x_coeff + y*y_coeff + z*z_coeff + offset not in [-1, 1]) + or + (x*x_coeff + y*y_coeff + (1-z)*z_coeff + offset in [-1, 1])): + return False + return True + +def all_valid_formulas(truth_table, x_coeff_range, y_coeff_range, z_coeff_range, offset_range): + for x_coeff, y_coeff, z_coeff, offset in itertools.product(x_coeff_range, y_coeff_range, z_coeff_range, offset_range): + if valid_formula(truth_table, x_coeff, y_coeff, z_coeff, offset): + yield x_coeff, y_coeff, z_coeff, offset + +if __name__ == '__main__': + x_coeff_range, y_coeff_range, z_coeff_range, offset_range = range(-2, 3), range(-2, 3), range(1, 5), range(-5, 6) + print "Possible coefficients for x: %s, for y: %s, for z: %s, for offset: %s" % (x_coeff_range, y_coeff_range, z_coeff_range, offset_range) + for truth_table in itertools.product([0, 1], repeat=4): + print "Truth table (00, 01, 10, 11):", truth_table + for x_coeff, y_coeff, z_coeff, offset in all_valid_formulas(truth_table, x_coeff_range, y_coeff_range, z_coeff_range, offset_range): + print " %s * x + %s * y + %s * z + %s \in {-1, 1}" % (x_coeff, y_coeff, z_coeff, offset) diff --git a/privacy/zsl/zsl/reductions/tbcs_to_uscs/tbcs_reduction.txt b/privacy/zsl/zsl/reductions/tbcs_to_uscs/tbcs_reduction.txt new file mode 100644 index 0000000..d7ceb0d --- /dev/null +++ b/privacy/zsl/zsl/reductions/tbcs_to_uscs/tbcs_reduction.txt @@ -0,0 +1,33 @@ +Possible coefficients for x: [-2, -1, 0, 1, 2], for y: [-2, -1, 0, 1, 2], for z: [1, 2, 3, 4], for offset: [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5] +Truth table (00, 01, 10, 11): (0, 0, 0, 0) + 0 * x + 0 * y + 1 * z + 1 \in {-1, 1} +Truth table (00, 01, 10, 11): (0, 0, 0, 1) + -2 * x + -2 * y + 4 * z + 1 \in {-1, 1} +Truth table (00, 01, 10, 11): (0, 0, 1, 0) + -2 * x + 2 * y + 4 * z + -1 \in {-1, 1} +Truth table (00, 01, 10, 11): (0, 0, 1, 1) + -1 * x + 0 * y + 1 * z + 1 \in {-1, 1} +Truth table (00, 01, 10, 11): (0, 1, 0, 0) + 2 * x + -2 * y + 4 * z + -1 \in {-1, 1} +Truth table (00, 01, 10, 11): (0, 1, 0, 1) + 0 * x + 1 * y + 1 * z + -1 \in {-1, 1} +Truth table (00, 01, 10, 11): (0, 1, 1, 0) + 1 * x + 1 * y + 1 * z + -1 \in {-1, 1} +Truth table (00, 01, 10, 11): (0, 1, 1, 1) + -2 * x + -2 * y + 4 * z + -1 \in {-1, 1} +Truth table (00, 01, 10, 11): (1, 0, 0, 0) + 2 * x + 2 * y + 4 * z + -3 \in {-1, 1} +Truth table (00, 01, 10, 11): (1, 0, 0, 1) + 1 * x + 1 * y + 1 * z + -2 \in {-1, 1} +Truth table (00, 01, 10, 11): (1, 0, 1, 0) + 0 * x + -1 * y + 1 * z + 0 \in {-1, 1} +Truth table (00, 01, 10, 11): (1, 0, 1, 1) + -2 * x + 2 * y + 4 * z + -3 \in {-1, 1} +Truth table (00, 01, 10, 11): (1, 1, 0, 0) + -1 * x + 0 * y + 1 * z + 0 \in {-1, 1} +Truth table (00, 01, 10, 11): (1, 1, 0, 1) + 2 * x + -2 * y + 4 * z + -3 \in {-1, 1} +Truth table (00, 01, 10, 11): (1, 1, 1, 0) + 2 * x + 2 * y + 4 * z + -5 \in {-1, 1} +Truth table (00, 01, 10, 11): (1, 1, 1, 1) + 0 * x + 0 * y + 1 * z + 0 \in {-1, 1} diff --git a/privacy/zsl/zsl/reductions/tbcs_to_uscs/tbcs_to_uscs.hpp b/privacy/zsl/zsl/reductions/tbcs_to_uscs/tbcs_to_uscs.hpp new file mode 100644 index 0000000..92fe642 --- /dev/null +++ b/privacy/zsl/zsl/reductions/tbcs_to_uscs/tbcs_to_uscs.hpp @@ -0,0 +1,55 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a TBCS-to-USCS reduction, that is, constructing + a USCS ("Unitary-Square Constraint System") from a TBCS ("Two-input Boolean Circuit Satisfiability"). + + The reduction is straightforward: each non-output wire is mapped to a + corresponding USCS constraint that enforces the wire to carry a boolean value; + each 2-input boolean gate is mapped to a corresponding USCS constraint that + enforces correct computation of the gate; each output wire is mapped to a + corresponding USCS constraint that enforces that the output is zero. + + The mapping of a gate to a USCS constraint is due to \[GOS12]. + + References: + + \[GOS12]: + "New techniques for noninteractive zero-knowledge", + Jens Groth, Rafail Ostrovsky, Amit Sahai + JACM 2012, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TBCS_TO_USCS_HPP_ +#define TBCS_TO_USCS_HPP_ + +#include "relations/constraint_satisfaction_problems/uscs/uscs.hpp" +#include "relations/circuit_satisfaction_problems/tbcs/tbcs.hpp" + +namespace libsnark { + +/** + * Instance map for the TBCS-to-USCS reduction. + */ +template +uscs_constraint_system tbcs_to_uscs_instance_map(const tbcs_circuit &circuit); + +/** + * Witness map for the TBCS-to-USCS reduction. + */ +template +uscs_variable_assignment tbcs_to_uscs_witness_map(const tbcs_circuit &circuit, + const tbcs_primary_input &primary_input, + const tbcs_auxiliary_input &auxiliary_input); + +} // libsnark + +#include "reductions/tbcs_to_uscs/tbcs_to_uscs.tcc" + +#endif // TBCS_TO_USCS_HPP_ diff --git a/privacy/zsl/zsl/reductions/tbcs_to_uscs/tbcs_to_uscs.tcc b/privacy/zsl/zsl/reductions/tbcs_to_uscs/tbcs_to_uscs.tcc new file mode 100644 index 0000000..a81d381 --- /dev/null +++ b/privacy/zsl/zsl/reductions/tbcs_to_uscs/tbcs_to_uscs.tcc @@ -0,0 +1,165 @@ +/** @file +***************************************************************************** + +Implementation of interfaces for a TBCS-to-USCS reduction. + +See tbcs_to_uscs.hpp . + +***************************************************************************** +* @author This file is part of libsnark, developed by SCIPR Lab +* and contributors (see AUTHORS). +* @copyright MIT license (see LICENSE file) +*****************************************************************************/ + +#ifndef TBCS_TO_USCS_TCC_ +#define TBCS_TO_USCS_TCC_ + +#include "algebra/fields/field_utils.hpp" + +namespace libsnark { + +template +uscs_constraint_system tbcs_to_uscs_instance_map(const tbcs_circuit &circuit) +{ + assert(circuit.is_valid()); + uscs_constraint_system result; + +#ifdef DEBUG + result.variable_annotations = circuit.variable_annotations; +#endif + + result.primary_input_size = circuit.primary_input_size; + result.auxiliary_input_size = circuit.auxiliary_input_size + circuit.gates.size(); + + for (auto &g : circuit.gates) + { + const variable x(g.left_wire); + const variable y(g.right_wire); + const variable z(g.output); + +#ifdef DEBUG + auto it = circuit.gate_annotations.find(g.output); + const std::string annotation = (it != circuit.gate_annotations.end() ? it->second : FORMAT("", "compute_wire_%zu", g.output)); +#else + const std::string annotation = ""; +#endif + + switch (g.type) + { + case TBCS_GATE_CONSTANT_0: + /* Truth table (00, 01, 10, 11): (0, 0, 0, 0) + 0 * x + 0 * y + 1 * z + 1 \in {-1, 1} */ + result.add_constraint(0 * x + 0 * y + 1 * z + 1, annotation); + break; + case TBCS_GATE_AND: + /* Truth table (00, 01, 10, 11): (0, 0, 0, 1) + -2 * x + -2 * y + 4 * z + 1 \in {-1, 1} */ + result.add_constraint(-2 * x + -2 * y + 4 * z + 1, annotation); + break; + case TBCS_GATE_X_AND_NOT_Y: + /* Truth table (00, 01, 10, 11): (0, 0, 1, 0) + -2 * x + 2 * y + 4 * z + -1 \in {-1, 1} */ + result.add_constraint(-2 * x + 2 * y + 4 * z + -1, annotation); + break; + case TBCS_GATE_X: + /* Truth table (00, 01, 10, 11): (0, 0, 1, 1) + -1 * x + 0 * y + 1 * z + 1 \in {-1, 1} */ + result.add_constraint(-1 * x + 0 * y + 1 * z + 1, annotation); + break; + case TBCS_GATE_NOT_X_AND_Y: + /* Truth table (00, 01, 10, 11): (0, 1, 0, 0) + 2 * x + -2 * y + 4 * z + -1 \in {-1, 1} */ + result.add_constraint(2 * x + -2 * y + 4 * z + -1, annotation); + break; + case TBCS_GATE_Y: + /* Truth table (00, 01, 10, 11): (0, 1, 0, 1) + 0 * x + 1 * y + 1 * z + -1 \in {-1, 1} */ + result.add_constraint(0 * x + 1 * y + 1 * z + -1, annotation); + break; + case TBCS_GATE_XOR: + /* Truth table (00, 01, 10, 11): (0, 1, 1, 0) + 1 * x + 1 * y + 1 * z + -1 \in {-1, 1} */ + result.add_constraint(1 * x + 1 * y + 1 * z + -1, annotation); + break; + case TBCS_GATE_OR: + /* Truth table (00, 01, 10, 11): (0, 1, 1, 1) + -2 * x + -2 * y + 4 * z + -1 \in {-1, 1} */ + result.add_constraint(-2 * x + -2 * y + 4 * z + -1, annotation); + break; + case TBCS_GATE_NOR: + /* Truth table (00, 01, 10, 11): (1, 0, 0, 0) + 2 * x + 2 * y + 4 * z + -3 \in {-1, 1} */ + result.add_constraint(2 * x + 2 * y + 4 * z + -3, annotation); + break; + case TBCS_GATE_EQUIVALENCE: + /* Truth table (00, 01, 10, 11): (1, 0, 0, 1) + 1 * x + 1 * y + 1 * z + -2 \in {-1, 1} */ + result.add_constraint(1 * x + 1 * y + 1 * z + -2, annotation); + break; + case TBCS_GATE_NOT_Y: + /* Truth table (00, 01, 10, 11): (1, 0, 1, 0) + 0 * x + -1 * y + 1 * z + 0 \in {-1, 1} */ + result.add_constraint(0 * x + -1 * y + 1 * z + 0, annotation); + break; + case TBCS_GATE_IF_Y_THEN_X: + /* Truth table (00, 01, 10, 11): (1, 0, 1, 1) + -2 * x + 2 * y + 4 * z + -3 \in {-1, 1} */ + result.add_constraint(-2 * x + 2 * y + 4 * z + -3, annotation); + break; + case TBCS_GATE_NOT_X: + /* Truth table (00, 01, 10, 11): (1, 1, 0, 0) + -1 * x + 0 * y + 1 * z + 0 \in {-1, 1} */ + result.add_constraint(-1 * x + 0 * y + 1 * z + 0, annotation); + break; + case TBCS_GATE_IF_X_THEN_Y: + /* Truth table (00, 01, 10, 11): (1, 1, 0, 1) + 2 * x + -2 * y + 4 * z + -3 \in {-1, 1} */ + result.add_constraint(2 * x + -2 * y + 4 * z + -3, annotation); + break; + case TBCS_GATE_NAND: + /* Truth table (00, 01, 10, 11): (1, 1, 1, 0) + 2 * x + 2 * y + 4 * z + -5 \in {-1, 1} */ + result.add_constraint(2 * x + 2 * y + 4 * z + -5, annotation); + break; + case TBCS_GATE_CONSTANT_1: + /* Truth table (00, 01, 10, 11): (1, 1, 1, 1) + 0 * x + 0 * y + 1 * z + 0 \in {-1, 1} */ + result.add_constraint(0 * x + 0 * y + 1 * z + 0, annotation); + break; + default: + assert(0); + } + } + + for (size_t i = 0; i < circuit.primary_input_size + circuit.auxiliary_input_size + circuit.gates.size(); ++i) + { + /* require that 2 * wire - 1 \in {-1,1}, that is wire \in {0,1} */ + result.add_constraint(2 * variable(i) - 1, FMT("", "wire_%zu", i)); + } + + for (auto &g : circuit.gates) + { + if (g.is_circuit_output) + { + /* require that output + 1 \in {-1,1}, this together with output binary (above) enforces output = 0 */ + result.add_constraint(variable(g.output) + 1, FMT("", "output_%zu", g.output)); + } + } + + return result; +} + +template +uscs_variable_assignment tbcs_to_uscs_witness_map(const tbcs_circuit &circuit, + const tbcs_primary_input &primary_input, + const tbcs_auxiliary_input &auxiliary_input) +{ + const tbcs_variable_assignment all_wires = circuit.get_all_wires(primary_input, auxiliary_input); + const uscs_variable_assignment result = convert_bit_vector_to_field_element_vector(all_wires); + return result; +} + +} // libsnark + + +#endif // TBCS_TO_USCS_TCC_ diff --git a/privacy/zsl/zsl/reductions/uscs_to_ssp/uscs_to_ssp.hpp b/privacy/zsl/zsl/reductions/uscs_to_ssp/uscs_to_ssp.hpp new file mode 100644 index 0000000..d6352db --- /dev/null +++ b/privacy/zsl/zsl/reductions/uscs_to_ssp/uscs_to_ssp.hpp @@ -0,0 +1,68 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a USCS-to-SSP reduction, that is, constructing + a SSP ("Square Span Program") from a USCS ("boolean circuit with 2-input gates"). + + SSPs are defined in \[DFGK14], and construced for USCS also in \[DFGK14]. + + The implementation of the reduction adapts to \[DFGK14], extends, and optimizes + the efficient QAP-based approach described in Appendix E of \[BCGTV13]. + + References: + + \[BCGTV13] + "SNARKs for C: Verifying Program Executions Succinctly and in Zero Knowledge", + Eli Ben-Sasson, Alessandro Chiesa, Daniel Genkin, Eran Tromer, Madars Virza, + CRYPTO 2013, + + + \[DFGK14]: + "Square Span Programs with Applications to Succinct NIZK Arguments" + George Danezis, Cedric Fournet, Jens Groth, Markulf Kohlweiss, + ASIACRYPT 2014, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef USCS_TO_SSP_HPP_ +#define USCS_TO_SSP_HPP_ + +#include "relations/arithmetic_programs/ssp/ssp.hpp" +#include "relations/constraint_satisfaction_problems/uscs/uscs.hpp" + +namespace libsnark { + +/** + * Instance map for the USCS-to-SSP reduction. + */ +template +ssp_instance uscs_to_ssp_instance_map(const uscs_constraint_system &cs); + +/** + * Instance map for the USCS-to-SSP reduction followed by evaluation of the resulting SSP instance. + */ +template +ssp_instance_evaluation uscs_to_ssp_instance_map_with_evaluation(const uscs_constraint_system &cs, + const FieldT &t); + +/** + * Witness map for the USCS-to-SSP reduction. + * + * The witness map takes zero knowledge into account when d is random. + */ +template +ssp_witness uscs_to_ssp_witness_map(const uscs_constraint_system &cs, + const uscs_primary_input &primary_input, + const uscs_auxiliary_input &auxiliary_input, + const FieldT &d); + +} // libsnark + +#include "reductions/uscs_to_ssp/uscs_to_ssp.tcc" + +#endif // USCS_TO_SSP_HPP_ diff --git a/privacy/zsl/zsl/reductions/uscs_to_ssp/uscs_to_ssp.tcc b/privacy/zsl/zsl/reductions/uscs_to_ssp/uscs_to_ssp.tcc new file mode 100644 index 0000000..95dd12a --- /dev/null +++ b/privacy/zsl/zsl/reductions/uscs_to_ssp/uscs_to_ssp.tcc @@ -0,0 +1,242 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a USCS-to-SSP reduction. + + See uscs_to_ssp.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef USCS_TO_SSP_TCC_ +#define USCS_TO_SSP_TCC_ + +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "algebra/evaluation_domain/evaluation_domain.hpp" + +namespace libsnark { + +/** + * Instance map for the USCS-to-SSP reduction. + * + * Namely, given a USCS constraint system cs, construct a SSP instance for which: + * V := (V_0(z),V_1(z),...,V_m(z)) + * where + * m = number of variables of the SSP + * and + * each V_i is expressed in the Lagrange basis. + */ +template +ssp_instance uscs_to_ssp_instance_map(const uscs_constraint_system &cs) +{ + enter_block("Call to uscs_to_ssp_instance_map"); + + const std::shared_ptr > domain = get_evaluation_domain(cs.num_constraints()); + + enter_block("Compute polynomials V in Lagrange basis"); + std::vector > V_in_Lagrange_basis(cs.num_variables()+1); + for (size_t i = 0; i < cs.num_constraints(); ++i) + { + for (size_t j = 0; j < cs.constraints[i].terms.size(); ++j) + { + V_in_Lagrange_basis[cs.constraints[i].terms[j].index][i] += cs.constraints[i].terms[j].coeff; + } + } + for (size_t i = cs.num_constraints(); i < domain->m; ++i) + { + V_in_Lagrange_basis[0][i] += FieldT::one(); + } + leave_block("Compute polynomials V in Lagrange basis"); + + leave_block("Call to uscs_to_ssp_instance_map"); + + return ssp_instance(domain, + cs.num_variables(), + domain->m, + cs.num_inputs(), + std::move(V_in_Lagrange_basis)); +} + +/** + * Instance map for the USCS-to-SSP reduction followed by evaluation of the resulting SSP instance. + * + * Namely, given a USCS constraint system cs and a field element t, construct + * a SSP instance (evaluated at t) for which: + * Vt := (V_0(t),V_1(t),...,V_m(t)) + * Ht := (1,t,t^2,...,t^n) + * Zt := Z(t) = "vanishing polynomial of a certain set S, evaluated at t" + * where + * m = number of variables of the SSP + * n = degree of the SSP + */ +template +ssp_instance_evaluation uscs_to_ssp_instance_map_with_evaluation(const uscs_constraint_system &cs, + const FieldT &t) +{ + enter_block("Call to uscs_to_ssp_instance_map_with_evaluation"); + + const std::shared_ptr > domain = get_evaluation_domain(cs.num_constraints()); + + std::vector Vt(cs.num_variables()+1, FieldT::zero()); + std::vector Ht(domain->m+1); + + const FieldT Zt = domain->compute_Z(t); + + enter_block("Compute evaluations of V and H at t"); + const std::vector u = domain->lagrange_coeffs(t); + for (size_t i = 0; i < cs.num_constraints(); ++i) + { + for (size_t j = 0; j < cs.constraints[i].terms.size(); ++j) + { + Vt[cs.constraints[i].terms[j].index] += u[i]*cs.constraints[i].terms[j].coeff; + } + } + for (size_t i = cs.num_constraints(); i < domain->m; ++i) + { + Vt[0] += u[i]; /* dummy constraint: 1^2 = 1 */ + } + FieldT ti = FieldT::one(); + for (size_t i = 0; i < domain->m+1; ++i) + { + Ht[i] = ti; + ti *= t; + } + leave_block("Compute evaluations of V and H at t"); + + leave_block("Call to uscs_to_ssp_instance_map_with_evaluation"); + + return ssp_instance_evaluation(domain, + cs.num_variables(), + domain->m, + cs.num_inputs(), + t, + std::move(Vt), + std::move(Ht), + Zt); +} + +/** + * Witness map for the USCS-to-SSP reduction. + * + * The witness map takes zero knowledge into account when d is random. + * + * More precisely, compute the coefficients + * h_0,h_1,...,h_n + * of the polynomial + * H(z) := (V(z)^2-1)/Z(z) + * where + * V(z) := V_0(z) + \sum_{k=1}^{m} w_k V_k(z) + d * Z(z) + * Z(z) := "vanishing polynomial of set S" + * and + * m = number of variables of the SSP + * n = degree of the SSP + * + * This is done as follows: + * (1) compute evaluations of V on S = {sigma_1,...,sigma_n} + * (2) compute coefficients of V + * (3) compute evaluations of V on T = "coset of S" + * (4) compute evaluation of H on T + * (5) compute coefficients of H + * (6) patch H to account for d (i.e., add coefficients of the polynomial 2*d*V(z) + d*d*Z(z) ) + * + * The code below is not as simple as the above high-level description due to + * some reshuffling to save space. + */ +template +ssp_witness uscs_to_ssp_witness_map(const uscs_constraint_system &cs, + const uscs_primary_input &primary_input, + const uscs_auxiliary_input &auxiliary_input, + const FieldT &d) +{ + enter_block("Call to uscs_to_ssp_witness_map"); + + /* sanity check */ + + assert(cs.is_satisfied(primary_input, auxiliary_input)); + + uscs_variable_assignment full_variable_assignment = primary_input; + full_variable_assignment.insert(full_variable_assignment.end(), auxiliary_input.begin(), auxiliary_input.end()); + + const std::shared_ptr > domain = get_evaluation_domain(cs.num_constraints()); + + enter_block("Compute evaluation of polynomial V on set S"); + std::vector aA(domain->m, FieldT::zero()); + assert(domain->m >= cs.num_constraints()); + for (size_t i = 0; i < cs.num_constraints(); ++i) + { + aA[i] += cs.constraints[i].evaluate(full_variable_assignment); + } + for (size_t i = cs.num_constraints(); i < domain->m; ++i) + { + aA[i] += FieldT::one(); + } + leave_block("Compute evaluation of polynomial V on set S"); + + enter_block("Compute coefficients of polynomial V"); + domain->iFFT(aA); + leave_block("Compute coefficients of polynomial V"); + + enter_block("Compute ZK-patch"); + std::vector coefficients_for_H(domain->m+1, FieldT::zero()); +#ifdef MULTICORE +#pragma omp parallel for +#endif + /* add coefficients of the polynomial 2*d*V(z) + d*d*Z(z) */ + for (size_t i = 0; i < domain->m; ++i) + { + coefficients_for_H[i] = FieldT(2)*d*aA[i]; + } + domain->add_poly_Z(d.squared(), coefficients_for_H); + leave_block("Compute ZK-patch"); + + enter_block("Compute evaluation of polynomial V on set T"); + domain->cosetFFT(aA, FieldT::multiplicative_generator); + leave_block("Compute evaluation of polynomial V on set T"); + + enter_block("Compute evaluation of polynomial H on set T"); + std::vector &H_tmp = aA; // can overwrite aA because it is not used later +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < domain->m; ++i) + { + H_tmp[i] = aA[i].squared()-FieldT::one(); + } + + enter_block("Divide by Z on set T"); + domain->divide_by_Z_on_coset(H_tmp); + leave_block("Divide by Z on set T"); + + leave_block("Compute evaluation of polynomial H on set T"); + + enter_block("Compute coefficients of polynomial H"); + domain->icosetFFT(H_tmp, FieldT::multiplicative_generator); + leave_block("Compute coefficients of polynomial H"); + + enter_block("Compute sum of H and ZK-patch"); +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < domain->m; ++i) + { + coefficients_for_H[i] += H_tmp[i]; + } + leave_block("Compute sum of H and ZK-patch"); + + leave_block("Call to uscs_to_ssp_witness_map"); + + return ssp_witness(cs.num_variables(), + domain->m, + cs.num_inputs(), + d, + full_variable_assignment, + std::move(coefficients_for_H)); +} + +} // libsnark + +#endif // USCS_TO_SSP_TCC_ diff --git a/privacy/zsl/zsl/relations/arithmetic_programs/qap/qap.hpp b/privacy/zsl/zsl/relations/arithmetic_programs/qap/qap.hpp new file mode 100644 index 0000000..4991d20 --- /dev/null +++ b/privacy/zsl/zsl/relations/arithmetic_programs/qap/qap.hpp @@ -0,0 +1,193 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a QAP ("Quadratic Arithmetic Program"). + + QAPs are defined in \[GGPR13]. + + References: + + \[GGPR13]: + "Quadratic span programs and succinct NIZKs without PCPs", + Rosario Gennaro, Craig Gentry, Bryan Parno, Mariana Raykova, + EUROCRYPT 2013, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef QAP_HPP_ +#define QAP_HPP_ + +#include "algebra/evaluation_domain/evaluation_domain.hpp" + +namespace libsnark { + +/* forward declaration */ +template +class qap_witness; + +/** + * A QAP instance. + * + * Specifically, the datastructure stores: + * - a choice of domain (corresponding to a certain subset of the field); + * - the number of variables, the degree, and the number of inputs; and + * - coefficients of the A,B,C polynomials in the Lagrange basis. + * + * There is no need to store the Z polynomial because it is uniquely + * determined by the domain (as Z is its vanishing polynomial). + */ +template +class qap_instance { +private: + size_t num_variables_; + size_t degree_; + size_t num_inputs_; + +public: + std::shared_ptr > domain; + + std::vector > A_in_Lagrange_basis; + std::vector > B_in_Lagrange_basis; + std::vector > C_in_Lagrange_basis; + + qap_instance(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const std::vector > &A_in_Lagrange_basis, + const std::vector > &B_in_Lagrange_basis, + const std::vector > &C_in_Lagrange_basis); + + qap_instance(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + std::vector > &&A_in_Lagrange_basis, + std::vector > &&B_in_Lagrange_basis, + std::vector > &&C_in_Lagrange_basis); + + qap_instance(const qap_instance &other) = default; + qap_instance(qap_instance &&other) = default; + qap_instance& operator=(const qap_instance &other) = default; + qap_instance& operator=(qap_instance &&other) = default; + + size_t num_variables() const; + size_t degree() const; + size_t num_inputs() const; + + bool is_satisfied(const qap_witness &witness) const; +}; + +/** + * A QAP instance evaluation is a QAP instance that is evaluated at a field element t. + * + * Specifically, the datastructure stores: + * - a choice of domain (corresponding to a certain subset of the field); + * - the number of variables, the degree, and the number of inputs; + * - a field element t; + * - evaluations of the A,B,C (and Z) polynomials at t; + * - evaluations of all monomials of t; + * - counts about how many of the above evaluations are in fact non-zero. + */ +template +class qap_instance_evaluation { +private: + size_t num_variables_; + size_t degree_; + size_t num_inputs_; +public: + std::shared_ptr > domain; + + FieldT t; + + std::vector At, Bt, Ct, Ht; + + FieldT Zt; + + qap_instance_evaluation(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &t, + const std::vector &At, + const std::vector &Bt, + const std::vector &Ct, + const std::vector &Ht, + const FieldT &Zt); + qap_instance_evaluation(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &t, + std::vector &&At, + std::vector &&Bt, + std::vector &&Ct, + std::vector &&Ht, + const FieldT &Zt); + + qap_instance_evaluation(const qap_instance_evaluation &other) = default; + qap_instance_evaluation(qap_instance_evaluation &&other) = default; + qap_instance_evaluation& operator=(const qap_instance_evaluation &other) = default; + qap_instance_evaluation& operator=(qap_instance_evaluation &&other) = default; + + size_t num_variables() const; + size_t degree() const; + size_t num_inputs() const; + + bool is_satisfied(const qap_witness &witness) const; +}; + +/** + * A QAP witness. + */ +template +class qap_witness { +private: + size_t num_variables_; + size_t degree_; + size_t num_inputs_; + +public: + FieldT d1, d2, d3; + + std::vector coefficients_for_ABCs; + std::vector coefficients_for_H; + + qap_witness(const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &d1, + const FieldT &d2, + const FieldT &d3, + const std::vector &coefficients_for_ABCs, + const std::vector &coefficients_for_H); + + qap_witness(const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &d1, + const FieldT &d2, + const FieldT &d3, + const std::vector &coefficients_for_ABCs, + std::vector &&coefficients_for_H); + + qap_witness(const qap_witness &other) = default; + qap_witness(qap_witness &&other) = default; + qap_witness& operator=(const qap_witness &other) = default; + qap_witness& operator=(qap_witness &&other) = default; + + size_t num_variables() const; + size_t degree() const; + size_t num_inputs() const; +}; + +} // libsnark + +#include "relations/arithmetic_programs/qap/qap.tcc" + +#endif // QAP_HPP_ diff --git a/privacy/zsl/zsl/relations/arithmetic_programs/qap/qap.tcc b/privacy/zsl/zsl/relations/arithmetic_programs/qap/qap.tcc new file mode 100644 index 0000000..a4a3c96 --- /dev/null +++ b/privacy/zsl/zsl/relations/arithmetic_programs/qap/qap.tcc @@ -0,0 +1,324 @@ +/** @file +***************************************************************************** + +Implementation of interfaces for a QAP ("Quadratic Arithmetic Program"). + +See qap.hpp . + +***************************************************************************** +* @author This file is part of libsnark, developed by SCIPR Lab +* and contributors (see AUTHORS). +* @copyright MIT license (see LICENSE file) +*****************************************************************************/ + +#ifndef QAP_TCC_ +#define QAP_TCC_ + +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "algebra/evaluation_domain/evaluation_domain.hpp" +#include "algebra/scalar_multiplication/multiexp.hpp" + +namespace libsnark { + +template +qap_instance::qap_instance(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const std::vector > &A_in_Lagrange_basis, + const std::vector > &B_in_Lagrange_basis, + const std::vector > &C_in_Lagrange_basis) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + domain(domain), + A_in_Lagrange_basis(A_in_Lagrange_basis), + B_in_Lagrange_basis(B_in_Lagrange_basis), + C_in_Lagrange_basis(C_in_Lagrange_basis) +{ +} + +template +qap_instance::qap_instance(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + std::vector > &&A_in_Lagrange_basis, + std::vector > &&B_in_Lagrange_basis, + std::vector > &&C_in_Lagrange_basis) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + domain(domain), + A_in_Lagrange_basis(std::move(A_in_Lagrange_basis)), + B_in_Lagrange_basis(std::move(B_in_Lagrange_basis)), + C_in_Lagrange_basis(std::move(C_in_Lagrange_basis)) +{ +} + +template +size_t qap_instance::num_variables() const +{ + return num_variables_; +} + +template +size_t qap_instance::degree() const +{ + return degree_; +} + +template +size_t qap_instance::num_inputs() const +{ + return num_inputs_; +} + +template +bool qap_instance::is_satisfied(const qap_witness &witness) const +{ + const FieldT t = FieldT::random_element(); + + std::vector At(this->num_variables()+1, FieldT::zero()); + std::vector Bt(this->num_variables()+1, FieldT::zero()); + std::vector Ct(this->num_variables()+1, FieldT::zero()); + std::vector Ht(this->degree()+1); + + const FieldT Zt = this->domain->compute_Z(t); + + const std::vector u = this->domain->lagrange_coeffs(t); + + for (size_t i = 0; i < this->num_variables()+1; ++i) + { + for (auto &el : A_in_Lagrange_basis[i]) + { + At[i] += u[el.first] * el.second; + } + + for (auto &el : B_in_Lagrange_basis[i]) + { + Bt[i] += u[el.first] * el.second; + } + + for (auto &el : C_in_Lagrange_basis[i]) + { + Ct[i] += u[el.first] * el.second; + } + } + + FieldT ti = FieldT::one(); + for (size_t i = 0; i < this->degree()+1; ++i) + { + Ht[i] = ti; + ti *= t; + } + + const qap_instance_evaluation eval_qap_inst(this->domain, + this->num_variables(), + this->degree(), + this->num_inputs(), + t, + std::move(At), + std::move(Bt), + std::move(Ct), + std::move(Ht), + Zt); + return eval_qap_inst.is_satisfied(witness); +} + +template +qap_instance_evaluation::qap_instance_evaluation(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &t, + const std::vector &At, + const std::vector &Bt, + const std::vector &Ct, + const std::vector &Ht, + const FieldT &Zt) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + domain(domain), + t(t), + At(At), + Bt(Bt), + Ct(Ct), + Ht(Ht), + Zt(Zt) +{ +} + +template +qap_instance_evaluation::qap_instance_evaluation(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &t, + std::vector &&At, + std::vector &&Bt, + std::vector &&Ct, + std::vector &&Ht, + const FieldT &Zt) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + domain(domain), + t(t), + At(std::move(At)), + Bt(std::move(Bt)), + Ct(std::move(Ct)), + Ht(std::move(Ht)), + Zt(Zt) +{ +} + +template +size_t qap_instance_evaluation::num_variables() const +{ + return num_variables_; +} + +template +size_t qap_instance_evaluation::degree() const +{ + return degree_; +} + +template +size_t qap_instance_evaluation::num_inputs() const +{ + return num_inputs_; +} + +template +bool qap_instance_evaluation::is_satisfied(const qap_witness &witness) const +{ + + if (this->num_variables() != witness.num_variables()) + { + return false; + } + + if (this->degree() != witness.degree()) + { + return false; + } + + if (this->num_inputs() != witness.num_inputs()) + { + return false; + } + + if (this->num_variables() != witness.coefficients_for_ABCs.size()) + { + return false; + } + + if (this->degree()+1 != witness.coefficients_for_H.size()) + { + return false; + } + + if (this->At.size() != this->num_variables()+1 || this->Bt.size() != this->num_variables()+1 || this->Ct.size() != this->num_variables()+1) + { + return false; + } + + if (this->Ht.size() != this->degree()+1) + { + return false; + } + + if (this->Zt != this->domain->compute_Z(this->t)) + { + return false; + } + + FieldT ans_A = this->At[0] + witness.d1*this->Zt; + FieldT ans_B = this->Bt[0] + witness.d2*this->Zt; + FieldT ans_C = this->Ct[0] + witness.d3*this->Zt; + FieldT ans_H = FieldT::zero(); + + ans_A = ans_A + naive_plain_exp(this->At.begin()+1, this->At.begin()+1+this->num_variables(), + witness.coefficients_for_ABCs.begin(), witness.coefficients_for_ABCs.begin()+this->num_variables()); + ans_B = ans_B + naive_plain_exp(this->Bt.begin()+1, this->Bt.begin()+1+this->num_variables(), + witness.coefficients_for_ABCs.begin(), witness.coefficients_for_ABCs.begin()+this->num_variables()); + ans_C = ans_C + naive_plain_exp(this->Ct.begin()+1, this->Ct.begin()+1+this->num_variables(), + witness.coefficients_for_ABCs.begin(), witness.coefficients_for_ABCs.begin()+this->num_variables()); + ans_H = ans_H + naive_plain_exp(this->Ht.begin(), this->Ht.begin()+this->degree()+1, + witness.coefficients_for_H.begin(), witness.coefficients_for_H.begin()+this->degree()+1); + + if (ans_A * ans_B - ans_C != ans_H * this->Zt) + { + return false; + } + + return true; +} + +template +qap_witness::qap_witness(const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &d1, + const FieldT &d2, + const FieldT &d3, + const std::vector &coefficients_for_ABCs, + const std::vector &coefficients_for_H) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + d1(d1), + d2(d2), + d3(d3), + coefficients_for_ABCs(coefficients_for_ABCs), + coefficients_for_H(coefficients_for_H) +{ +} + +template +qap_witness::qap_witness(const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &d1, + const FieldT &d2, + const FieldT &d3, + const std::vector &coefficients_for_ABCs, + std::vector &&coefficients_for_H) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + d1(d1), + d2(d2), + d3(d3), + coefficients_for_ABCs(coefficients_for_ABCs), + coefficients_for_H(std::move(coefficients_for_H)) +{ +} + + +template +size_t qap_witness::num_variables() const +{ + return num_variables_; +} + +template +size_t qap_witness::degree() const +{ + return degree_; +} + +template +size_t qap_witness::num_inputs() const +{ + return num_inputs_; +} + + +} // libsnark + +#endif // QAP_TCC_ diff --git a/privacy/zsl/zsl/relations/arithmetic_programs/qap/tests/test_qap.cpp b/privacy/zsl/zsl/relations/arithmetic_programs/qap/tests/test_qap.cpp new file mode 100644 index 0000000..d8aadda --- /dev/null +++ b/privacy/zsl/zsl/relations/arithmetic_programs/qap/tests/test_qap.cpp @@ -0,0 +1,115 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include +#include +#include +#include + +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +#include "algebra/fields/field_utils.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "reductions/r1cs_to_qap/r1cs_to_qap.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" + +using namespace libsnark; + +template +void test_qap(const size_t qap_degree, const size_t num_inputs, const bool binary_input) +{ + /* + We construct an instance where the QAP degree is qap_degree. + So we generate an instance of R1CS where the number of constraints qap_degree - num_inputs - 1. + See the transformation from R1CS to QAP for why this is the case. + So we need that qap_degree >= num_inputs + 1. + */ + assert(num_inputs + 1 <= qap_degree); + enter_block("Call to test_qap"); + + const size_t num_constraints = qap_degree - num_inputs - 1; + + print_indent(); printf("* QAP degree: %zu\n", qap_degree); + print_indent(); printf("* Number of inputs: %zu\n", num_inputs); + print_indent(); printf("* Number of R1CS constraints: %zu\n", num_constraints); + print_indent(); printf("* Input type: %s\n", binary_input ? "binary" : "field"); + + enter_block("Generate constraint system and assignment"); + r1cs_example example; + if (binary_input) + { + example = generate_r1cs_example_with_binary_input(num_constraints, num_inputs); + } + else + { + example = generate_r1cs_example_with_field_input(num_constraints, num_inputs); + } + leave_block("Generate constraint system and assignment"); + + enter_block("Check satisfiability of constraint system"); + assert(example.constraint_system.is_satisfied(example.primary_input, example.auxiliary_input)); + leave_block("Check satisfiability of constraint system"); + + const FieldT t = FieldT::random_element(), + d1 = FieldT::random_element(), + d2 = FieldT::random_element(), + d3 = FieldT::random_element(); + + enter_block("Compute QAP instance 1"); + qap_instance qap_inst_1 = r1cs_to_qap_instance_map(example.constraint_system); + leave_block("Compute QAP instance 1"); + + enter_block("Compute QAP instance 2"); + qap_instance_evaluation qap_inst_2 = r1cs_to_qap_instance_map_with_evaluation(example.constraint_system, t); + leave_block("Compute QAP instance 2"); + + enter_block("Compute QAP witness"); + qap_witness qap_wit = r1cs_to_qap_witness_map(example.constraint_system, example.primary_input, example.auxiliary_input, d1, d2, d3); + leave_block("Compute QAP witness"); + + enter_block("Check satisfiability of QAP instance 1"); + assert(qap_inst_1.is_satisfied(qap_wit)); + leave_block("Check satisfiability of QAP instance 1"); + + enter_block("Check satisfiability of QAP instance 2"); + assert(qap_inst_2.is_satisfied(qap_wit)); + leave_block("Check satisfiability of QAP instance 2"); + + leave_block("Call to test_qap"); +} + +int main() +{ + start_profiling(); + + mnt6_pp::init_public_params(); + + const size_t num_inputs = 10; + + const size_t basic_domain_size = 1ul< >(basic_domain_size, num_inputs, true); + test_qap >(step_domain_size, num_inputs, true); + test_qap >(extended_domain_size, num_inputs, true); + test_qap >(extended_domain_size_special, num_inputs, true); + + leave_block("Test QAP with binary input"); + + enter_block("Test QAP with field input"); + + test_qap >(basic_domain_size, num_inputs, false); + test_qap >(step_domain_size, num_inputs, false); + test_qap >(extended_domain_size, num_inputs, false); + test_qap >(extended_domain_size_special, num_inputs, false); + + leave_block("Test QAP with field input"); +} diff --git a/privacy/zsl/zsl/relations/arithmetic_programs/ssp/ssp.hpp b/privacy/zsl/zsl/relations/arithmetic_programs/ssp/ssp.hpp new file mode 100644 index 0000000..48ddd05 --- /dev/null +++ b/privacy/zsl/zsl/relations/arithmetic_programs/ssp/ssp.hpp @@ -0,0 +1,178 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a SSP ("Square Span Program"). + + SSPs are defined in \[DFGK14]. + + References: + + \[DFGK14]: + "Square Span Programs with Applications to Succinct NIZK Arguments" + George Danezis, Cedric Fournet, Jens Groth, Markulf Kohlweiss, + ASIACRYPT 2014, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SSP_HPP_ +#define SSP_HPP_ + +#include "algebra/evaluation_domain/evaluation_domain.hpp" + +namespace libsnark { + +/* forward declaration */ +template +class ssp_witness; + +/** + * A SSP instance. + * + * Specifically, the datastructure stores: + * - a choice of domain (corresponding to a certain subset of the field); + * - the number of variables, the degree, and the number of inputs; and + * - coefficients of the V polynomials in the Lagrange basis. + * + * There is no need to store the Z polynomial because it is uniquely + * determined by the domain (as Z is its vanishing polynomial). + */ +template +class ssp_instance { +private: + size_t num_variables_; + size_t degree_; + size_t num_inputs_; + +public: + std::shared_ptr > domain; + + std::vector > V_in_Lagrange_basis; + + ssp_instance(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const std::vector > &V_in_Lagrange_basis); + ssp_instance(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + std::vector > &&V_in_Lagrange_basis); + + ssp_instance(const ssp_instance &other) = default; + ssp_instance(ssp_instance &&other) = default; + ssp_instance& operator=(const ssp_instance &other) = default; + ssp_instance& operator=(ssp_instance &&other) = default; + + size_t num_variables() const; + size_t degree() const; + size_t num_inputs() const; + + bool is_satisfied(const ssp_witness &witness) const; +}; + + +/** + * A SSP instance evaluation is a SSP instance that is evaluated at a field element t. + * + * Specifically, the datastructure stores: + * - a choice of domain (corresponding to a certain subset of the field); + * - the number of variables, the degree, and the number of inputs; + * - a field element t; + * - evaluations of the V (and Z) polynomials at t; + * - evaluations of all monomials of t. + */ +template +class ssp_instance_evaluation { +private: + size_t num_variables_; + size_t degree_; + size_t num_inputs_; + +public: + std::shared_ptr > domain; + + FieldT t; + + std::vector Vt, Ht; + + FieldT Zt; + + ssp_instance_evaluation(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &t, + const std::vector &Vt, + const std::vector &Ht, + const FieldT &Zt); + ssp_instance_evaluation(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &t, + std::vector &&Vt, + std::vector &&Ht, + const FieldT &Zt); + + ssp_instance_evaluation(const ssp_instance_evaluation &other) = default; + ssp_instance_evaluation(ssp_instance_evaluation &&other) = default; + ssp_instance_evaluation& operator=(const ssp_instance_evaluation &other) = default; + ssp_instance_evaluation& operator=(ssp_instance_evaluation &&other) = default; + + size_t num_variables() const; + size_t degree() const; + size_t num_inputs() const; + + bool is_satisfied(const ssp_witness &witness) const; +}; + +/** + * A SSP witness. + */ +template +class ssp_witness { +private: + size_t num_variables_; + size_t degree_; + size_t num_inputs_; + +public: + FieldT d; + + std::vector coefficients_for_Vs; + std::vector coefficients_for_H; + + ssp_witness(const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &d, + const std::vector &coefficients_for_Vs, + const std::vector &coefficients_for_H); + ssp_witness(const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &d, + const std::vector &coefficients_for_Vs, + std::vector &&coefficients_for_H); + + ssp_witness(const ssp_witness &other) = default; + ssp_witness(ssp_witness &&other) = default; + ssp_witness& operator=(const ssp_witness &other) = default; + ssp_witness& operator=(ssp_witness &&other) = default; + + size_t num_variables() const; + size_t degree() const; + size_t num_inputs() const; +}; + +} // libsnark + +#include "relations/arithmetic_programs/ssp/ssp.tcc" + +#endif // SSP_HPP_ diff --git a/privacy/zsl/zsl/relations/arithmetic_programs/ssp/ssp.tcc b/privacy/zsl/zsl/relations/arithmetic_programs/ssp/ssp.tcc new file mode 100644 index 0000000..d0db747 --- /dev/null +++ b/privacy/zsl/zsl/relations/arithmetic_programs/ssp/ssp.tcc @@ -0,0 +1,277 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a SSP ("Square Span Program"). + + See ssp.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SSP_TCC_ +#define SSP_TCC_ + +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "algebra/evaluation_domain/evaluation_domain.hpp" +#include "algebra/scalar_multiplication/multiexp.hpp" + +namespace libsnark { + +template +ssp_instance::ssp_instance(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const std::vector > &V_in_Lagrange_basis) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + domain(domain), + V_in_Lagrange_basis(V_in_Lagrange_basis) +{ +} + +template +ssp_instance::ssp_instance(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + std::vector > &&V_in_Lagrange_basis) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + domain(domain), + V_in_Lagrange_basis(std::move(V_in_Lagrange_basis)) +{ +} + +template +size_t ssp_instance::num_variables() const +{ + return num_variables_; +} + +template +size_t ssp_instance::degree() const +{ + return degree_; +} + +template +size_t ssp_instance::num_inputs() const +{ + return num_inputs_; +} + +template +bool ssp_instance::is_satisfied(const ssp_witness &witness) const +{ + const FieldT t = FieldT::random_element();; + std::vector Vt(this->num_variables()+1, FieldT::zero()); + std::vector Ht(this->degree()+1); + + const FieldT Zt = this->domain->compute_Z(t); + + const std::vector u = this->domain->lagrange_coeffs(t); + + for (size_t i = 0; i < this->num_variables()+1; ++i) + { + for (auto &el : V_in_Lagrange_basis[i]) + { + Vt[i] += u[el.first] * el.second; + } + } + + FieldT ti = FieldT::one(); + for (size_t i = 0; i < this->degree()+1; ++i) + { + Ht[i] = ti; + ti *= t; + } + + const ssp_instance_evaluation eval_ssp_inst(this->domain, + this->num_variables(), + this->degree(), + this->num_inputs(), + t, + std::move(Vt), + std::move(Ht), + Zt); + return eval_ssp_inst.is_satisfied(witness); +} + +template +ssp_instance_evaluation::ssp_instance_evaluation(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &t, + const std::vector &Vt, + const std::vector &Ht, + const FieldT &Zt) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + domain(domain), + t(t), + Vt(Vt), + Ht(Ht), + Zt(Zt) +{ +} + +template +ssp_instance_evaluation::ssp_instance_evaluation(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &t, + std::vector &&Vt, + std::vector &&Ht, + const FieldT &Zt) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + domain(domain), + t(t), + Vt(std::move(Vt)), + Ht(std::move(Ht)), + Zt(Zt) +{ +} + +template +size_t ssp_instance_evaluation::num_variables() const +{ + return num_variables_; +} + +template +size_t ssp_instance_evaluation::degree() const +{ + return degree_; +} + +template +size_t ssp_instance_evaluation::num_inputs() const +{ + return num_inputs_; +} + +template +bool ssp_instance_evaluation::is_satisfied(const ssp_witness &witness) const +{ + + if (this->num_variables() != witness.num_variables()) + { + return false; + } + + if (this->degree() != witness.degree()) + { + return false; + } + + if (this->num_inputs() != witness.num_inputs()) + { + return false; + } + + if (this->num_variables() != witness.coefficients_for_Vs.size()) + { + return false; + } + + if (this->degree()+1 != witness.coefficients_for_H.size()) + { + return false; + } + + if (this->Vt.size() != this->num_variables()+1) + { + return false; + } + + if (this->Ht.size() != this->degree()+1) + { + return false; + } + + if (this->Zt != this->domain->compute_Z(this->t)) + { + return false; + } + + FieldT ans_V = this->Vt[0] + witness.d*this->Zt; + FieldT ans_H = FieldT::zero(); + + ans_V = ans_V + naive_plain_exp(this->Vt.begin()+1, this->Vt.begin()+1+this->num_variables(), + witness.coefficients_for_Vs.begin(), witness.coefficients_for_Vs.begin()+this->num_variables()); + ans_H = ans_H + naive_plain_exp(this->Ht.begin(), this->Ht.begin()+this->degree()+1, + witness.coefficients_for_H.begin(), witness.coefficients_for_H.begin()+this->degree()+1); + + if (ans_V.squared() - FieldT::one() != ans_H * this->Zt) + { + return false; + } + + return true; +} + +template +ssp_witness::ssp_witness(const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &d, + const std::vector &coefficients_for_Vs, + const std::vector &coefficients_for_H) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + d(d), + coefficients_for_Vs(coefficients_for_Vs), + coefficients_for_H(coefficients_for_H) +{ +} + +template +ssp_witness::ssp_witness(const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &d, + const std::vector &coefficients_for_Vs, + std::vector &&coefficients_for_H) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + d(d), + coefficients_for_Vs(coefficients_for_Vs), + coefficients_for_H(std::move(coefficients_for_H)) +{ +} + +template +size_t ssp_witness::num_variables() const +{ + return num_variables_; +} + +template +size_t ssp_witness::degree() const +{ + return degree_; +} + +template +size_t ssp_witness::num_inputs() const +{ + return num_inputs_; +} + +} // libsnark + +#endif // SSP_TCC_ diff --git a/privacy/zsl/zsl/relations/arithmetic_programs/ssp/tests/test_ssp.cpp b/privacy/zsl/zsl/relations/arithmetic_programs/ssp/tests/test_ssp.cpp new file mode 100644 index 0000000..a0eeeea --- /dev/null +++ b/privacy/zsl/zsl/relations/arithmetic_programs/ssp/tests/test_ssp.cpp @@ -0,0 +1,103 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include +#include +#include +#include + +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +#include "algebra/fields/field_utils.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "reductions/uscs_to_ssp/uscs_to_ssp.hpp" +#include "relations/constraint_satisfaction_problems/uscs/examples/uscs_examples.hpp" + +using namespace libsnark; + +template +void test_ssp(const size_t num_constraints, const size_t num_inputs, const bool binary_input) +{ + enter_block("Call to test_ssp"); + + print_indent(); printf("* Number of constraints: %zu\n", num_constraints); + print_indent(); printf("* Number of inputs: %zu\n", num_inputs); + print_indent(); printf("* Input type: %s\n", binary_input ? "binary" : "field"); + + enter_block("Generate constraint system and assignment"); + uscs_example example; + if (binary_input) + { + example = generate_uscs_example_with_binary_input(num_constraints, num_inputs); + } + else + { + example = generate_uscs_example_with_field_input(num_constraints, num_inputs); + } + leave_block("Generate constraint system and assignment"); + + enter_block("Check satisfiability of constraint system"); + assert(example.constraint_system.is_satisfied(example.primary_input, example.auxiliary_input)); + leave_block("Check satisfiability of constraint system"); + + const FieldT t = FieldT::random_element(), + d = FieldT::random_element(); + + enter_block("Compute SSP instance 1"); + ssp_instance ssp_inst_1 = uscs_to_ssp_instance_map(example.constraint_system); + leave_block("Compute SSP instance 1"); + + enter_block("Compute SSP instance 2"); + ssp_instance_evaluation ssp_inst_2 = uscs_to_ssp_instance_map_with_evaluation(example.constraint_system, t); + leave_block("Compute SSP instance 2"); + + enter_block("Compute SSP witness"); + ssp_witness ssp_wit = uscs_to_ssp_witness_map(example.constraint_system, example.primary_input, example.auxiliary_input, d); + leave_block("Compute SSP witness"); + + enter_block("Check satisfiability of SSP instance 1"); + assert(ssp_inst_1.is_satisfied(ssp_wit)); + leave_block("Check satisfiability of SSP instance 1"); + + enter_block("Check satisfiability of SSP instance 2"); + assert(ssp_inst_2.is_satisfied(ssp_wit)); + leave_block("Check satisfiability of SSP instance 2"); + + leave_block("Call to test_ssp"); +} + +int main() +{ + start_profiling(); + + mnt6_pp::init_public_params(); + + const size_t num_inputs = 10; + + const size_t basic_domain_size = 1ul< >(basic_domain_size, num_inputs, true); + test_ssp >(step_domain_size, num_inputs, true); + test_ssp >(extended_domain_size, num_inputs, true); + test_ssp >(extended_domain_size_special, num_inputs, true); + + leave_block("Test SSP for binary inputs"); + + enter_block("Test SSP for field inputs"); + + test_ssp >(basic_domain_size, num_inputs, false); + test_ssp >(step_domain_size, num_inputs, false); + test_ssp >(extended_domain_size, num_inputs, false); + test_ssp >(extended_domain_size_special, num_inputs, false); + + leave_block("Test SSP for field inputs"); +} diff --git a/privacy/zsl/zsl/relations/circuit_satisfaction_problems/bacs/bacs.hpp b/privacy/zsl/zsl/relations/circuit_satisfaction_problems/bacs/bacs.hpp new file mode 100644 index 0000000..274c9ec --- /dev/null +++ b/privacy/zsl/zsl/relations/circuit_satisfaction_problems/bacs/bacs.hpp @@ -0,0 +1,155 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for: + - a BACS variable assigment, + - a BACS gate, + - a BACS primary input, + - a BACS auxiliary input, + - a BACS circuit. + + Above, BACS stands for "Bilinear Arithmetic Circuit Satisfiability". + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BACS_HPP_ +#define BACS_HPP_ + +#include + +#include "relations/variable.hpp" + +namespace libsnark { + +/*********************** BACS variable assignment ****************************/ + +/** + * A BACS variable assignment is a vector of field elements. + */ +template +using bacs_variable_assignment = std::vector; + + +/**************************** BACS gate **************************************/ + +template +struct bacs_gate; + +template +std::ostream& operator<<(std::ostream &out, const bacs_gate &g); + +template +std::istream& operator>>(std::istream &in, bacs_gate &g); + +/** + * A BACS gate is a formal expression of the form lhs * rhs = output , + * where lhs and rhs are linear combinations (of variables) and output is a variable. + * + * In other words, a BACS gate is an arithmetic gate that is bilinear. + */ +template +struct bacs_gate { + + linear_combination lhs; + linear_combination rhs; + + variable output; + bool is_circuit_output; + + FieldT evaluate(const bacs_variable_assignment &input) const; + void print(const std::map &variable_annotations = std::map()) const; + + bool operator==(const bacs_gate &other) const; + + friend std::ostream& operator<< (std::ostream &out, const bacs_gate &g); + friend std::istream& operator>> (std::istream &in, bacs_gate &g); +}; + + +/****************************** BACS inputs **********************************/ + +/** + * A BACS primary input is a BACS variable assignment. + */ +template +using bacs_primary_input = bacs_variable_assignment; + +/** + * A BACS auxiliary input is a BACS variable assigment. + */ +template +using bacs_auxiliary_input = bacs_variable_assignment; + + +/************************** BACS circuit *************************************/ + +template +class bacs_circuit; + +template +std::ostream& operator<<(std::ostream &out, const bacs_circuit &circuit); + +template +std::istream& operator>>(std::istream &in, bacs_circuit &circuit); + +/** + * A BACS circuit is an arithmetic circuit in which every gate is a BACS gate. + * + * Given a BACS primary input and a BACS auxiliary input, the circuit can be evaluated. + * If every output evaluates to zero, then the circuit is satisfied. + * + * NOTE: + * The 0-th variable (i.e., "x_{0}") always represents the constant 1. + * Thus, the 0-th variable is not included in num_variables. + */ +template +class bacs_circuit { +public: + size_t primary_input_size; + size_t auxiliary_input_size; + std::vector > gates; + + bacs_circuit() : primary_input_size(0), auxiliary_input_size(0) {} + + size_t num_inputs() const; + size_t num_gates() const; + size_t num_wires() const; + + std::vector wire_depths() const; + size_t depth() const; + +#ifdef DEBUG + std::map gate_annotations; + std::map variable_annotations; +#endif + + bool is_valid() const; + bool is_satisfied(const bacs_primary_input &primary_input, + const bacs_auxiliary_input &auxiliary_input) const; + + bacs_variable_assignment get_all_outputs(const bacs_primary_input &primary_input, + const bacs_auxiliary_input &auxiliary_input) const; + bacs_variable_assignment get_all_wires(const bacs_primary_input &primary_input, + const bacs_auxiliary_input &auxiliary_input) const; + + void add_gate(const bacs_gate &g); + void add_gate(const bacs_gate &g, const std::string &annotation); + + bool operator==(const bacs_circuit &other) const; + + void print() const; + void print_info() const; + + friend std::ostream& operator<< (std::ostream &out, const bacs_circuit &circuit); + friend std::istream& operator>> (std::istream &in, bacs_circuit &circuit); +}; + +} // libsnark + +#include "relations/circuit_satisfaction_problems/bacs/bacs.tcc" + +#endif // BACS_HPP_ diff --git a/privacy/zsl/zsl/relations/circuit_satisfaction_problems/bacs/bacs.tcc b/privacy/zsl/zsl/relations/circuit_satisfaction_problems/bacs/bacs.tcc new file mode 100644 index 0000000..3aff51b --- /dev/null +++ b/privacy/zsl/zsl/relations/circuit_satisfaction_problems/bacs/bacs.tcc @@ -0,0 +1,305 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for: + - a BACS variable assigment, + - a BACS gate, + - a BACS primary input, + - a BACS auxiliary input, + - a BACS circuit. + + See bacs.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BACS_TCC_ +#define BACS_TCC_ + +#include +#include "common/profiling.hpp" +#include "common/utils.hpp" + +namespace libsnark { + +template +FieldT bacs_gate::evaluate(const bacs_variable_assignment &input) const +{ + return lhs.evaluate(input) * rhs.evaluate(input); +} + +template +void bacs_gate::print(const std::map &variable_annotations) const +{ + printf("(\n"); + lhs.print(variable_annotations); + printf(")\n *\n(\n"); + rhs.print(variable_annotations); + printf(")\n -> \n"); + auto it = variable_annotations.find(output.index); + printf(" x_%zu (%s) (%s)\n", + output.index, + (it == variable_annotations.end() ? "no annotation" : it->second.c_str()), + (is_circuit_output ? "circuit output" : "internal wire")); +} + +template +bool bacs_gate::operator==(const bacs_gate &other) const +{ + return (this->lhs == other.lhs && + this->rhs == other.rhs && + this->output == other.output && + this->is_circuit_output == other.is_circuit_output); +} + +template +std::ostream& operator<<(std::ostream &out, const bacs_gate &g) +{ + out << (g.is_circuit_output ? 1 : 0) << "\n"; + out << g.lhs << OUTPUT_NEWLINE; + out << g.rhs << OUTPUT_NEWLINE; + out << g.output.index << "\n"; + + return out; +} + +template +std::istream& operator>>(std::istream &in, bacs_gate &g) +{ + size_t tmp; + in >> tmp; + consume_newline(in); + g.is_circuit_output = (tmp != 0 ? true : false); + in >> g.lhs; + consume_OUTPUT_NEWLINE(in); + in >> g.rhs; + consume_OUTPUT_NEWLINE(in); + in >> g.output.index; + consume_newline(in); + + return in; +} + +template +size_t bacs_circuit::num_inputs() const +{ + return primary_input_size + auxiliary_input_size; +} + +template +size_t bacs_circuit::num_gates() const +{ + return gates.size(); +} + +template +size_t bacs_circuit::num_wires() const +{ + return num_inputs() + num_gates(); +} + +template +std::vector bacs_circuit::wire_depths() const +{ + std::vector depths; + depths.emplace_back(0); + depths.resize(num_inputs() + 1, 1); + + for (auto &g: gates) + { + size_t max_depth = 0; + for (auto &t : g.lhs) + { + max_depth = std::max(max_depth, depths[t.index]); + } + + for (auto &t : g.rhs) + { + max_depth = std::max(max_depth, depths[t.index]); + } + + depths.emplace_back(max_depth + 1); + } + + return depths; +} + +template +size_t bacs_circuit::depth() const +{ + std::vector all_depths = this->wire_depths(); + return *(std::max_element(all_depths.begin(), all_depths.end())); +} + +template +bool bacs_circuit::is_valid() const +{ + for (size_t i = 0; i < num_gates(); ++i) + { + /** + * The output wire of gates[i] must have index 1+num_inputs+i. + * (The '1+' accounts for the the index of the constant wire.) + */ + if (gates[i].output.index != 1+num_inputs()+i) + { + return false; + } + + /** + * Gates must be topologically sorted. + */ + if (!gates[i].lhs.is_valid(gates[i].output.index) || !gates[i].rhs.is_valid(gates[i].output.index)) + { + return false; + } + } + + return true; +} + +template +bacs_variable_assignment bacs_circuit::get_all_wires(const bacs_primary_input &primary_input, + const bacs_auxiliary_input &auxiliary_input) const +{ + assert(primary_input.size() == primary_input_size); + assert(auxiliary_input.size() == auxiliary_input_size); + + bacs_variable_assignment result; + result.insert(result.end(), primary_input.begin(), primary_input.end()); + result.insert(result.end(), auxiliary_input.begin(), auxiliary_input.end()); + + assert(result.size() == num_inputs()); + + for (auto &g : gates) + { + const FieldT gate_output = g.evaluate(result); + result.emplace_back(gate_output); + } + + return result; +} + +template +bacs_variable_assignment bacs_circuit::get_all_outputs(const bacs_primary_input &primary_input, + const bacs_auxiliary_input &auxiliary_input) const +{ + const bacs_variable_assignment all_wires = get_all_wires(primary_input, auxiliary_input); + + bacs_variable_assignment all_outputs; + + for (auto &g: gates) + { + if (g.is_circuit_output) + { + all_outputs.emplace_back(all_wires[g.output.index-1]); + } + } + + return all_outputs; +} + +template +bool bacs_circuit::is_satisfied(const bacs_primary_input &primary_input, + const bacs_auxiliary_input &auxiliary_input) const +{ + const bacs_variable_assignment all_outputs = get_all_outputs(primary_input, auxiliary_input); + + for (size_t i = 0; i < all_outputs.size(); ++i) + { + if (!all_outputs[i].is_zero()) + { + return false; + } + } + + return true; +} + +template +void bacs_circuit::add_gate(const bacs_gate &g) +{ + assert(g.output.index == num_wires()+1); + gates.emplace_back(g); +} + +template +void bacs_circuit::add_gate(const bacs_gate &g, const std::string &annotation) +{ + assert(g.output.index == num_wires()+1); + gates.emplace_back(g); +#ifdef DEBUG + gate_annotations[g.output.index] = annotation; +#endif +} + +template +bool bacs_circuit::operator==(const bacs_circuit &other) const +{ + return (this->primary_input_size == other.primary_input_size && + this->auxiliary_input_size == other.auxiliary_input_size && + this->gates == other.gates); +} + +template +std::ostream& operator<<(std::ostream &out, const bacs_circuit &circuit) +{ + out << circuit.primary_input_size << "\n"; + out << circuit.auxiliary_input_size << "\n"; + out << circuit.gates << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, bacs_circuit &circuit) +{ + in >> circuit.primary_input_size; + consume_newline(in); + in >> circuit.auxiliary_input_size; + consume_newline(in); + in >> circuit.gates; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +void bacs_circuit::print() const +{ + print_indent(); printf("General information about the circuit:\n"); + this->print_info(); + print_indent(); printf("All gates:\n"); + for (size_t i = 0; i < gates.size(); ++i) + { + std::string annotation = "no annotation"; +#ifdef DEBUG + auto it = gate_annotations.find(i); + if (it != gate_annotations.end()) + { + annotation = it->second; + } +#endif + printf("Gate %zu (%s):\n", i, annotation.c_str()); +#ifdef DEBUG + gates[i].print(variable_annotations); +#else + gates[i].print(); +#endif + } +} + +template +void bacs_circuit::print_info() const +{ + print_indent(); printf("* Number of inputs: %zu\n", this->num_inputs()); + print_indent(); printf("* Number of gates: %zu\n", this->num_gates()); + print_indent(); printf("* Number of wires: %zu\n", this->num_wires()); + print_indent(); printf("* Depth: %zu\n", this->depth()); +} + +} // libsnark + +#endif // BACS_TCC_ diff --git a/privacy/zsl/zsl/relations/circuit_satisfaction_problems/bacs/examples/bacs_examples.hpp b/privacy/zsl/zsl/relations/circuit_satisfaction_problems/bacs/examples/bacs_examples.hpp new file mode 100644 index 0000000..565cf4b --- /dev/null +++ b/privacy/zsl/zsl/relations/circuit_satisfaction_problems/bacs/examples/bacs_examples.hpp @@ -0,0 +1,71 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a BACS example, as well as functions to sample + BACS examples with prescribed parameters (according to some distribution). + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BACS_EXAMPLES_HPP_ +#define BACS_EXAMPLES_HPP_ + +#include "relations/circuit_satisfaction_problems/bacs/bacs.hpp" + +namespace libsnark { + +/** + * A BACS example comprises a BACS circuit, BACS primary input, and BACS auxiliary input. + */ +template +struct bacs_example { + + bacs_circuit circuit; + bacs_primary_input primary_input; + bacs_auxiliary_input auxiliary_input; + + bacs_example() = default; + bacs_example(const bacs_example &other) = default; + bacs_example(const bacs_circuit &circuit, + const bacs_primary_input &primary_input, + const bacs_auxiliary_input &auxiliary_input) : + circuit(circuit), + primary_input(primary_input), + auxiliary_input(auxiliary_input) + {} + + bacs_example(bacs_circuit &&circuit, + bacs_primary_input &&primary_input, + bacs_auxiliary_input &&auxiliary_input) : + circuit(std::move(circuit)), + primary_input(std::move(primary_input)), + auxiliary_input(std::move(auxiliary_input)) + {} +}; + +/** + * Generate a BACS example such that: + * - the primary input has size primary_input_size; + * - the auxiliary input has size auxiliary_input_size; + * - the circuit has num_gates gates; + * - the circuit has num_outputs (<= num_gates) output gates. + * + * This is done by first selecting primary and auxiliary inputs uniformly at random, and then for each gate: + * - selecting random left and right wires from primary inputs, auxiliary inputs, and outputs of previous gates, + * - selecting random linear combinations for left and right wires, consisting of 1, 2, 3 or 4 terms each, with random coefficients, + * - if the gate is an output gate, then adding a random non-output wire to either left or right linear combination, with appropriate coefficient, so that the linear combination evaluates to 0. + */ +template +bacs_example generate_bacs_example(const size_t primary_input_size, + const size_t auxiliary_input_size, + const size_t num_gates, + const size_t num_outputs); + +} // libsnark + +#include "relations/circuit_satisfaction_problems/bacs/examples/bacs_examples.tcc" + +#endif // BACS_EXAMPLES_HPP_ diff --git a/privacy/zsl/zsl/relations/circuit_satisfaction_problems/bacs/examples/bacs_examples.tcc b/privacy/zsl/zsl/relations/circuit_satisfaction_problems/bacs/examples/bacs_examples.tcc new file mode 100644 index 0000000..d4fca1f --- /dev/null +++ b/privacy/zsl/zsl/relations/circuit_satisfaction_problems/bacs/examples/bacs_examples.tcc @@ -0,0 +1,109 @@ +/** @file + ***************************************************************************** + + Implementation of functions to sample BACS examples with prescribed parameters + (according to some distribution). + + See bacs_examples.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BACS_EXAMPLES_TCC_ +#define BACS_EXAMPLES_TCC_ + +#include + +#include "common/utils.hpp" + +namespace libsnark { + +template +linear_combination random_linear_combination(const size_t num_variables) +{ + const size_t terms = 1 + (std::rand() % 3); + linear_combination result; + + for (size_t i = 0; i < terms; ++i) + { + const FieldT coeff = FieldT(std::rand()); // TODO: replace with FieldT::random_element(), when it becomes faster... + result = result + coeff * variable(std::rand() % (num_variables + 1)); + } + + return result; +} + +template +bacs_example generate_bacs_example(const size_t primary_input_size, + const size_t auxiliary_input_size, + const size_t num_gates, + const size_t num_outputs) +{ + bacs_example example; + for (size_t i = 0; i < primary_input_size; ++i) + { + example.primary_input.emplace_back(FieldT::random_element()); + } + + for (size_t i = 0; i < auxiliary_input_size; ++i) + { + example.auxiliary_input.emplace_back(FieldT::random_element()); + } + + example.circuit.primary_input_size = primary_input_size; + example.circuit.auxiliary_input_size = auxiliary_input_size; + + bacs_variable_assignment all_vals; + all_vals.insert(all_vals.end(), example.primary_input.begin(), example.primary_input.end()); + all_vals.insert(all_vals.end(), example.auxiliary_input.begin(), example.auxiliary_input.end()); + + for (size_t i = 0; i < num_gates; ++i) + { + const size_t num_variables = primary_input_size + auxiliary_input_size + i; + bacs_gate gate; + gate.lhs = random_linear_combination(num_variables); + gate.rhs = random_linear_combination(num_variables); + gate.output = variable(num_variables+1); + + if (i >= num_gates - num_outputs) + { + /* make gate a circuit output and fix */ + gate.is_circuit_output = true; + const var_index_t var_idx = std::rand() % (1 + primary_input_size + std::min(num_gates-num_outputs, i)); + const FieldT var_val = (var_idx == 0 ? FieldT::one() : all_vals[var_idx-1]); + + if (std::rand() % 2 == 0) + { + const FieldT lhs_val = gate.lhs.evaluate(all_vals); + const FieldT coeff = -(lhs_val * var_val.inverse()); + gate.lhs = gate.lhs + coeff * variable(var_idx); + } + else + { + const FieldT rhs_val = gate.rhs.evaluate(all_vals); + const FieldT coeff = -(rhs_val * var_val.inverse()); + gate.rhs = gate.rhs + coeff * variable(var_idx); + } + + assert(gate.evaluate(all_vals).is_zero()); + } + else + { + gate.is_circuit_output = false; + } + + example.circuit.add_gate(gate); + all_vals.emplace_back(gate.evaluate(all_vals)); + } + + assert(example.circuit.is_satisfied(example.primary_input, example.auxiliary_input)); + + return example; +} + +} // libsnark + +#endif // BACS_EXAMPLES_TCC diff --git a/privacy/zsl/zsl/relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.cpp b/privacy/zsl/zsl/relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.cpp new file mode 100644 index 0000000..c8e703e --- /dev/null +++ b/privacy/zsl/zsl/relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.cpp @@ -0,0 +1,80 @@ +/** @file + ***************************************************************************** + + Implementation of functions to sample TBCS examples with prescribed parameters + (according to some distribution). + + See tbcs_examples.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.hpp" + +#include + +#include "common/utils.hpp" + +namespace libsnark { + +tbcs_example generate_tbcs_example(const size_t primary_input_size, + const size_t auxiliary_input_size, + const size_t num_gates, + const size_t num_outputs) +{ + tbcs_example example; + for (size_t i = 0; i < primary_input_size; ++i) + { + example.primary_input.push_back(std::rand() % 2 == 0 ? false : true); + } + + for (size_t i = 0; i < auxiliary_input_size; ++i) + { + example.auxiliary_input.push_back(std::rand() % 2 == 0 ? false : true); + } + + example.circuit.primary_input_size = primary_input_size; + example.circuit.auxiliary_input_size = auxiliary_input_size; + + tbcs_variable_assignment all_vals; + all_vals.insert(all_vals.end(), example.primary_input.begin(), example.primary_input.end()); + all_vals.insert(all_vals.end(), example.auxiliary_input.begin(), example.auxiliary_input.end()); + + for (size_t i = 0; i < num_gates; ++i) + { + const size_t num_variables = primary_input_size + auxiliary_input_size + i; + tbcs_gate gate; + gate.left_wire = std::rand() % (num_variables+1); + gate.right_wire = std::rand() % (num_variables+1); + gate.output = num_variables+1; + + if (i >= num_gates - num_outputs) + { + /* make gate a circuit output and fix */ + do + { + gate.type = (tbcs_gate_type)(std::rand() % num_tbcs_gate_types); + } + while (gate.evaluate(all_vals)); + + gate.is_circuit_output = true; + } + else + { + gate.type = (tbcs_gate_type)(std::rand() % num_tbcs_gate_types); + gate.is_circuit_output = false; + } + + example.circuit.add_gate(gate); + all_vals.push_back(gate.evaluate(all_vals)); + } + + assert(example.circuit.is_satisfied(example.primary_input, example.auxiliary_input)); + + return example; +} + +} // libsnark diff --git a/privacy/zsl/zsl/relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.d b/privacy/zsl/zsl/relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.d new file mode 100644 index 0000000..cfc683b --- /dev/null +++ b/privacy/zsl/zsl/relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.d @@ -0,0 +1,8 @@ +src/relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.o: \ + src/relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.cpp \ + src/relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.hpp \ + src/relations/circuit_satisfaction_problems/tbcs/tbcs.hpp \ + src/common/profiling.hpp src/relations/variable.hpp \ + src/relations/variable.tcc src/algebra/fields/bigint.hpp \ + src/common/serialization.hpp src/common/serialization.tcc \ + src/common/utils.hpp src/common/utils.tcc src/algebra/fields/bigint.tcc diff --git a/privacy/zsl/zsl/relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.hpp b/privacy/zsl/zsl/relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.hpp new file mode 100644 index 0000000..f236f74 --- /dev/null +++ b/privacy/zsl/zsl/relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.hpp @@ -0,0 +1,66 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a TBCS example, as well as functions to sample + TBCS examples with prescribed parameters (according to some distribution). + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TBCS_EXAMPLES_HPP_ +#define TBCS_EXAMPLES_HPP_ + +#include "relations/circuit_satisfaction_problems/tbcs/tbcs.hpp" + +namespace libsnark { + +/** + * A TBCS example comprises a TBCS circuit, TBCS primary input, and TBCS auxiliary input. + */ +struct tbcs_example { + + tbcs_circuit circuit; + tbcs_primary_input primary_input; + tbcs_auxiliary_input auxiliary_input; + + tbcs_example() = default; + tbcs_example(const tbcs_example &other) = default; + tbcs_example(const tbcs_circuit &circuit, + const tbcs_primary_input &primary_input, + const tbcs_auxiliary_input &auxiliary_input) : + circuit(circuit), + primary_input(primary_input), + auxiliary_input(auxiliary_input) + {} + + tbcs_example(tbcs_circuit &&circuit, + tbcs_primary_input &&primary_input, + tbcs_auxiliary_input &&auxiliary_input) : + circuit(std::move(circuit)), + primary_input(std::move(primary_input)), + auxiliary_input(std::move(auxiliary_input)) + {} +}; + +/** + * Generate a TBCS example such that: + * - the primary input has size primary_input_size; + * - the auxiliary input has size auxiliary_input_size; + * - the circuit has num_gates gates; + * - the circuit has num_outputs (<= num_gates) output gates. + * + * This is done by first selecting primary and auxiliary inputs uniformly at random, and then for each gate: + * - selecting random left and right wires from primary inputs, auxiliary inputs, and outputs of previous gates, + * - selecting a gate type at random (subject to the constraint "output = 0" if this is an output gate). + */ +tbcs_example generate_tbcs_example(const size_t primary_input_size, + const size_t auxiliary_input_size, + const size_t num_gates, + const size_t num_outputs); + +} // libsnark + +#endif // TBCS_EXAMPLES_HPP_ diff --git a/privacy/zsl/zsl/relations/circuit_satisfaction_problems/tbcs/tbcs.cpp b/privacy/zsl/zsl/relations/circuit_satisfaction_problems/tbcs/tbcs.cpp new file mode 100644 index 0000000..599c0ae --- /dev/null +++ b/privacy/zsl/zsl/relations/circuit_satisfaction_problems/tbcs/tbcs.cpp @@ -0,0 +1,348 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for: + - a TBCS gate, + - a TBCS variable assignment, and + - a TBCS constraint system. + + See tbcs.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "relations/circuit_satisfaction_problems/tbcs/tbcs.hpp" + +#include +#include "common/utils.hpp" + +namespace libsnark { + +bool tbcs_gate::evaluate(const tbcs_variable_assignment &input) const +{ + /** + * This function is very tricky. + * See comment in tbcs.hpp . + */ + + const bool X = (left_wire == 0 ? true : input[left_wire - 1]); + const bool Y = (right_wire == 0 ? true : input[right_wire - 1]); + + const size_t pos = 3 - ((X ? 2 : 0) + (Y ? 1 : 0)); /* 3 - ... inverts position */ + + return (((int)type) & (1u << pos)); +} + +void print_tbcs_wire(const tbcs_wire_t wire, const std::map &variable_annotations) +{ + /** + * The type tbcs_wire_t does not deserve promotion to a class, + * but still benefits from a dedicated printing mechanism. + */ + if (wire == 0) + { + printf(" 1"); + } + else + { + auto it = variable_annotations.find(wire); + printf(" x_%zu (%s)", + wire, + (it == variable_annotations.end() ? "no annotation" : it->second.c_str())); + } +} + +void tbcs_gate::print(const std::map &variable_annotations) const +{ + switch (this->type) + { + case TBCS_GATE_CONSTANT_0: + printf("CONSTANT_0"); + break; + case TBCS_GATE_AND: + printf("AND"); + break; + case TBCS_GATE_X_AND_NOT_Y: + printf("X_AND_NOT_Y"); + break; + case TBCS_GATE_X: + printf("X"); + break; + case TBCS_GATE_NOT_X_AND_Y: + printf("NOT_X_AND_Y"); + break; + case TBCS_GATE_Y: + printf("Y"); + break; + case TBCS_GATE_XOR: + printf("XOR"); + break; + case TBCS_GATE_OR: + printf("OR"); + break; + case TBCS_GATE_NOR: + printf("NOR"); + break; + case TBCS_GATE_EQUIVALENCE: + printf("EQUIVALENCE"); + break; + case TBCS_GATE_NOT_Y: + printf("NOT_Y"); + break; + case TBCS_GATE_IF_Y_THEN_X: + printf("IF_Y_THEN_X"); + break; + case TBCS_GATE_NOT_X: + printf("NOT_X"); + break; + case TBCS_GATE_IF_X_THEN_Y: + printf("IF_X_THEN_Y"); + break; + case TBCS_GATE_NAND: + printf("NAND"); + break; + case TBCS_GATE_CONSTANT_1: + printf("CONSTANT_1"); + break; + default: + printf("Invalid type"); + } + + printf("\n(\n"); + print_tbcs_wire(left_wire, variable_annotations); + printf(",\n"); + print_tbcs_wire(right_wire, variable_annotations); + printf("\n) ->\n"); + print_tbcs_wire(output, variable_annotations); + printf(" (%s)\n", is_circuit_output ? "circuit output" : "internal wire"); +} + +bool tbcs_gate::operator==(const tbcs_gate &other) const +{ + return (this->left_wire == other.left_wire && + this->right_wire == other.right_wire && + this->type == other.type && + this->output == other.output && + this->is_circuit_output == other.is_circuit_output); +} + +std::ostream& operator<<(std::ostream &out, const tbcs_gate &g) +{ + out << g.left_wire << "\n"; + out << g.right_wire << "\n"; + out << (int)g.type << "\n"; + out << g.output << "\n"; + output_bool(out, g.is_circuit_output); + + return out; +} + +std::istream& operator>>(std::istream &in, tbcs_gate &g) +{ + in >> g.left_wire; + consume_newline(in); + in >> g.right_wire; + consume_newline(in); + int tmp; + in >> tmp; + g.type = (tbcs_gate_type)tmp; + consume_newline(in); + in >> g.output; + input_bool(in, g.is_circuit_output); + + return in; +} + +std::vector tbcs_circuit::wire_depths() const +{ + std::vector depths(num_inputs(), 1); + + for (auto &g: gates) + { + depths.emplace_back(std::max(depths[g.left_wire], depths[g.right_wire]) + 1); + } + + return depths; +} + +size_t tbcs_circuit::num_inputs() const +{ + return primary_input_size + auxiliary_input_size; +} + +size_t tbcs_circuit::num_gates() const +{ + return gates.size(); +} + +size_t tbcs_circuit::num_wires() const +{ + return num_inputs() + num_gates(); +} + +size_t tbcs_circuit::depth() const +{ + std::vector all_depths = this->wire_depths(); + return *(std::max_element(all_depths.begin(), all_depths.end())); +} + +bool tbcs_circuit::is_valid() const +{ + for (size_t i = 0; i < num_gates(); ++i) + { + /** + * The output wire of gates[i] must have index 1+num_inputs+i. + * (The '1+' accounts for the the index of the constant wire.) + */ + if (gates[i].output != num_inputs()+i+1) + { + return false; + } + + /** + * Gates must be topologically sorted. + */ + if (gates[i].left_wire >= gates[i].output || gates[i].right_wire >= gates[i].output) + { + return false; + } + } + + return true; +} + +tbcs_variable_assignment tbcs_circuit::get_all_wires(const tbcs_primary_input &primary_input, + const tbcs_auxiliary_input &auxiliary_input) const +{ + assert(primary_input.size() == primary_input_size); + assert(auxiliary_input.size() == auxiliary_input_size); + + tbcs_variable_assignment result; + result.insert(result.end(), primary_input.begin(), primary_input.end()); + result.insert(result.end(), auxiliary_input.begin(), auxiliary_input.end()); + + assert(result.size() == num_inputs()); + + for (auto &g : gates) + { + const bool gate_output = g.evaluate(result); + result.push_back(gate_output); + } + + return result; +} + +tbcs_variable_assignment tbcs_circuit::get_all_outputs(const tbcs_primary_input &primary_input, + const tbcs_auxiliary_input &auxiliary_input) const +{ + const tbcs_variable_assignment all_wires = get_all_wires(primary_input, auxiliary_input); + tbcs_variable_assignment all_outputs; + + for (auto &g : gates) + { + if (g.is_circuit_output) + { + all_outputs.push_back(all_wires[g.output-1]); + } + } + + return all_outputs; +} + + +bool tbcs_circuit::is_satisfied(const tbcs_primary_input &primary_input, + const tbcs_auxiliary_input &auxiliary_input) const +{ + const tbcs_variable_assignment all_outputs = get_all_outputs(primary_input, auxiliary_input); + for (size_t i = 0; i < all_outputs.size(); ++i) + { + if (all_outputs[i]) + { + return false; + } + } + + return true; +} + +void tbcs_circuit::add_gate(const tbcs_gate &g) +{ + assert(g.output == num_wires()+1); + gates.emplace_back(g); +} + +void tbcs_circuit::add_gate(const tbcs_gate &g, const std::string &annotation) +{ + assert(g.output == num_wires()+1); + gates.emplace_back(g); +#ifdef DEBUG + gate_annotations[g.output] = annotation; +#else + UNUSED(annotation); +#endif +} + +bool tbcs_circuit::operator==(const tbcs_circuit &other) const +{ + return (this->primary_input_size == other.primary_input_size && + this->auxiliary_input_size == other.auxiliary_input_size && + this->gates == other.gates); +} + +std::ostream& operator<<(std::ostream &out, const tbcs_circuit &circuit) +{ + out << circuit.primary_input_size << "\n"; + out << circuit.auxiliary_input_size << "\n"; + out << circuit.gates << OUTPUT_NEWLINE; + + return out; +} + +std::istream& operator>>(std::istream &in, tbcs_circuit &circuit) +{ + in >> circuit.primary_input_size; + consume_newline(in); + in >> circuit.auxiliary_input_size; + consume_newline(in); + in >> circuit.gates; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +void tbcs_circuit::print() const +{ + print_indent(); printf("General information about the circuit:\n"); + this->print_info(); + print_indent(); printf("All gates:\n"); + for (size_t i = 0; i < gates.size(); ++i) + { + std::string annotation = "no annotation"; +#ifdef DEBUG + auto it = gate_annotations.find(i); + if (it != gate_annotations.end()) + { + annotation = it->second; + } +#endif + printf("Gate %zu (%s):\n", i, annotation.c_str()); +#ifdef DEBUG + gates[i].print(variable_annotations); +#else + gates[i].print(); +#endif + } +} + +void tbcs_circuit::print_info() const +{ + print_indent(); printf("* Number of inputs: %zu\n", this->num_inputs()); + print_indent(); printf("* Number of gates: %zu\n", this->num_gates()); + print_indent(); printf("* Number of wires: %zu\n", this->num_wires()); + print_indent(); printf("* Depth: %zu\n", this->depth()); +} + +} // libsnark diff --git a/privacy/zsl/zsl/relations/circuit_satisfaction_problems/tbcs/tbcs.d b/privacy/zsl/zsl/relations/circuit_satisfaction_problems/tbcs/tbcs.d new file mode 100644 index 0000000..8170f30 --- /dev/null +++ b/privacy/zsl/zsl/relations/circuit_satisfaction_problems/tbcs/tbcs.d @@ -0,0 +1,7 @@ +src/relations/circuit_satisfaction_problems/tbcs/tbcs.o: \ + src/relations/circuit_satisfaction_problems/tbcs/tbcs.cpp \ + src/relations/circuit_satisfaction_problems/tbcs/tbcs.hpp \ + src/common/profiling.hpp src/relations/variable.hpp \ + src/relations/variable.tcc src/algebra/fields/bigint.hpp \ + src/common/serialization.hpp src/common/serialization.tcc \ + src/common/utils.hpp src/common/utils.tcc src/algebra/fields/bigint.tcc diff --git a/privacy/zsl/zsl/relations/circuit_satisfaction_problems/tbcs/tbcs.hpp b/privacy/zsl/zsl/relations/circuit_satisfaction_problems/tbcs/tbcs.hpp new file mode 100644 index 0000000..cc1f96f --- /dev/null +++ b/privacy/zsl/zsl/relations/circuit_satisfaction_problems/tbcs/tbcs.hpp @@ -0,0 +1,175 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for: + - a TBCS gate, + - a TBCS variable assignment, and + - a TBCS circuit. + + Above, TBCS stands for "Two-input Boolean Circuit Satisfiability". + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TBCS_HPP_ +#define TBCS_HPP_ + +#include "common/profiling.hpp" +#include "relations/variable.hpp" + +namespace libsnark { + +/*********************** BACS variable assignment ****************************/ + +/** + * A TBCS variable assignment is a vector of bools. + */ +typedef std::vector tbcs_variable_assignment; + + +/**************************** TBCS gate **************************************/ + +typedef size_t tbcs_wire_t; + +/** + * Types of TBCS gates (2-input boolean gates). + * + * The order and names used below is taken from page 4 of [1]. + * + * Note that each gate's truth table is encoded in its 4-bit opcode. Namely, + * if g(X,Y) denotes the output of gate g with inputs X and Y, then + * OPCODE(g) = (g(0,0),g(0,1),g(1,0),g(1,1)) + * For example, if g is of type IF_X_THEN_Y, which has opcode 13, then the + * truth table of g is 1101 (13 in binary). + * + * (Note that MSB above is g(0,0) and LSB is g(1,1)) + * + * References: + * + * [1] = https://mitpress.mit.edu/sites/default/files/titles/content/9780262640688_sch_0001.pdf + */ +enum tbcs_gate_type { + TBCS_GATE_CONSTANT_0 = 0, + TBCS_GATE_AND = 1, + TBCS_GATE_X_AND_NOT_Y = 2, + TBCS_GATE_X = 3, + TBCS_GATE_NOT_X_AND_Y = 4, + TBCS_GATE_Y = 5, + TBCS_GATE_XOR = 6, + TBCS_GATE_OR = 7, + TBCS_GATE_NOR = 8, + TBCS_GATE_EQUIVALENCE = 9, + TBCS_GATE_NOT_Y = 10, + TBCS_GATE_IF_Y_THEN_X = 11, + TBCS_GATE_NOT_X = 12, + TBCS_GATE_IF_X_THEN_Y = 13, + TBCS_GATE_NAND = 14, + TBCS_GATE_CONSTANT_1 = 15 +}; + +static const int num_tbcs_gate_types = 16; + +/** + * A TBCS gate is a formal expression of the form + * + * g(left_wire,right_wire) = output , + * + * where 'left_wire' and 'right_wire' are the two input wires, and 'output' is + * the output wire. In other words, a TBCS gate is a 2-input boolean gate; + * there are 16 possible such gates (see tbcs_gate_type above). + * + * A TBCS gate is used to construct a TBCS circuit (see below). + */ +class tbcs_gate { +public: + + tbcs_wire_t left_wire; + tbcs_wire_t right_wire; + + tbcs_gate_type type; + + tbcs_wire_t output; + + bool is_circuit_output; + + bool evaluate(const tbcs_variable_assignment &input) const; + void print(const std::map &variable_annotations = std::map()) const; + bool operator==(const tbcs_gate &other) const; + + friend std::ostream& operator<<(std::ostream &out, const tbcs_gate &g); + friend std::istream& operator>>(std::istream &in, tbcs_gate &g); +}; + + +/****************************** TBCS inputs **********************************/ + +/** + * A TBCS primary input is a TBCS variable assignment. + */ +typedef tbcs_variable_assignment tbcs_primary_input; + +/** + * A TBCS auxiliary input is a TBCS variable assigment. + */ +typedef tbcs_variable_assignment tbcs_auxiliary_input; + + +/************************** TBCS circuit *************************************/ + +/** + * A TBCS circuit is a boolean circuit in which every gate has 2 inputs. + * + * A TBCS circuit is satisfied by a TBCS variable assignment if every output + * evaluates to zero. + * + * NOTE: + * The 0-th variable (i.e., "x_{0}") always represents the constant 1. + * Thus, the 0-th variable is not included in num_variables. + */ +class tbcs_circuit { +public: + size_t primary_input_size; + size_t auxiliary_input_size; + std::vector gates; + + tbcs_circuit() : primary_input_size(0), auxiliary_input_size(0) {} + + size_t num_inputs() const; + size_t num_gates() const; + size_t num_wires() const; + + std::vector wire_depths() const; + size_t depth() const; + +#ifdef DEBUG + std::map gate_annotations; + std::map variable_annotations; +#endif + + bool is_valid() const; + bool is_satisfied(const tbcs_primary_input &primary_input, + const tbcs_auxiliary_input &auxiliary_input) const; + + tbcs_variable_assignment get_all_wires(const tbcs_primary_input &primary_input, + const tbcs_auxiliary_input &auxiliary_input) const; + tbcs_variable_assignment get_all_outputs(const tbcs_primary_input &primary_input, + const tbcs_auxiliary_input &auxiliary_input) const; + + void add_gate(const tbcs_gate &g); + void add_gate(const tbcs_gate &g, const std::string &annotation); + + bool operator==(const tbcs_circuit &other) const; + + void print() const; + void print_info() const; + + friend std::ostream& operator<<(std::ostream &out, const tbcs_circuit &circuit); + friend std::istream& operator>>(std::istream &in, tbcs_circuit &circuit); +}; + +} // libsnark + +#endif // TBCS_HPP_ diff --git a/privacy/zsl/zsl/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp b/privacy/zsl/zsl/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp new file mode 100644 index 0000000..47003e9 --- /dev/null +++ b/privacy/zsl/zsl/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp @@ -0,0 +1,73 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a R1CS example, as well as functions to sample + R1CS examples with prescribed parameters (according to some distribution). + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_EXAMPLES_HPP_ +#define R1CS_EXAMPLES_HPP_ + +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" + +namespace libsnark { + +/** + * A R1CS example comprises a R1CS constraint system, R1CS input, and R1CS witness. + */ +template +struct r1cs_example { + r1cs_constraint_system constraint_system; + r1cs_primary_input primary_input; + r1cs_auxiliary_input auxiliary_input; + + r1cs_example() = default; + r1cs_example(const r1cs_example &other) = default; + r1cs_example(const r1cs_constraint_system &constraint_system, + const r1cs_primary_input &primary_input, + const r1cs_auxiliary_input &auxiliary_input) : + constraint_system(constraint_system), + primary_input(primary_input), + auxiliary_input(auxiliary_input) + {}; + r1cs_example(r1cs_constraint_system &&constraint_system, + r1cs_primary_input &&primary_input, + r1cs_auxiliary_input &&auxiliary_input) : + constraint_system(std::move(constraint_system)), + primary_input(std::move(primary_input)), + auxiliary_input(std::move(auxiliary_input)) + {}; +}; + +/** + * Generate a R1CS example such that: + * - the number of constraints of the R1CS constraint system is num_constraints; + * - the number of variables of the R1CS constraint system is (approximately) num_constraints; + * - the number of inputs of the R1CS constraint system is num_inputs; + * - the R1CS input consists of ``full'' field elements (typically require the whole log|Field| bits to represent). + */ +template +r1cs_example generate_r1cs_example_with_field_input(const size_t num_constraints, + const size_t num_inputs); + +/** + * Generate a R1CS example such that: + * - the number of constraints of the R1CS constraint system is num_constraints; + * - the number of variables of the R1CS constraint system is (approximately) num_constraints; + * - the number of inputs of the R1CS constraint system is num_inputs; + * - the R1CS input consists of binary values (as opposed to ``full'' field elements). + */ +template +r1cs_example generate_r1cs_example_with_binary_input(const size_t num_constraints, + const size_t num_inputs); + +} // libsnark + +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc" + +#endif // R1CS_EXAMPLES_HPP_ diff --git a/privacy/zsl/zsl/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc b/privacy/zsl/zsl/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc new file mode 100644 index 0000000..defa077 --- /dev/null +++ b/privacy/zsl/zsl/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc @@ -0,0 +1,164 @@ +/** @file + ***************************************************************************** + + Implementation of functions to sample R1CS examples with prescribed parameters + (according to some distribution). + + See r1cs_examples.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_EXAMPLES_TCC_ +#define R1CS_EXAMPLES_TCC_ + +#include + +#include "common/utils.hpp" + +namespace libsnark { + +template +r1cs_example generate_r1cs_example_with_field_input(const size_t num_constraints, + const size_t num_inputs) +{ + enter_block("Call to generate_r1cs_example_with_field_input"); + + assert(num_inputs <= num_constraints + 2); + + r1cs_constraint_system cs; + cs.primary_input_size = num_inputs; + cs.auxiliary_input_size = 2 + num_constraints - num_inputs; // TODO: explain this + + r1cs_variable_assignment full_variable_assignment; + FieldT a = FieldT::random_element(); + FieldT b = FieldT::random_element(); + full_variable_assignment.push_back(a); + full_variable_assignment.push_back(b); + + for (size_t i = 0; i < num_constraints-1; ++i) + { + linear_combination A, B, C; + + if (i % 2) + { + // a * b = c + A.add_term(i+1, 1); + B.add_term(i+2, 1); + C.add_term(i+3, 1); + FieldT tmp = a*b; + full_variable_assignment.push_back(tmp); + a = b; b = tmp; + } + else + { + // a + b = c + B.add_term(0, 1); + A.add_term(i+1, 1); + A.add_term(i+2, 1); + C.add_term(i+3, 1); + FieldT tmp = a+b; + full_variable_assignment.push_back(tmp); + a = b; b = tmp; + } + + cs.add_constraint(r1cs_constraint(A, B, C)); + } + + linear_combination A, B, C; + FieldT fin = FieldT::zero(); + for (size_t i = 1; i < cs.num_variables(); ++i) + { + A.add_term(i, 1); + B.add_term(i, 1); + fin = fin + full_variable_assignment[i-1]; + } + C.add_term(cs.num_variables(), 1); + cs.add_constraint(r1cs_constraint(A, B, C)); + full_variable_assignment.push_back(fin.squared()); + + /* split variable assignment */ + r1cs_primary_input primary_input(full_variable_assignment.begin(), full_variable_assignment.begin() + num_inputs); + r1cs_primary_input auxiliary_input(full_variable_assignment.begin() + num_inputs, full_variable_assignment.end()); + + /* sanity checks */ + assert(cs.num_variables() == full_variable_assignment.size()); + assert(cs.num_variables() >= num_inputs); + assert(cs.num_inputs() == num_inputs); + assert(cs.num_constraints() == num_constraints); + assert(cs.is_satisfied(primary_input, auxiliary_input)); + + leave_block("Call to generate_r1cs_example_with_field_input"); + + return r1cs_example(std::move(cs), std::move(primary_input), std::move(auxiliary_input)); +} + +template +r1cs_example generate_r1cs_example_with_binary_input(const size_t num_constraints, + const size_t num_inputs) +{ + enter_block("Call to generate_r1cs_example_with_binary_input"); + + assert(num_inputs >= 1); + + r1cs_constraint_system cs; + cs.primary_input_size = num_inputs; + cs.auxiliary_input_size = num_constraints; /* we will add one auxiliary variable per constraint */ + + r1cs_variable_assignment full_variable_assignment; + for (size_t i = 0; i < num_inputs; ++i) + { + full_variable_assignment.push_back(FieldT(std::rand() % 2)); + } + + size_t lastvar = num_inputs-1; + for (size_t i = 0; i < num_constraints; ++i) + { + ++lastvar; + const size_t u = (i == 0 ? std::rand() % num_inputs : std::rand() % i); + const size_t v = (i == 0 ? std::rand() % num_inputs : std::rand() % i); + + /* chose two random bits and XOR them together: + res = u + v - 2 * u * v + 2 * u * v = u + v - res + */ + linear_combination A, B, C; + A.add_term(u+1, 2); + B.add_term(v+1, 1); + if (u == v) + { + C.add_term(u+1, 2); + } + else + { + C.add_term(u+1, 1); + C.add_term(v+1, 1); + } + C.add_term(lastvar+1, -FieldT::one()); + + cs.add_constraint(r1cs_constraint(A, B, C)); + full_variable_assignment.push_back(full_variable_assignment[u] + full_variable_assignment[v] - full_variable_assignment[u] * full_variable_assignment[v] - full_variable_assignment[u] * full_variable_assignment[v]); + } + + /* split variable assignment */ + r1cs_primary_input primary_input(full_variable_assignment.begin(), full_variable_assignment.begin() + num_inputs); + r1cs_primary_input auxiliary_input(full_variable_assignment.begin() + num_inputs, full_variable_assignment.end()); + + /* sanity checks */ + assert(cs.num_variables() == full_variable_assignment.size()); + assert(cs.num_variables() >= num_inputs); + assert(cs.num_inputs() == num_inputs); + assert(cs.num_constraints() == num_constraints); + assert(cs.is_satisfied(primary_input, auxiliary_input)); + + leave_block("Call to generate_r1cs_example_with_binary_input"); + + return r1cs_example(std::move(cs), std::move(primary_input), std::move(auxiliary_input)); +} + +} // libsnark + +#endif // R1CS_EXAMPLES_TCC diff --git a/privacy/zsl/zsl/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp b/privacy/zsl/zsl/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp new file mode 100644 index 0000000..ca3acb3 --- /dev/null +++ b/privacy/zsl/zsl/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp @@ -0,0 +1,153 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for: + - a R1CS constraint, + - a R1CS variable assignment, and + - a R1CS constraint system. + + Above, R1CS stands for "Rank-1 Constraint System". + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_HPP_ +#define R1CS_HPP_ + +#include +#include +#include +#include +#include + +#include "relations/variable.hpp" + +namespace libsnark { + +/************************* R1CS constraint ***********************************/ + +template +class r1cs_constraint; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_constraint &c); + +template +std::istream& operator>>(std::istream &in, r1cs_constraint &c); + +/** + * A R1CS constraint is a formal expression of the form + * + * < A , X > * < B , X > = < C , X > , + * + * where X = (x_0,x_1,...,x_m) is a vector of formal variables and A,B,C each + * consist of 1+m elements in . + * + * A R1CS constraint is used to construct a R1CS constraint system (see below). + */ +template +class r1cs_constraint { +public: + + linear_combination a, b, c; + + r1cs_constraint() {}; + r1cs_constraint(const linear_combination &a, + const linear_combination &b, + const linear_combination &c); + + r1cs_constraint(const std::initializer_list > &A, + const std::initializer_list > &B, + const std::initializer_list > &C); + + bool operator==(const r1cs_constraint &other) const; + + friend std::ostream& operator<< (std::ostream &out, const r1cs_constraint &c); + friend std::istream& operator>> (std::istream &in, r1cs_constraint &c); +}; + +/************************* R1CS variable assignment **************************/ + +/** + * A R1CS variable assignment is a vector of elements that represents + * a candidate solution to a R1CS constraint system (see below). + */ + +/* TODO: specify that it does *NOT* include the constant 1 */ +template +using r1cs_primary_input = std::vector; + +template +using r1cs_auxiliary_input = std::vector; + +template +using r1cs_variable_assignment = std::vector; /* note the changed name! (TODO: remove this comment after primary_input transition is complete) */ + +/************************* R1CS constraint system ****************************/ + +template +class r1cs_constraint_system; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_constraint_system &cs); + +template +std::istream& operator>>(std::istream &in, r1cs_constraint_system &cs); + +/** + * A system of R1CS constraints looks like + * + * { < A_k , X > * < B_k , X > = < C_k , X > }_{k=1}^{n} . + * + * In other words, the system is satisfied if and only if there exist a + * USCS variable assignment for which each R1CS constraint is satisfied. + * + * NOTE: + * The 0-th variable (i.e., "x_{0}") always represents the constant 1. + * Thus, the 0-th variable is not included in num_variables. + */ +template +class r1cs_constraint_system { +public: + size_t primary_input_size; + size_t auxiliary_input_size; + + std::vector > constraints; + + r1cs_constraint_system() : primary_input_size(0), auxiliary_input_size(0) {} + + size_t num_inputs() const; + size_t num_variables() const; + size_t num_constraints() const; + +#ifdef DEBUG + std::map constraint_annotations; + std::map variable_annotations; +#endif + + bool is_valid() const; + bool is_satisfied(const r1cs_primary_input &primary_input, + const r1cs_auxiliary_input &auxiliary_input) const; + + void add_constraint(const r1cs_constraint &c); + void add_constraint(const r1cs_constraint &c, const std::string &annotation); + + void swap_AB_if_beneficial(); + + bool operator==(const r1cs_constraint_system &other) const; + + friend std::ostream& operator<< (std::ostream &out, const r1cs_constraint_system &cs); + friend std::istream& operator>> (std::istream &in, r1cs_constraint_system &cs); + + void report_linear_constraint_statistics() const; +}; + + +} // libsnark + +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.tcc" + +#endif // R1CS_HPP_ diff --git a/privacy/zsl/zsl/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc b/privacy/zsl/zsl/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc new file mode 100644 index 0000000..0faa56a --- /dev/null +++ b/privacy/zsl/zsl/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc @@ -0,0 +1,310 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for: + - a R1CS constraint, + - a R1CS variable assignment, and + - a R1CS constraint system. + + See r1cs.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_TCC_ +#define R1CS_TCC_ + +#include +#include +#include +#include "common/utils.hpp" +#include "common/profiling.hpp" +#include "algebra/fields/bigint.hpp" + +namespace libsnark { + +template +r1cs_constraint::r1cs_constraint(const linear_combination &a, + const linear_combination &b, + const linear_combination &c) : + a(a), b(b), c(c) +{ +} + +template +r1cs_constraint::r1cs_constraint(const std::initializer_list > &A, + const std::initializer_list > &B, + const std::initializer_list > &C) +{ + for (auto lc_A : A) + { + a.terms.insert(a.terms.end(), lc_A.terms.begin(), lc_A.terms.end()); + } + for (auto lc_B : B) + { + b.terms.insert(b.terms.end(), lc_B.terms.begin(), lc_B.terms.end()); + } + for (auto lc_C : C) + { + c.terms.insert(c.terms.end(), lc_C.terms.begin(), lc_C.terms.end()); + } +} + +template +bool r1cs_constraint::operator==(const r1cs_constraint &other) const +{ + return (this->a == other.a && + this->b == other.b && + this->c == other.c); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_constraint &c) +{ + out << c.a; + out << c.b; + out << c.c; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_constraint &c) +{ + in >> c.a; + in >> c.b; + in >> c.c; + + return in; +} + +template +size_t r1cs_constraint_system::num_inputs() const +{ + return primary_input_size; +} + +template +size_t r1cs_constraint_system::num_variables() const +{ + return primary_input_size + auxiliary_input_size; +} + + +template +size_t r1cs_constraint_system::num_constraints() const +{ + return constraints.size(); +} + +template +bool r1cs_constraint_system::is_valid() const +{ + if (this->num_inputs() > this->num_variables()) return false; + + for (size_t c = 0; c < constraints.size(); ++c) + { + if (!(constraints[c].a.is_valid(this->num_variables()) && + constraints[c].b.is_valid(this->num_variables()) && + constraints[c].c.is_valid(this->num_variables()))) + { + return false; + } + } + + return true; +} + +template +void dump_r1cs_constraint(const r1cs_constraint &constraint, + const r1cs_variable_assignment &full_variable_assignment, + const std::map &variable_annotations) +{ + printf("terms for a:\n"); constraint.a.print_with_assignment(full_variable_assignment, variable_annotations); + printf("terms for b:\n"); constraint.b.print_with_assignment(full_variable_assignment, variable_annotations); + printf("terms for c:\n"); constraint.c.print_with_assignment(full_variable_assignment, variable_annotations); +} + +template +bool r1cs_constraint_system::is_satisfied(const r1cs_primary_input &primary_input, + const r1cs_auxiliary_input &auxiliary_input) const +{ + assert(primary_input.size() == num_inputs()); + assert(primary_input.size() + auxiliary_input.size() == num_variables()); + + r1cs_variable_assignment full_variable_assignment = primary_input; + full_variable_assignment.insert(full_variable_assignment.end(), auxiliary_input.begin(), auxiliary_input.end()); + + for (size_t c = 0; c < constraints.size(); ++c) + { + const FieldT ares = constraints[c].a.evaluate(full_variable_assignment); + const FieldT bres = constraints[c].b.evaluate(full_variable_assignment); + const FieldT cres = constraints[c].c.evaluate(full_variable_assignment); + + if (!(ares*bres == cres)) + { +#ifdef DEBUG + auto it = constraint_annotations.find(c); + printf("constraint %zu (%s) unsatisfied\n", c, (it == constraint_annotations.end() ? "no annotation" : it->second.c_str())); + printf(" = "); ares.print(); + printf(" = "); bres.print(); + printf(" = "); cres.print(); + printf("constraint was:\n"); + dump_r1cs_constraint(constraints[c], full_variable_assignment, variable_annotations); +#endif // DEBUG + return false; + } + } + + return true; +} + +template +void r1cs_constraint_system::add_constraint(const r1cs_constraint &c) +{ + constraints.emplace_back(c); +} + +template +void r1cs_constraint_system::add_constraint(const r1cs_constraint &c, const std::string &annotation) +{ +#ifdef DEBUG + constraint_annotations[constraints.size()] = annotation; +#endif + constraints.emplace_back(c); +} + +template +void r1cs_constraint_system::swap_AB_if_beneficial() +{ + enter_block("Call to r1cs_constraint_system::swap_AB_if_beneficial"); + + enter_block("Estimate densities"); + bit_vector touched_by_A(this->num_variables() + 1, false), touched_by_B(this->num_variables() + 1, false); + + for (size_t i = 0; i < this->constraints.size(); ++i) + { + for (size_t j = 0; j < this->constraints[i].a.terms.size(); ++j) + { + touched_by_A[this->constraints[i].a.terms[j].index] = true; + } + + for (size_t j = 0; j < this->constraints[i].b.terms.size(); ++j) + { + touched_by_B[this->constraints[i].b.terms[j].index] = true; + } + } + + size_t non_zero_A_count = 0, non_zero_B_count = 0; + for (size_t i = 0; i < this->num_variables() + 1; ++i) + { + non_zero_A_count += touched_by_A[i] ? 1 : 0; + non_zero_B_count += touched_by_B[i] ? 1 : 0; + } + + if (!inhibit_profiling_info) + { + print_indent(); printf("* Non-zero A-count (estimate): %zu\n", non_zero_A_count); + print_indent(); printf("* Non-zero B-count (estimate): %zu\n", non_zero_B_count); + } + leave_block("Estimate densities"); + + if (non_zero_B_count > non_zero_A_count) + { + enter_block("Perform the swap"); + for (size_t i = 0; i < this->constraints.size(); ++i) + { + std::swap(this->constraints[i].a, this->constraints[i].b); + } + leave_block("Perform the swap"); + } + else + { + print_indent(); printf("Swap is not beneficial, not performing\n"); + } + + leave_block("Call to r1cs_constraint_system::swap_AB_if_beneficial"); +} + +template +bool r1cs_constraint_system::operator==(const r1cs_constraint_system &other) const +{ + return (this->constraints == other.constraints && + this->primary_input_size == other.primary_input_size && + this->auxiliary_input_size == other.auxiliary_input_size); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_constraint_system &cs) +{ + out << cs.primary_input_size << "\n"; + out << cs.auxiliary_input_size << "\n"; + + out << cs.num_constraints() << "\n"; + for (const r1cs_constraint& c : cs.constraints) + { + out << c; + } + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_constraint_system &cs) +{ + in >> cs.primary_input_size; + in >> cs.auxiliary_input_size; + + cs.constraints.clear(); + + size_t s; + in >> s; + + char b; + in.read(&b, 1); + + cs.constraints.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + r1cs_constraint c; + in >> c; + cs.constraints.emplace_back(c); + } + + return in; +} + +template +void r1cs_constraint_system::report_linear_constraint_statistics() const +{ +#ifdef DEBUG + for (size_t i = 0; i < constraints.size(); ++i) + { + auto &constr = constraints[i]; + bool a_is_const = true; + for (auto &t : constr.a.terms) + { + a_is_const = a_is_const && (t.index == 0); + } + + bool b_is_const = true; + for (auto &t : constr.b.terms) + { + b_is_const = b_is_const && (t.index == 0); + } + + if (a_is_const || b_is_const) + { + auto it = constraint_annotations.find(i); + printf("%s\n", (it == constraint_annotations.end() ? FORMAT("", "constraint_%zu", i) : it->second).c_str()); + } + } +#endif +} + +} // libsnark +#endif // R1CS_TCC_ diff --git a/privacy/zsl/zsl/relations/constraint_satisfaction_problems/uscs/examples/uscs_examples.hpp b/privacy/zsl/zsl/relations/constraint_satisfaction_problems/uscs/examples/uscs_examples.hpp new file mode 100644 index 0000000..9edebef --- /dev/null +++ b/privacy/zsl/zsl/relations/constraint_satisfaction_problems/uscs/examples/uscs_examples.hpp @@ -0,0 +1,72 @@ +/** @file + + Declaration of interfaces for a USCS example, as well as functions to sample + USCS examples with prescribed parameters (according to some distribution). + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef USCS_EXAMPLES_HPP_ +#define USCS_EXAMPLES_HPP_ + +#include "relations/constraint_satisfaction_problems/uscs/uscs.hpp" + +namespace libsnark { + +/** + * A USCS example comprises a USCS constraint system, USCS input, and USCS witness. + */ +template +struct uscs_example { + uscs_constraint_system constraint_system; + uscs_primary_input primary_input; + uscs_auxiliary_input auxiliary_input; + + uscs_example() = default; + uscs_example(const uscs_example &other) = default; + uscs_example(const uscs_constraint_system &constraint_system, + const uscs_primary_input &primary_input, + const uscs_auxiliary_input &auxiliary_input) : + constraint_system(constraint_system), + primary_input(primary_input), + auxiliary_input(auxiliary_input) + {}; + uscs_example(uscs_constraint_system &&constraint_system, + uscs_primary_input &&primary_input, + uscs_auxiliary_input &&auxiliary_input) : + constraint_system(std::move(constraint_system)), + primary_input(std::move(primary_input)), + auxiliary_input(std::move(auxiliary_input)) + {}; +}; + +/** + * Generate a USCS example such that: + * - the number of constraints of the USCS constraint system is num_constraints; + * - the number of variables of the USCS constraint system is (approximately) num_constraints; + * - the number of inputs of the USCS constraint system is num_inputs; + * - the USCS input consists of ``full'' field elements (typically require the whole log|Field| bits to represent). + */ +template +uscs_example generate_uscs_example_with_field_input(const size_t num_constraints, + const size_t num_inputs); + +/** + * Generate a USCS example such that: + * - the number of constraints of the USCS constraint system is num_constraints; + * - the number of variables of the USCS constraint system is (approximately) num_constraints; + * - the number of inputs of the USCS constraint system is num_inputs; + * - the USCS input consists of binary values (as opposed to ``full'' field elements). + */ +template +uscs_example generate_uscs_example_with_binary_input(const size_t num_constraints, + const size_t num_inputs); + +} // libsnark + +#include "relations/constraint_satisfaction_problems/uscs/examples/uscs_examples.tcc" + +#endif // USCS_EXAMPLES_HPP_ diff --git a/privacy/zsl/zsl/relations/constraint_satisfaction_problems/uscs/examples/uscs_examples.tcc b/privacy/zsl/zsl/relations/constraint_satisfaction_problems/uscs/examples/uscs_examples.tcc new file mode 100644 index 0000000..90f011f --- /dev/null +++ b/privacy/zsl/zsl/relations/constraint_satisfaction_problems/uscs/examples/uscs_examples.tcc @@ -0,0 +1,137 @@ +/** @file + ***************************************************************************** + + Implementation of functions to sample USCS examples with prescribed parameters + (according to some distribution). + + See uscs_examples.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef USCS_EXAMPLES_TCC_ +#define USCS_EXAMPLES_TCC_ + +#include + +#include "common/utils.hpp" + +namespace libsnark { + +template +uscs_example generate_uscs_example_with_field_input(const size_t num_constraints, + const size_t num_inputs) +{ + enter_block("Call to generate_uscs_example_with_field_input"); + + assert(num_inputs >= 1); + assert(num_constraints >= num_inputs); + + uscs_constraint_system cs; + cs.primary_input_size = num_inputs; + cs.auxiliary_input_size = num_constraints - num_inputs; + + uscs_variable_assignment full_variable_assignment; + for (size_t i = 0; i < num_constraints; ++i) + { + full_variable_assignment.emplace_back(FieldT(std::rand())); + } + + for (size_t i = 0; i < num_constraints; ++i) + { + size_t x, y, z; + + do + { + x = std::rand() % num_constraints; + y = std::rand() % num_constraints; + z = std::rand() % num_constraints; + } while (x == z || y == z); + + const FieldT x_coeff = FieldT(std::rand()); + const FieldT y_coeff = FieldT(std::rand()); + const FieldT val = (std::rand() % 2 == 0 ? FieldT::one() : -FieldT::one()); + const FieldT z_coeff = (val - x_coeff * full_variable_assignment[x] - y_coeff * full_variable_assignment[y]) * full_variable_assignment[z].inverse(); + + uscs_constraint constr; + constr.add_term(x+1, x_coeff); + constr.add_term(y+1, y_coeff); + constr.add_term(z+1, z_coeff); + + cs.add_constraint(constr); + } + + /* split variable assignment */ + uscs_primary_input primary_input(full_variable_assignment.begin(), full_variable_assignment.begin() + num_inputs); + uscs_primary_input auxiliary_input(full_variable_assignment.begin() + num_inputs, full_variable_assignment.end()); + + /* sanity checks */ + assert(cs.num_variables() == full_variable_assignment.size()); + assert(cs.num_variables() >= num_inputs); + assert(cs.num_inputs() == num_inputs); + assert(cs.num_constraints() == num_constraints); + assert(cs.is_satisfied(primary_input, auxiliary_input)); + + leave_block("Call to generate_uscs_example_with_field_input"); + + return uscs_example(std::move(cs), std::move(primary_input), std::move(auxiliary_input)); +} + +template +uscs_example generate_uscs_example_with_binary_input(const size_t num_constraints, + const size_t num_inputs) +{ + enter_block("Call to generate_uscs_example_with_binary_input"); + + assert(num_inputs >= 1); + + uscs_constraint_system cs; + cs.primary_input_size = num_inputs; + cs.auxiliary_input_size = num_constraints; + + uscs_variable_assignment full_variable_assignment; + for (size_t i = 0; i < num_inputs; ++i) + { + full_variable_assignment.push_back(FieldT(std::rand() % 2)); + } + + size_t lastvar = num_inputs-1; + for (size_t i = 0; i < num_constraints; ++i) + { + ++lastvar; + + /* chose two random bits and XOR them together */ + const size_t u = (i == 0 ? std::rand() % num_inputs : std::rand() % i); + const size_t v = (i == 0 ? std::rand() % num_inputs : std::rand() % i); + + uscs_constraint constr; + constr.add_term(u+1, 1); + constr.add_term(v+1, 1); + constr.add_term(lastvar+1, 1); + constr.add_term(0,-FieldT::one()); // shift constant term (which is 0) by 1 + + cs.add_constraint(constr); + full_variable_assignment.push_back(full_variable_assignment[u] + full_variable_assignment[v] - full_variable_assignment[u] * full_variable_assignment[v] - full_variable_assignment[u] * full_variable_assignment[v]); + } + + /* split variable assignment */ + uscs_primary_input primary_input(full_variable_assignment.begin(), full_variable_assignment.begin() + num_inputs); + uscs_primary_input auxiliary_input(full_variable_assignment.begin() + num_inputs, full_variable_assignment.end()); + + /* sanity checks */ + assert(cs.num_variables() == full_variable_assignment.size()); + assert(cs.num_variables() >= num_inputs); + assert(cs.num_inputs() == num_inputs); + assert(cs.num_constraints() == num_constraints); + assert(cs.is_satisfied(primary_input, auxiliary_input)); + + leave_block("Call to generate_uscs_example_with_binary_input"); + + return uscs_example(std::move(cs), std::move(primary_input), std::move(auxiliary_input)); +} + +} // libsnark +#endif // USCS_EXAMPLES_TCC diff --git a/privacy/zsl/zsl/relations/constraint_satisfaction_problems/uscs/uscs.hpp b/privacy/zsl/zsl/relations/constraint_satisfaction_problems/uscs/uscs.hpp new file mode 100644 index 0000000..9a189e0 --- /dev/null +++ b/privacy/zsl/zsl/relations/constraint_satisfaction_problems/uscs/uscs.hpp @@ -0,0 +1,124 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for: + - a USCS constraint, + - a USCS variable assignment, and + - a USCS constraint system. + + Above, USCS stands for "Unitary-Square Constraint System". + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef USCS_HPP_ +#define USCS_HPP_ + +#include +#include +#include +#include +#include + +#include "relations/variable.hpp" + +namespace libsnark { + +/************************* USCS constraint ***********************************/ + +/** + * A USCS constraint is a formal expression of the form + * + * \sum_{i=1}^{m} a_i * x_{i} , + * + * where each a_i is in and each x_{i} is a formal variable. + * + * A USCS constraint is used to construct a USCS constraint system (see below). + */ +template +using uscs_constraint = linear_combination; + + +/************************* USCS variable assignment **************************/ + +/** + * A USCS variable assignment is a vector of elements that represents + * a candidate solution to a USCS constraint system (see below). + */ +template +using uscs_primary_input = std::vector; + +template +using uscs_auxiliary_input = std::vector; + +template +using uscs_variable_assignment = std::vector; + + + +/************************* USCS constraint system ****************************/ + +template +class uscs_constraint_system; + +template +std::ostream& operator<<(std::ostream &out, const uscs_constraint_system &cs); + +template +std::istream& operator>>(std::istream &in, uscs_constraint_system &cs); + +/** + * A system of USCS constraints looks like + * + * { ( \sum_{i=1}^{m_k} a_{k,i} * x_{k,i} )^2 = 1 }_{k=1}^{n} . + * + * In other words, the system is satisfied if and only if there exist a + * USCS variable assignment for which each USCS constraint evaluates to -1 or 1. + * + * NOTE: + * The 0-th variable (i.e., "x_{0}") always represents the constant 1. + * Thus, the 0-th variable is not included in num_variables. + */ +template +class uscs_constraint_system { +public: + size_t primary_input_size; + size_t auxiliary_input_size; + + std::vector > constraints; + + uscs_constraint_system() : primary_input_size(0), auxiliary_input_size(0) {}; + + size_t num_inputs() const; + size_t num_variables() const; + size_t num_constraints() const; + +#ifdef DEBUG + std::map constraint_annotations; + std::map variable_annotations; +#endif + + bool is_valid() const; + bool is_satisfied(const uscs_primary_input &primary_input, + const uscs_auxiliary_input &auxiliary_input) const; + + void add_constraint(const uscs_constraint &constraint); + void add_constraint(const uscs_constraint &constraint, const std::string &annotation); + + bool operator==(const uscs_constraint_system &other) const; + + friend std::ostream& operator<< (std::ostream &out, const uscs_constraint_system &cs); + friend std::istream& operator>> (std::istream &in, uscs_constraint_system &cs); + + void report_linear_constraint_statistics() const; +}; + + +} // libsnark + +#include "relations/constraint_satisfaction_problems/uscs/uscs.tcc" + +#endif // USCS_HPP_ diff --git a/privacy/zsl/zsl/relations/constraint_satisfaction_problems/uscs/uscs.tcc b/privacy/zsl/zsl/relations/constraint_satisfaction_problems/uscs/uscs.tcc new file mode 100644 index 0000000..e7a8324 --- /dev/null +++ b/privacy/zsl/zsl/relations/constraint_satisfaction_problems/uscs/uscs.tcc @@ -0,0 +1,192 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for: + - a USCS constraint, + - a USCS variable assignment, and + - a USCS constraint system. + + See uscs.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef USCS_TCC_ +#define USCS_TCC_ + +#include +#include +#include +#include "common/utils.hpp" +#include "common/profiling.hpp" +#include "algebra/fields/bigint.hpp" + +namespace libsnark { + +template +size_t uscs_constraint_system::num_inputs() const +{ + return primary_input_size; +} + +template +size_t uscs_constraint_system::num_variables() const +{ + return primary_input_size + auxiliary_input_size; +} + + +template +size_t uscs_constraint_system::num_constraints() const +{ + return constraints.size(); +} + +template +bool uscs_constraint_system::is_valid() const +{ + if (this->num_inputs() > this->num_variables()) return false; + + for (size_t c = 0; c < constraints.size(); ++c) + { + if (!valid_vector(constraints[c], this->num_variables())) + { + return false; + } + } + + return true; +} + +template +void dump_uscs_constraint(const uscs_constraint &constraint, + const uscs_variable_assignment &full_variable_assignment, + const std::map &variable_annotations) +{ + printf("terms:\n"); + constraint.print_with_assignment(full_variable_assignment, variable_annotations); +} + +template +bool uscs_constraint_system::is_satisfied(const uscs_primary_input &primary_input, + const uscs_auxiliary_input &auxiliary_input) const +{ + assert(primary_input.size() == num_inputs()); + assert(primary_input.size() + auxiliary_input.size() == num_variables()); + + uscs_variable_assignment full_variable_assignment = primary_input; + full_variable_assignment.insert(full_variable_assignment.end(), auxiliary_input.begin(), auxiliary_input.end()); + + for (size_t c = 0; c < constraints.size(); ++c) + { + FieldT res = constraints[c].evaluate(full_variable_assignment); + if (!(res.squared() == FieldT::one())) + { +#ifdef DEBUG + auto it = constraint_annotations.find(c); + printf("constraint %zu (%s) unsatisfied\n", c, (it == constraint_annotations.end() ? "no annotation" : it->second.c_str())); + printf(" = "); res.print(); + printf("constraint was:\n"); + dump_uscs_constraint(constraints[c], full_variable_assignment, variable_annotations); +#endif // DEBUG + return false; + } + } + + return true; +} + +template +void uscs_constraint_system::add_constraint(const uscs_constraint &c) +{ + constraints.emplace_back(c); +} + +template +void uscs_constraint_system::add_constraint(const uscs_constraint &c, const std::string &annotation) +{ +#ifdef DEBUG + constraint_annotations[constraints.size()] = annotation; +#else + UNUSED(annotation); +#endif + constraints.emplace_back(c); +} + +template +bool uscs_constraint_system::operator==(const uscs_constraint_system &other) const +{ + return (this->constraints == other.constraints && + this->primary_input_size == other.primary_input_size && + this->auxiliary_input_size == other.auxiliary_input_size); +} + +template +std::ostream& operator<<(std::ostream &out, const uscs_constraint_system &cs) +{ + out << cs.primary_input_size << "\n"; + out << cs.auxiliary_input_size << "\n"; + + out << cs.num_constraints() << "\n"; + for (const uscs_constraint& c : cs.constraints) + { + out << c; + } + + return out; +} + +template +std::istream& operator>>(std::istream &in, uscs_constraint_system &cs) +{ + in >> cs.primary_input_size; + in >> cs.auxiliary_input_size; + + cs.constraints.clear(); + + size_t s; + in >> s; + + char b; + in.read(&b, 1); + + cs.constraints.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + uscs_constraint c; + in >> c; + cs.constraints.emplace_back(c); + } + + return in; +} + +template +void uscs_constraint_system::report_linear_constraint_statistics() const +{ +#ifdef DEBUG + for (size_t i = 0; i < constraints.size(); ++i) + { + auto &constr = constraints[i]; + bool a_is_const = true; + for (auto &t : constr.terms) + { + a_is_const = a_is_const && (t.index == 0); + } + + if (a_is_const) + { + auto it = constraint_annotations.find(i); + printf("%s\n", (it == constraint_annotations.end() ? FORMAT("", "constraint_%zu", i) : it->second).c_str()); + } + } +#endif +} + +} // libsnark + +#endif // USCS_TCC_ diff --git a/privacy/zsl/zsl/relations/ram_computations/memory/delegated_ra_memory.hpp b/privacy/zsl/zsl/relations/ram_computations/memory/delegated_ra_memory.hpp new file mode 100644 index 0000000..0a17c3a --- /dev/null +++ b/privacy/zsl/zsl/relations/ram_computations/memory/delegated_ra_memory.hpp @@ -0,0 +1,50 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a delegated random-access memory. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef DELEGATED_RA_MEMORY_HPP_ +#define DELEGATED_RA_MEMORY_HPP_ + +#include +#include +#include + +#include "common/data_structures/merkle_tree.hpp" +#include "relations/ram_computations/memory/memory_interface.hpp" + +namespace libsnark { + +template +class delegated_ra_memory : public memory_interface { +private: + bit_vector int_to_tree_elem(const size_t i) const; + size_t int_from_tree_elem(const bit_vector &v) const; + + std::unique_ptr > contents; + +public: + delegated_ra_memory(const size_t num_addresses, const size_t value_size); + delegated_ra_memory(const size_t num_addresses, const size_t value_size, const std::vector &contents_as_vector); + delegated_ra_memory(const size_t num_addresses, const size_t value_size, const memory_contents &contents_as_map); + + size_t get_value(const size_t address) const; + void set_value(const size_t address, const size_t value); + + typename HashT::hash_value_type get_root() const; + typename HashT::merkle_authentication_path_type get_path(const size_t address) const; + + void dump() const; +}; + +} // libsnark + +#include "relations/ram_computations/memory/delegated_ra_memory.tcc" + +#endif // DELEGATED_RA_MEMORY_HPP_ diff --git a/privacy/zsl/zsl/relations/ram_computations/memory/delegated_ra_memory.tcc b/privacy/zsl/zsl/relations/ram_computations/memory/delegated_ra_memory.tcc new file mode 100644 index 0000000..b29b284 --- /dev/null +++ b/privacy/zsl/zsl/relations/ram_computations/memory/delegated_ra_memory.tcc @@ -0,0 +1,114 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a delegated random-access memory. + + See delegated_ra_memory.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef DELEGATED_RA_MEMORY_TCC +#define DELEGATED_RA_MEMORY_TCC + +#include + +#include "common/profiling.hpp" +#include "common/utils.hpp" + +namespace libsnark { + +template +bit_vector delegated_ra_memory::int_to_tree_elem(const size_t i) const +{ + bit_vector v(value_size, false); + for (size_t k = 0; k < value_size; ++k) + { + v[k] = ((i & (1ul << k)) != 0); + } + return v; +} + +template +size_t delegated_ra_memory::int_from_tree_elem(const bit_vector &v) const +{ + size_t result = 0; + for (size_t i = 0; i < value_size; ++i) + { + result |= (v[i] ? 1ul : 0ul) << i; + } + + return result; +} + +template +delegated_ra_memory::delegated_ra_memory(const size_t num_addresses, + const size_t value_size) : + memory_interface(num_addresses, value_size) +{ + contents.reset(new merkle_tree(log2(num_addresses), value_size)); +} + +template +delegated_ra_memory::delegated_ra_memory(const size_t num_addresses, + const size_t value_size, + const std::vector &contents_as_vector) : + memory_interface(num_addresses, value_size) +{ + std::vector contents_as_bit_vector_vector(contents.size()); + std::transform(contents_as_vector.begin(), contents_as_vector.end(), contents_as_bit_vector_vector, [this](size_t value) { return int_to_tree_elem(value); }); + contents.reset(new merkle_tree(log2(num_addresses), value_size, contents_as_bit_vector_vector)); +} + +template +delegated_ra_memory::delegated_ra_memory(const size_t num_addresses, + const size_t value_size, + const std::map &contents_as_map) : + memory_interface(num_addresses, value_size) +{ + std::map contents_as_bit_vector_map; + for (auto &it : contents_as_map) + { + contents_as_bit_vector_map[it.first] = int_to_tree_elem(it.second); + } + + contents.reset(new merkle_tree(log2(num_addresses), value_size, contents_as_bit_vector_map)); +} + +template +size_t delegated_ra_memory::get_value(const size_t address) const +{ + return int_from_tree_elem(contents->get_value(address)); +} + +template +void delegated_ra_memory::set_value(const size_t address, + const size_t value) +{ + contents->set_value(address, int_to_tree_elem(value)); +} + +template +typename HashT::hash_value_type delegated_ra_memory::get_root() const +{ + return contents->get_root(); +} + +template +typename HashT::merkle_authentication_path_type delegated_ra_memory::get_path(const size_t address) const +{ + return contents->get_path(address); +} + +template +void delegated_ra_memory::dump() const +{ + contents->dump(); +} + +} // libsnark + +#endif // DELEGATED_RA_MEMORY_TCC diff --git a/privacy/zsl/zsl/relations/ram_computations/memory/examples/memory_contents_examples.cpp b/privacy/zsl/zsl/relations/ram_computations/memory/examples/memory_contents_examples.cpp new file mode 100644 index 0000000..336958e --- /dev/null +++ b/privacy/zsl/zsl/relations/ram_computations/memory/examples/memory_contents_examples.cpp @@ -0,0 +1,67 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for functions to sample examples of memory contents. + + See memory_contents_examples.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "relations/ram_computations/memory/examples/memory_contents_examples.hpp" + +#include +#include +#include + +namespace libsnark { + +memory_contents block_memory_contents(const size_t num_addresses, + const size_t value_size, + const size_t block1_size, + const size_t block2_size) +{ + const size_t max_unit = 1ul< unfilled; + for (size_t i = 0; i < num_addresses; ++i) + { + unfilled.insert(i); + } + + memory_contents result; + for (size_t i = 0; i < num_filled; ++i) + { + auto it = unfilled.begin(); + std::advance(it, std::rand() % unfilled.size()); + result[*it] = std::rand() % max_unit; + unfilled.erase(it); + } + + return result; +} + +} // libsnark diff --git a/privacy/zsl/zsl/relations/ram_computations/memory/examples/memory_contents_examples.d b/privacy/zsl/zsl/relations/ram_computations/memory/examples/memory_contents_examples.d new file mode 100644 index 0000000..7217415 --- /dev/null +++ b/privacy/zsl/zsl/relations/ram_computations/memory/examples/memory_contents_examples.d @@ -0,0 +1,4 @@ +src/relations/ram_computations/memory/examples/memory_contents_examples.o: \ + src/relations/ram_computations/memory/examples/memory_contents_examples.cpp \ + src/relations/ram_computations/memory/examples/memory_contents_examples.hpp \ + src/relations/ram_computations/memory/memory_interface.hpp diff --git a/privacy/zsl/zsl/relations/ram_computations/memory/examples/memory_contents_examples.hpp b/privacy/zsl/zsl/relations/ram_computations/memory/examples/memory_contents_examples.hpp new file mode 100644 index 0000000..6fbffea --- /dev/null +++ b/privacy/zsl/zsl/relations/ram_computations/memory/examples/memory_contents_examples.hpp @@ -0,0 +1,39 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for functions to sample examples of memory contents. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MEMORY_CONTENTS_EXAMPLES_HPP_ +#define MEMORY_CONTENTS_EXAMPLES_HPP_ + +#include "relations/ram_computations/memory/memory_interface.hpp" + +namespace libsnark { + +/** + * Sample memory contents consisting of two blocks of random values; + * the first block is located at the beginning of memory, while + * the second block is located half-way through memory. + */ +memory_contents block_memory_contents(const size_t num_addresses, + const size_t value_size, + const size_t block1_size, + const size_t block2_size); + +/** + * Sample memory contents having a given number of non-zero entries; + * each non-zero entry is a random value at a random address (approximately). + */ +memory_contents random_memory_contents(const size_t num_addresses, + const size_t value_size, + const size_t num_filled); + +} // libsnark + +#endif // MEMORY_CONTENTS_EXAMPLES_HPP_ diff --git a/privacy/zsl/zsl/relations/ram_computations/memory/memory_interface.hpp b/privacy/zsl/zsl/relations/ram_computations/memory/memory_interface.hpp new file mode 100644 index 0000000..b20281a --- /dev/null +++ b/privacy/zsl/zsl/relations/ram_computations/memory/memory_interface.hpp @@ -0,0 +1,54 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a memory interface. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MEMORY_INTERFACE_HPP_ +#define MEMORY_INTERFACE_HPP_ + +#include +#include +#include + +namespace libsnark { + +/** + * A function from addresses to values that represents a memory's contents. + */ +typedef std::map memory_contents; + +/** + * A memory interface is a virtual class for specifying and maintining a memory. + * + * A memory is parameterized by two quantities: + * - num_addresses (which specifies the number of addresses); and + * - value_size (which specifies the number of bits stored at each address). + * + * The methods get_val and set_val can be used to load and store values. + */ +class memory_interface { +public: + + size_t num_addresses; + size_t value_size; + + memory_interface(const size_t num_addresses, const size_t value_size) : + num_addresses(num_addresses), + value_size(value_size) + {} + memory_interface(const size_t num_addresses, const size_t value_size, const std::vector &contents_as_vector); + memory_interface(const size_t num_addresses, const size_t value_size, const memory_contents &contents); + + virtual size_t get_value(const size_t address) const = 0; + virtual void set_value(const size_t address, const size_t value) = 0; +}; + +} // libsnark + +#endif // MEMORY_INTERFACE_HPP_ diff --git a/privacy/zsl/zsl/relations/ram_computations/memory/memory_store_trace.cpp b/privacy/zsl/zsl/relations/ram_computations/memory/memory_store_trace.cpp new file mode 100644 index 0000000..e115962 --- /dev/null +++ b/privacy/zsl/zsl/relations/ram_computations/memory/memory_store_trace.cpp @@ -0,0 +1,50 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a memory store trace. + + See memory_store_trace.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "relations/ram_computations/memory/memory_store_trace.hpp" + +namespace libsnark { + +memory_store_trace::memory_store_trace() +{ +} + +address_and_value memory_store_trace::get_trace_entry(const size_t timestamp) const +{ + auto it = entries.find(timestamp); + return (it != entries.end() ? it->second : std::make_pair(0, 0)); +} + +std::map memory_store_trace::get_all_trace_entries() const +{ + return entries; +} + +void memory_store_trace::set_trace_entry(const size_t timestamp, const address_and_value &av) +{ + entries[timestamp] = av; +} + +memory_contents memory_store_trace::as_memory_contents() const +{ + memory_contents result; + + for (auto &ts_and_addrval : entries) + { + result[ts_and_addrval.second.first] = ts_and_addrval.second.second; + } + + return result; +} + +} // libsnark diff --git a/privacy/zsl/zsl/relations/ram_computations/memory/memory_store_trace.d b/privacy/zsl/zsl/relations/ram_computations/memory/memory_store_trace.d new file mode 100644 index 0000000..3c22f32 --- /dev/null +++ b/privacy/zsl/zsl/relations/ram_computations/memory/memory_store_trace.d @@ -0,0 +1,4 @@ +src/relations/ram_computations/memory/memory_store_trace.o: \ + src/relations/ram_computations/memory/memory_store_trace.cpp \ + src/relations/ram_computations/memory/memory_store_trace.hpp \ + src/relations/ram_computations/memory/memory_interface.hpp diff --git a/privacy/zsl/zsl/relations/ram_computations/memory/memory_store_trace.hpp b/privacy/zsl/zsl/relations/ram_computations/memory/memory_store_trace.hpp new file mode 100644 index 0000000..dd88f35 --- /dev/null +++ b/privacy/zsl/zsl/relations/ram_computations/memory/memory_store_trace.hpp @@ -0,0 +1,43 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a memory store trace. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MEMORY_STORE_TRACE_HPP_ +#define MEMORY_STORE_TRACE_HPP_ + +#include "relations/ram_computations/memory/memory_interface.hpp" + +namespace libsnark { + +/** + * A pair consisting of an address and a value. + * It represents a memory store. + */ +typedef std::pair address_and_value; + +/** + * A list in which each component consists of a timestamp and a memory store. + */ +class memory_store_trace { +private: + std::map entries; + +public: + memory_store_trace(); + address_and_value get_trace_entry(const size_t timestamp) const; + std::map get_all_trace_entries() const; + void set_trace_entry(const size_t timestamp, const address_and_value &av); + + memory_contents as_memory_contents() const; +}; + +} // libsnark + +#endif // MEMORY_STORE_TRACE_HPP_ diff --git a/privacy/zsl/zsl/relations/ram_computations/memory/ra_memory.cpp b/privacy/zsl/zsl/relations/ram_computations/memory/ra_memory.cpp new file mode 100644 index 0000000..d16ddcd --- /dev/null +++ b/privacy/zsl/zsl/relations/ram_computations/memory/ra_memory.cpp @@ -0,0 +1,57 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a random-access memory. + + See ra_memory.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include + +#include "relations/ram_computations/memory/ra_memory.hpp" + +namespace libsnark { + +ra_memory::ra_memory(const size_t num_addresses, const size_t value_size) : + memory_interface(num_addresses, value_size) +{ +} + +ra_memory::ra_memory(const size_t num_addresses, + const size_t value_size, + const std::vector &contents_as_vector) : + memory_interface(num_addresses, value_size) +{ + /* copy std::vector into std::map */ + for (size_t i = 0; i < contents_as_vector.size(); ++i) + { + contents[i] = contents_as_vector[i]; + } +} + + +ra_memory::ra_memory(const size_t num_addresses, + const size_t value_size, + const memory_contents &contents) : + memory_interface(num_addresses, value_size), contents(contents) +{ +} + +size_t ra_memory::get_value(const size_t address) const +{ + assert(address < num_addresses); + auto it = contents.find(address); + return (it == contents.end() ? 0 : it->second); +} + +void ra_memory::set_value(const size_t address, const size_t value) +{ + contents[address] = value; +} + +} // libsnark diff --git a/privacy/zsl/zsl/relations/ram_computations/memory/ra_memory.d b/privacy/zsl/zsl/relations/ram_computations/memory/ra_memory.d new file mode 100644 index 0000000..716a13b --- /dev/null +++ b/privacy/zsl/zsl/relations/ram_computations/memory/ra_memory.d @@ -0,0 +1,4 @@ +src/relations/ram_computations/memory/ra_memory.o: \ + src/relations/ram_computations/memory/ra_memory.cpp \ + src/relations/ram_computations/memory/ra_memory.hpp \ + src/relations/ram_computations/memory/memory_interface.hpp diff --git a/privacy/zsl/zsl/relations/ram_computations/memory/ra_memory.hpp b/privacy/zsl/zsl/relations/ram_computations/memory/ra_memory.hpp new file mode 100644 index 0000000..21abd6e --- /dev/null +++ b/privacy/zsl/zsl/relations/ram_computations/memory/ra_memory.hpp @@ -0,0 +1,38 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a random-access memory. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RA_MEMORY_HPP_ +#define RA_MEMORY_HPP_ + +#include "relations/ram_computations/memory/memory_interface.hpp" + +namespace libsnark { + +/** + * A random-access memory maintains the memory's contents via a map (from addresses to values). + */ +class ra_memory : public memory_interface { +public: + + memory_contents contents; + + ra_memory(const size_t num_addresses, const size_t value_size); + ra_memory(const size_t num_addresses, const size_t value_size, const std::vector &contents_as_vector); + ra_memory(const size_t num_addresses, const size_t value_size, const memory_contents &contents); + + size_t get_value(const size_t address) const; + void set_value(const size_t address, const size_t value); + +}; + +} // libsnark + +#endif // RA_MEMORY_HPP_ diff --git a/privacy/zsl/zsl/relations/ram_computations/rams/examples/ram_examples.hpp b/privacy/zsl/zsl/relations/ram_computations/rams/examples/ram_examples.hpp new file mode 100644 index 0000000..93c9bf6 --- /dev/null +++ b/privacy/zsl/zsl/relations/ram_computations/rams/examples/ram_examples.hpp @@ -0,0 +1,45 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a RAM example, as well as functions to sample + RAM examples with prescribed parameters (according to some distribution). + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_EXAMPLES_HPP_ +#define RAM_EXAMPLES_HPP_ + +#include "relations/ram_computations/rams/ram_params.hpp" + +namespace libsnark { + +template +struct ram_example { + ram_architecture_params ap; + size_t boot_trace_size_bound; + size_t time_bound; + ram_boot_trace boot_trace; + ram_input_tape auxiliary_input; +}; + +/** + * For now: only specialized to TinyRAM + */ +template +ram_example gen_ram_example_simple(const ram_architecture_params &ap, const size_t boot_trace_size_bound, const size_t time_bound, const bool satisfiable=true); + +/** + * For now: only specialized to TinyRAM + */ +template +ram_example gen_ram_example_complex(const ram_architecture_params &ap, const size_t boot_trace_size_bound, const size_t time_bound, const bool satisfiable=true); + +} // libsnark + +#include "relations/ram_computations/rams/examples/ram_examples.tcc" + +#endif // RAM_EXAMPLES_HPP_ diff --git a/privacy/zsl/zsl/relations/ram_computations/rams/examples/ram_examples.tcc b/privacy/zsl/zsl/relations/ram_computations/rams/examples/ram_examples.tcc new file mode 100644 index 0000000..c58c248 --- /dev/null +++ b/privacy/zsl/zsl/relations/ram_computations/rams/examples/ram_examples.tcc @@ -0,0 +1,121 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a RAM example, as well as functions to sample + RAM examples with prescribed parameters (according to some distribution). + + See ram_examples.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_EXAMPLES_TCC_ +#define RAM_EXAMPLES_TCC_ + +#include "relations/ram_computations/rams/tinyram/tinyram_aux.hpp" + +namespace libsnark { + +template +ram_example gen_ram_example_simple(const ram_architecture_params &ap, const size_t boot_trace_size_bound, const size_t time_bound, const bool satisfiable) +{ + enter_block("Call to gen_ram_example_simple"); + + const size_t program_size = boot_trace_size_bound / 2; + const size_t input_size = boot_trace_size_bound - program_size; + + ram_example result; + + result.ap = ap; + result.boot_trace_size_bound = boot_trace_size_bound; + result.time_bound = time_bound; + + tinyram_program prelude; prelude.instructions = generate_tinyram_prelude(ap); + + size_t boot_pos = 0; + for (size_t i = 0; i < prelude.instructions.size(); ++i) + { + result.boot_trace.set_trace_entry(boot_pos++, std::make_pair(i, prelude.instructions[i].as_dword(ap))); + } + + result.boot_trace[boot_pos] = std::make_pair(boot_pos++, tinyram_instruction(tinyram_opcode_ANSWER, true, 0, 0, satisfiable ? 0 : 1).as_dword(ap)); /* answer 0/1 depending on satisfiability */ + + while (boot_pos < program_size) + { + result.boot_trace.set_trace_entry(boot_pos++, random_tinyram_instruction(ap).as_dword(ap)); + } + + for (size_t i = 0; i < input_size; ++i) + { + result.boot_trace.set_trace_entry(boot_pos++, std::make_pair((1ul<<(ap.dwaddr_len()-1)) + i, std::rand() % (1ul<<(2*ap.w)))); + } + + assert(boot_pos == boot_trace_size_bound); + + leave_block("Call to gen_ram_example_simple"); + return result; +} + +template +ram_example gen_ram_example_complex(const ram_architecture_params &ap, const size_t boot_trace_size_bound, const size_t time_bound, const bool satisfiable) +{ + enter_block("Call to gen_ram_example_complex"); + + const size_t program_size = boot_trace_size_bound / 2; + const size_t input_size = boot_trace_size_bound - program_size; + + assert(2*ap.w/8*program_size < 1ul<<(ap.w-1)); + assert(ap.w/8*input_size < 1ul<<(ap.w-1)); + + ram_example result; + + result.ap = ap; + result.boot_trace_size_bound = boot_trace_size_bound; + result.time_bound = time_bound; + + tinyram_program prelude; prelude.instructions = generate_tinyram_prelude(ap); + + size_t boot_pos = 0; + for (size_t i = 0; i < prelude.instructions.size(); ++i) + { + result.boot_trace.set_trace_entry(boot_pos++, std::make_pair(i, prelude.instructions[i].as_dword(ap))); + } + + const size_t prelude_len = prelude.instructions.size(); + const size_t instr_addr = (prelude_len+4)*(2*ap.w/8); + const size_t input_addr = (1ul<<(ap.w-1)) + (ap.w/8); // byte address of the first input word + + result.boot_trace.set_trace_entry(boot_pos, std::make_pair(boot_pos, tinyram_instruction(tinyram_opcode_LOADB, true, 1, 0, instr_addr).as_dword(ap))); + ++boot_pos; + result.boot_trace.set_trace_entry(boot_pos, std::make_pair(boot_pos, tinyram_instruction(tinyram_opcode_LOADW, true, 2, 0, input_addr).as_dword(ap))); + ++boot_pos; + result.boot_trace.set_trace_entry(boot_pos, std::make_pair(boot_pos, tinyram_instruction(tinyram_opcode_SUB, false, 1, 1, 2).as_dword(ap))); + ++boot_pos; + result.boot_trace.set_trace_entry(boot_pos, std::make_pair(boot_pos, tinyram_instruction(tinyram_opcode_STOREB, true, 1, 0, instr_addr).as_dword(ap))); + ++boot_pos; + result.boot_trace.set_trace_entry(boot_pos, std::make_pair(boot_pos, tinyram_instruction(tinyram_opcode_ANSWER, true, 0, 0, 1).as_dword(ap))); + ++boot_pos; + + while (boot_pos < program_size) + { + result.boot_trace.set_trace_entry(boot_pos, std::make_pair(boot_pos, random_tinyram_instruction(ap).as_dword(ap))); + ++boot_pos; + } + + result.boot_trace.set_trace_entry(boot_pos++, std::make_pair(1ul<<(ap.dwaddr_len()-1), satisfiable ? 1ul<w == other.w); +} + +std::ostream& operator<<(std::ostream &out, const fooram_architecture_params &ap) +{ + out << ap.w << "\n"; + return out; +} + +std::istream& operator>>(std::istream &in, fooram_architecture_params &ap) +{ + in >> ap.w; + consume_newline(in); + return in; +} + +} // libsnark + diff --git a/privacy/zsl/zsl/relations/ram_computations/rams/fooram/fooram_aux.d b/privacy/zsl/zsl/relations/ram_computations/rams/fooram/fooram_aux.d new file mode 100644 index 0000000..85c3e93 --- /dev/null +++ b/privacy/zsl/zsl/relations/ram_computations/rams/fooram/fooram_aux.d @@ -0,0 +1,6 @@ +src/relations/ram_computations/rams/fooram/fooram_aux.o: \ + src/relations/ram_computations/rams/fooram/fooram_aux.cpp \ + src/relations/ram_computations/rams/fooram/fooram_aux.hpp \ + src/common/utils.hpp src/common/utils.tcc \ + src/relations/ram_computations/memory/memory_interface.hpp \ + src/common/serialization.hpp src/common/serialization.tcc diff --git a/privacy/zsl/zsl/relations/ram_computations/rams/fooram/fooram_aux.hpp b/privacy/zsl/zsl/relations/ram_computations/rams/fooram/fooram_aux.hpp new file mode 100644 index 0000000..8e16436 --- /dev/null +++ b/privacy/zsl/zsl/relations/ram_computations/rams/fooram/fooram_aux.hpp @@ -0,0 +1,51 @@ +/** @file + ***************************************************************************** + + Declaration of auxiliary functions for FOORAM. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FOORAM_AUX_HPP_ +#define FOORAM_AUX_HPP_ + +#include +#include + +#include "common/utils.hpp" +#include "relations/ram_computations/memory/memory_interface.hpp" + +namespace libsnark { + +typedef std::vector fooram_program; +typedef std::vector fooram_input_tape; +typedef typename std::vector::const_iterator fooram_input_tape_iterator; + +class fooram_architecture_params { +public: + size_t w; + fooram_architecture_params(const size_t w=16); + + size_t num_addresses() const; + size_t address_size() const; + size_t value_size() const; + size_t cpu_state_size() const; + size_t initial_pc_addr() const; + + memory_contents initial_memory_contents(const fooram_program &program, + const fooram_input_tape &primary_input) const; + + bit_vector initial_cpu_state() const; + void print() const; + bool operator==(const fooram_architecture_params &other) const; + + friend std::ostream& operator<<(std::ostream &out, const fooram_architecture_params &ap); + friend std::istream& operator>>(std::istream &in, fooram_architecture_params &ap); +}; + +} // libsnark + +#endif // FOORAM_AUX_HPP_ diff --git a/privacy/zsl/zsl/relations/ram_computations/rams/fooram/fooram_params.hpp b/privacy/zsl/zsl/relations/ram_computations/rams/fooram/fooram_params.hpp new file mode 100644 index 0000000..3a50501 --- /dev/null +++ b/privacy/zsl/zsl/relations/ram_computations/rams/fooram/fooram_params.hpp @@ -0,0 +1,38 @@ +/** @file + ***************************************************************************** + + Declaration of public parameters for FOORAM. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FOORAM_PARAMS_HPP_ +#define FOORAM_PARAMS_HPP_ + +#include "gadgetlib1/gadgets/cpu_checkers/fooram/fooram_cpu_checker.hpp" +#include "relations/ram_computations/rams/fooram/fooram_aux.hpp" +#include "relations/ram_computations/rams/ram_params.hpp" + +namespace libsnark { + +template +class ram_fooram { +public: + typedef FieldT base_field_type; + typedef fooram_protoboard protoboard_type; + typedef fooram_gadget gadget_base_type; + typedef fooram_cpu_checker cpu_checker_type; + typedef fooram_architecture_params architecture_params_type; + + static size_t timestamp_length; +}; + +template +size_t ram_fooram::timestamp_length = 300; + +} // libsnark + +#endif // FOORAM_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/relations/ram_computations/rams/ram_params.hpp b/privacy/zsl/zsl/relations/ram_computations/rams/ram_params.hpp new file mode 100644 index 0000000..18a342b --- /dev/null +++ b/privacy/zsl/zsl/relations/ram_computations/rams/ram_params.hpp @@ -0,0 +1,79 @@ +/** @file + ***************************************************************************** + + Declaration of public-parameter selector for RAMs. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_PARAMS_HPP_ +#define RAM_PARAMS_HPP_ + +#include + +#include "relations/ram_computations/memory/memory_store_trace.hpp" + +namespace libsnark { + +/* + When declaring a new ramT one should do a make it a class that declares typedefs for: + + base_field_type + ram_cpu_checker_type + architecture_params_type + + For ram_to_r1cs reduction currently the following are also necessary: + protoboard_type (e.g. tinyram_protoboard) + gadget_base_type (e.g. tinyram_gadget) + cpu_state_variable_type (must have pb_variable_array all_vars) + + The ramT class must also have a static size_t variable + timestamp_length, which specifies the zk-SNARK reduction timestamp + length. +*/ + +template +using ram_base_field = typename ramT::base_field_type; + +template +using ram_cpu_state = bit_vector; + +template +using ram_boot_trace = memory_store_trace; + +template +using ram_protoboard = typename ramT::protoboard_type; + +template +using ram_gadget_base = typename ramT::gadget_base_type; + +template +using ram_cpu_checker = typename ramT::cpu_checker_type; + +template +using ram_architecture_params = typename ramT::architecture_params_type; + +template +using ram_input_tape = std::vector; + +/* + One should also make the following methods for ram_architecture_params + + (We are not yet making a ram_architecture_params base class, as it + would require base class for ram_program + + TODO: make this base class) + + size_t address_size(); + size_t value_size(); + size_t cpu_state_size(); + size_t initial_pc_addr(); + bit_vector initial_cpu_state(); +*/ + +} // libsnark + +#endif // RAM_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/relations/ram_computations/rams/tinyram/tinyram_aux.cpp b/privacy/zsl/zsl/relations/ram_computations/rams/tinyram/tinyram_aux.cpp new file mode 100644 index 0000000..a205443 --- /dev/null +++ b/privacy/zsl/zsl/relations/ram_computations/rams/tinyram/tinyram_aux.cpp @@ -0,0 +1,371 @@ +/** @file + ***************************************************************************** + + Implementation of auxiliary functions for TinyRAM. + + See tinyram_aux.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include + +#include "common/profiling.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_aux.hpp" +#include "common/utils.hpp" + +namespace libsnark { + +tinyram_instruction tinyram_default_instruction = tinyram_instruction(tinyram_opcode_ANSWER, true, 0, 0, 1); + +std::map tinyram_opcode_names = +{ + { tinyram_opcode_AND, "and" }, + { tinyram_opcode_OR, "or" }, + { tinyram_opcode_XOR, "xor" }, + { tinyram_opcode_NOT, "not" }, + { tinyram_opcode_ADD, "add" }, + { tinyram_opcode_SUB, "sub" }, + { tinyram_opcode_MULL, "mull" }, + { tinyram_opcode_UMULH, "umulh" }, + { tinyram_opcode_SMULH, "smulh" }, + { tinyram_opcode_UDIV, "udiv" }, + { tinyram_opcode_UMOD, "umod" }, + { tinyram_opcode_SHL, "shl" }, + { tinyram_opcode_SHR, "shr" }, + + { tinyram_opcode_CMPE, "cmpe" }, + { tinyram_opcode_CMPA, "cmpa" }, + { tinyram_opcode_CMPAE, "cmpae" }, + { tinyram_opcode_CMPG, "cmpg" }, + { tinyram_opcode_CMPGE, "cmpge" }, + + { tinyram_opcode_MOV, "mov" }, + { tinyram_opcode_CMOV, "cmov" }, + { tinyram_opcode_JMP, "jmp" }, + + { tinyram_opcode_CJMP, "cjmp" }, + { tinyram_opcode_CNJMP, "cnjmp" }, + + { tinyram_opcode_10111, "opcode_10111" }, + { tinyram_opcode_11000, "opcode_11000" }, + { tinyram_opcode_11001, "opcode_11001" }, + { tinyram_opcode_STOREB, "store.b" }, + { tinyram_opcode_LOADB, "load.b" }, + + { tinyram_opcode_STOREW, "store.w" }, + { tinyram_opcode_LOADW, "load.w" }, + { tinyram_opcode_READ, "read" }, + { tinyram_opcode_ANSWER, "answer" } +}; + +std::map opcode_args = +{ + { tinyram_opcode_AND, tinyram_opcode_args_des_arg1_arg2 }, + { tinyram_opcode_OR, tinyram_opcode_args_des_arg1_arg2 }, + { tinyram_opcode_XOR, tinyram_opcode_args_des_arg1_arg2 }, + { tinyram_opcode_NOT, tinyram_opcode_args_des_arg2 }, + { tinyram_opcode_ADD, tinyram_opcode_args_des_arg1_arg2 }, + { tinyram_opcode_SUB, tinyram_opcode_args_des_arg1_arg2 }, + { tinyram_opcode_MULL, tinyram_opcode_args_des_arg1_arg2 }, + { tinyram_opcode_UMULH, tinyram_opcode_args_des_arg1_arg2 }, + { tinyram_opcode_SMULH, tinyram_opcode_args_des_arg1_arg2 }, + { tinyram_opcode_UDIV, tinyram_opcode_args_des_arg1_arg2 }, + { tinyram_opcode_UMOD, tinyram_opcode_args_des_arg1_arg2 }, + { tinyram_opcode_SHL, tinyram_opcode_args_des_arg1_arg2 }, + { tinyram_opcode_SHR, tinyram_opcode_args_des_arg1_arg2 }, + { tinyram_opcode_CMPE, tinyram_opcode_args_arg1_arg2 }, + { tinyram_opcode_CMPA, tinyram_opcode_args_arg1_arg2 }, + { tinyram_opcode_CMPAE, tinyram_opcode_args_arg1_arg2 }, + { tinyram_opcode_CMPG, tinyram_opcode_args_arg1_arg2 }, + { tinyram_opcode_CMPGE, tinyram_opcode_args_arg1_arg2 }, + { tinyram_opcode_MOV, tinyram_opcode_args_des_arg2 }, + { tinyram_opcode_CMOV, tinyram_opcode_args_des_arg2 }, + { tinyram_opcode_JMP, tinyram_opcode_args_arg2 }, + { tinyram_opcode_CJMP, tinyram_opcode_args_arg2 }, + { tinyram_opcode_CNJMP, tinyram_opcode_args_arg2 }, + { tinyram_opcode_10111, tinyram_opcode_args_none }, + { tinyram_opcode_11000, tinyram_opcode_args_none }, + { tinyram_opcode_11001, tinyram_opcode_args_none }, + { tinyram_opcode_STOREB, tinyram_opcode_args_arg2_des }, + { tinyram_opcode_LOADB, tinyram_opcode_args_des_arg2 }, + { tinyram_opcode_STOREW, tinyram_opcode_args_arg2_des }, + { tinyram_opcode_LOADW, tinyram_opcode_args_des_arg2 }, + { tinyram_opcode_READ, tinyram_opcode_args_des_arg2 }, + { tinyram_opcode_ANSWER, tinyram_opcode_args_arg2 } +}; + +std::map opcode_values; + +void ensure_tinyram_opcode_value_map() +{ + if (opcode_values.empty()) + { + for (auto it : tinyram_opcode_names) + { + opcode_values[it.second] = it.first; + } + } +} + +std::vector generate_tinyram_prelude(const tinyram_architecture_params &ap) +{ + std::vector result; + const size_t increment = log2(ap.w)/8; + const size_t mem_start = 1ul<<(ap.w-1); + result.emplace_back(tinyram_instruction(tinyram_opcode_STOREW, true, 0, 0, 0)); // 0: store.w 0, r0 + result.emplace_back(tinyram_instruction(tinyram_opcode_MOV, true, 0, 0, mem_start)); // 1: mov r0, 2^{W-1} + result.emplace_back(tinyram_instruction(tinyram_opcode_READ, true, 1, 0, 0)); // 2: read r1, 0 + result.emplace_back(tinyram_instruction(tinyram_opcode_CJMP, true, 0, 0, 7)); // 3: cjmp 7 + result.emplace_back(tinyram_instruction(tinyram_opcode_ADD, true, 0, 0, increment)); // 4: add r0, r0, INCREMENT + result.emplace_back(tinyram_instruction(tinyram_opcode_STOREW, false, 1, 0, 0)); // 5: store.w r0, r1 + result.emplace_back(tinyram_instruction(tinyram_opcode_JMP, true, 0, 0, 2)); // 6: jmp 2 + result.emplace_back(tinyram_instruction(tinyram_opcode_STOREW, true, 0, 0, mem_start)); // 7: store.w 2^{W-1}, r0 + return result; +} + +size_t tinyram_architecture_params::address_size() const +{ + return dwaddr_len(); +} + +size_t tinyram_architecture_params::value_size() const +{ + return 2*w; +} + +size_t tinyram_architecture_params::cpu_state_size() const +{ + return k * w + 2; /* + flag + tape1_exhausted */ +} + +size_t tinyram_architecture_params::initial_pc_addr() const +{ + /* the initial PC address is memory units for the RAM reduction */ + const size_t initial_pc_addr = generate_tinyram_prelude(*this).size(); + return initial_pc_addr; +} + +bit_vector tinyram_architecture_params::initial_cpu_state() const +{ + bit_vector result(this->cpu_state_size(), false); + return result; +} + +memory_contents tinyram_architecture_params::initial_memory_contents(const tinyram_program &program, + const tinyram_input_tape &primary_input) const +{ + // remember that memory consists of 1ul<(tinyram_opcode_ANSWER)); /* assumption: answer is the last */ +} + +size_t tinyram_architecture_params::reg_arg_width() const +{ + return log2(k); +} + +size_t tinyram_architecture_params::instruction_padding_width() const +{ + return 2 * w - (opcode_width() + 1 + 2 * reg_arg_width() + reg_arg_or_imm_width()); +} + +size_t tinyram_architecture_params::reg_arg_or_imm_width() const +{ + return std::max(w, reg_arg_width()); +} + +size_t tinyram_architecture_params::dwaddr_len() const +{ + return w-(log2(w)-2); +} + +size_t tinyram_architecture_params::subaddr_len() const +{ + return log2(w)-2; +} + +size_t tinyram_architecture_params::bytes_in_word() const +{ + return w/8; +} + +size_t tinyram_architecture_params::instr_size() const +{ + return 2*w; +} + +bool tinyram_architecture_params::operator==(const tinyram_architecture_params &other) const +{ + return (this->w == other.w && + this->k == other.k); +} + +std::ostream& operator<<(std::ostream &out, const tinyram_architecture_params &ap) +{ + out << ap.w << "\n"; + out << ap.k << "\n"; + return out; +} + +std::istream& operator>>(std::istream &in, tinyram_architecture_params &ap) +{ + in >> ap.w; + consume_newline(in); + in >> ap.k; + consume_newline(in); + return in; +} + +tinyram_instruction::tinyram_instruction(const tinyram_opcode &opcode, + const bool arg2_is_imm, + const size_t &desidx, + const size_t &arg1idx, + const size_t &arg2idx_or_imm) : + opcode(opcode), + arg2_is_imm(arg2_is_imm), + desidx(desidx), + arg1idx(arg1idx), + arg2idx_or_imm(arg2idx_or_imm) +{ +} + +size_t tinyram_instruction::as_dword(const tinyram_architecture_params &ap) const +{ + size_t result = static_cast(opcode); + result = (result << 1) | (arg2_is_imm ? 1 : 0); + result = (result << log2(ap.k)) | desidx; + result = (result << log2(ap.k)) | arg1idx; + result = (result << (2*ap.w - ap.opcode_width() - 1 - 2 * log2(ap.k))) | arg2idx_or_imm; + + return result; +} + +void tinyram_architecture_params::print() const +{ + printf("* Number of registers (k): %zu\n", k); + printf("* Word size (w): %zu\n", w); +} + +tinyram_instruction random_tinyram_instruction(const tinyram_architecture_params &ap) +{ + const tinyram_opcode opcode = (tinyram_opcode)(std::rand() % (1ul<> instr) + { + print_indent(); + size_t immflag, des, a1; + long long int a2; + if (preprocessed.good()) + { + preprocessed >> immflag >> des >> a1 >> a2; + a2 = ((1ul<> cell) + { + printf("\t%zu", cell); + result.emplace_back(cell); + } + printf("\n"); + + leave_block("Loading tape"); + return result; +} + +} // libsnark diff --git a/privacy/zsl/zsl/relations/ram_computations/rams/tinyram/tinyram_aux.d b/privacy/zsl/zsl/relations/ram_computations/rams/tinyram/tinyram_aux.d new file mode 100644 index 0000000..cc93a8f --- /dev/null +++ b/privacy/zsl/zsl/relations/ram_computations/rams/tinyram/tinyram_aux.d @@ -0,0 +1,13 @@ +src/relations/ram_computations/rams/tinyram/tinyram_aux.o: \ + src/relations/ram_computations/rams/tinyram/tinyram_aux.cpp \ + src/common/profiling.hpp \ + src/relations/ram_computations/rams/tinyram/tinyram_aux.hpp \ + src/common/utils.hpp src/common/utils.tcc \ + src/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp \ + src/relations/variable.hpp src/relations/variable.tcc \ + src/algebra/fields/bigint.hpp src/common/serialization.hpp \ + src/common/serialization.tcc src/algebra/fields/bigint.tcc \ + src/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc \ + src/relations/ram_computations/memory/memory_interface.hpp \ + src/relations/ram_computations/rams/ram_params.hpp \ + src/relations/ram_computations/memory/memory_store_trace.hpp diff --git a/privacy/zsl/zsl/relations/ram_computations/rams/tinyram/tinyram_aux.hpp b/privacy/zsl/zsl/relations/ram_computations/rams/tinyram/tinyram_aux.hpp new file mode 100644 index 0000000..6f6a79b --- /dev/null +++ b/privacy/zsl/zsl/relations/ram_computations/rams/tinyram/tinyram_aux.hpp @@ -0,0 +1,226 @@ +/** @file + ***************************************************************************** + + Declaration of auxiliary functions for TinyRAM. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TINYRAM_AUX_HPP_ +#define TINYRAM_AUX_HPP_ + +#include +#include +#include + +#include "common/utils.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" +#include "relations/ram_computations/memory/memory_interface.hpp" +#include "relations/ram_computations/rams/ram_params.hpp" + +namespace libsnark { + +enum tinyram_opcode { + tinyram_opcode_AND = 0b00000, + tinyram_opcode_OR = 0b00001, + tinyram_opcode_XOR = 0b00010, + tinyram_opcode_NOT = 0b00011, + tinyram_opcode_ADD = 0b00100, + tinyram_opcode_SUB = 0b00101, + tinyram_opcode_MULL = 0b00110, + tinyram_opcode_UMULH = 0b00111, + tinyram_opcode_SMULH = 0b01000, + tinyram_opcode_UDIV = 0b01001, + tinyram_opcode_UMOD = 0b01010, + tinyram_opcode_SHL = 0b01011, + tinyram_opcode_SHR = 0b01100, + + tinyram_opcode_CMPE = 0b01101, + tinyram_opcode_CMPA = 0b01110, + tinyram_opcode_CMPAE = 0b01111, + tinyram_opcode_CMPG = 0b10000, + tinyram_opcode_CMPGE = 0b10001, + + tinyram_opcode_MOV = 0b10010, + tinyram_opcode_CMOV = 0b10011, + + tinyram_opcode_JMP = 0b10100, + tinyram_opcode_CJMP = 0b10101, + tinyram_opcode_CNJMP = 0b10110, + + tinyram_opcode_10111 = 0b10111, + tinyram_opcode_11000 = 0b11000, + tinyram_opcode_11001 = 0b11001, + + tinyram_opcode_STOREB = 0b11010, + tinyram_opcode_LOADB = 0b11011, + tinyram_opcode_STOREW = 0b11100, + tinyram_opcode_LOADW = 0b11101, + tinyram_opcode_READ = 0b11110, + tinyram_opcode_ANSWER = 0b11111 +}; + +enum tinyram_opcode_args { + tinyram_opcode_args_des_arg1_arg2 = 1, + tinyram_opcode_args_des_arg2 = 2, + tinyram_opcode_args_arg1_arg2 = 3, + tinyram_opcode_args_arg2 = 4, + tinyram_opcode_args_none = 5, + tinyram_opcode_args_arg2_des = 6 +}; + +/** + * Instructions that may change a register or the flag. + * All other instructions leave all registers and the flag intact. + */ +const static int tinyram_opcodes_register[] = { + tinyram_opcode_AND, + tinyram_opcode_OR, + tinyram_opcode_XOR, + tinyram_opcode_NOT, + tinyram_opcode_ADD, + tinyram_opcode_SUB, + tinyram_opcode_MULL, + tinyram_opcode_UMULH, + tinyram_opcode_SMULH, + tinyram_opcode_UDIV, + tinyram_opcode_UMOD, + tinyram_opcode_SHL, + tinyram_opcode_SHR, + + tinyram_opcode_CMPE, + tinyram_opcode_CMPA, + tinyram_opcode_CMPAE, + tinyram_opcode_CMPG, + tinyram_opcode_CMPGE, + + tinyram_opcode_MOV, + tinyram_opcode_CMOV, + + tinyram_opcode_LOADB, + tinyram_opcode_LOADW, + tinyram_opcode_READ +}; + +/** + * Instructions that modify the program counter. + * All other instructions either advance it (+1) or stall (see below). + */ +const static int tinyram_opcodes_control_flow[] = { + tinyram_opcode_JMP, + tinyram_opcode_CJMP, + tinyram_opcode_CNJMP +}; + +/** + * Instructions that make the program counter stall; + * these are "answer" plus all the undefined opcodes. + */ +const static int tinyram_opcodes_stall[] = { + tinyram_opcode_10111, + tinyram_opcode_11000, + tinyram_opcode_11001, + + tinyram_opcode_ANSWER +}; + +typedef size_t reg_count_t; // type for the number of registers +typedef size_t reg_width_t; // type for the width of a register + +extern std::map tinyram_opcode_names; + +extern std::map opcode_values; + +extern std::map opcode_args; + +void ensure_tinyram_opcode_value_map(); + +class tinyram_program; +typedef std::vector tinyram_input_tape; +typedef typename tinyram_input_tape::const_iterator tinyram_input_tape_iterator; + +class tinyram_architecture_params { +public: + reg_width_t w; /* width of a register */ + reg_count_t k; /* number of registers */ + + tinyram_architecture_params() {}; + tinyram_architecture_params(const reg_width_t w, const reg_count_t k) : w(w), k(k) { assert(w == 1ul << log2(w)); }; + + size_t address_size() const; + size_t value_size() const; + size_t cpu_state_size() const; + size_t initial_pc_addr() const; + + bit_vector initial_cpu_state() const; + memory_contents initial_memory_contents(const tinyram_program &program, + const tinyram_input_tape &primary_input) const; + + size_t opcode_width() const; + size_t reg_arg_width() const; + size_t instruction_padding_width() const; + size_t reg_arg_or_imm_width() const; + + size_t dwaddr_len() const; + size_t subaddr_len() const; + + size_t bytes_in_word() const; + + size_t instr_size() const; + + bool operator==(const tinyram_architecture_params &other) const; + + friend std::ostream& operator<<(std::ostream &out, const tinyram_architecture_params &ap); + friend std::istream& operator>>(std::istream &in, tinyram_architecture_params &ap); + + void print() const; +}; + +/* order everywhere is reversed (i.e. MSB comes first), + corresponding to the order in memory */ + +class tinyram_instruction { +public: + tinyram_opcode opcode; + bool arg2_is_imm; + size_t desidx; + size_t arg1idx; + size_t arg2idx_or_imm; + + tinyram_instruction(const tinyram_opcode &opcode, + const bool arg2_is_imm, + const size_t &desidx, + const size_t &arg1idx, + const size_t &arg2idx_or_imm); + + size_t as_dword(const tinyram_architecture_params &ap) const; +}; + +tinyram_instruction random_tinyram_instruction(const tinyram_architecture_params &ap); + +std::vector generate_tinyram_prelude(const tinyram_architecture_params &ap); +extern tinyram_instruction tinyram_default_instruction; + +class tinyram_program { +public: + std::vector instructions; + size_t size() const { return instructions.size(); } + void add_instruction(const tinyram_instruction &instr); +}; + +tinyram_program load_preprocessed_program(const tinyram_architecture_params &ap, + std::istream &preprocessed); + +memory_store_trace tinyram_boot_trace_from_program_and_input(const tinyram_architecture_params &ap, + const size_t boot_trace_size_bound, + const tinyram_program &program, + const tinyram_input_tape &primary_input); + +tinyram_input_tape load_tape(std::istream &tape); + +} // libsnark + +#endif // TINYRAM_AUX_HPP_ diff --git a/privacy/zsl/zsl/relations/ram_computations/rams/tinyram/tinyram_params.hpp b/privacy/zsl/zsl/relations/ram_computations/rams/tinyram/tinyram_params.hpp new file mode 100644 index 0000000..35147b4 --- /dev/null +++ b/privacy/zsl/zsl/relations/ram_computations/rams/tinyram/tinyram_params.hpp @@ -0,0 +1,38 @@ +/** @file + ***************************************************************************** + + Declaration of public parameters for TinyRAM. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TINYRAM_PARAMS_HPP_ +#define TINYRAM_PARAMS_HPP_ + +#include "relations/ram_computations/rams/ram_params.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_aux.hpp" +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/tinyram_cpu_checker.hpp" + +namespace libsnark { + +template +class ram_tinyram { +public: + static size_t timestamp_length; + + typedef FieldT base_field_type; + typedef tinyram_protoboard protoboard_type; + typedef tinyram_gadget gadget_base_type; + typedef tinyram_cpu_checker cpu_checker_type; + typedef tinyram_architecture_params architecture_params_type; +}; + +template +size_t ram_tinyram::timestamp_length = 300; + +} // libsnark + +#endif // TINYRAM_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/relations/variable.hpp b/privacy/zsl/zsl/relations/variable.hpp new file mode 100644 index 0000000..df82ac4 --- /dev/null +++ b/privacy/zsl/zsl/relations/variable.hpp @@ -0,0 +1,213 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for: + - a variable (i.e., x_i), + - a linear term (i.e., a_i * x_i), and + - a linear combination (i.e., sum_i a_i * x_i). + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef VARIABLE_HPP_ +#define VARIABLE_HPP_ + +#include +#include +#include +#include + +namespace libsnark { + +/** + * Mnemonic typedefs. + */ +typedef size_t var_index_t; +typedef long integer_coeff_t; + +/** + * Forward declaration. + */ +template +class linear_term; + +/** + * Forward declaration. + */ +template +class linear_combination; + +/********************************* Variable **********************************/ + +/** + * A variable represents a formal expresison of the form "x_{index}". + */ +template +class variable { +public: + + var_index_t index; + + variable(const var_index_t index = 0) : index(index) {}; + + linear_term operator*(const integer_coeff_t int_coeff) const; + linear_term operator*(const FieldT &field_coeff) const; + + linear_combination operator+(const linear_combination &other) const; + linear_combination operator-(const linear_combination &other) const; + + linear_term operator-() const; + + bool operator==(const variable &other) const; +}; + +template +linear_term operator*(const integer_coeff_t int_coeff, const variable &var); + +template +linear_term operator*(const FieldT &field_coeff, const variable &var); + +template +linear_combination operator+(const integer_coeff_t int_coeff, const variable &var); + +template +linear_combination operator+(const FieldT &field_coeff, const variable &var); + +template +linear_combination operator-(const integer_coeff_t int_coeff, const variable &var); + +template +linear_combination operator-(const FieldT &field_coeff, const variable &var); + + +/****************************** Linear term **********************************/ + +/** + * A linear term represents a formal expression of the form "coeff * x_{index}". + */ +template +class linear_term { +public: + + var_index_t index; + FieldT coeff; + + linear_term() {}; + linear_term(const variable &var); + linear_term(const variable &var, const integer_coeff_t int_coeff); + linear_term(const variable &var, const FieldT &field_coeff); + + linear_term operator*(const integer_coeff_t int_coeff) const; + linear_term operator*(const FieldT &field_coeff) const; + + linear_combination operator+(const linear_combination &other) const; + linear_combination operator-(const linear_combination &other) const; + + linear_term operator-() const; + + bool operator==(const linear_term &other) const; +}; + +template +linear_term operator*(const integer_coeff_t int_coeff, const linear_term <); + +template +linear_term operator*(const FieldT &field_coeff, const linear_term <); + +template +linear_combination operator+(const integer_coeff_t int_coeff, const linear_term <); + +template +linear_combination operator+(const FieldT &field_coeff, const linear_term <); + +template +linear_combination operator-(const integer_coeff_t int_coeff, const linear_term <); + +template +linear_combination operator-(const FieldT &field_coeff, const linear_term <); + + +/***************************** Linear combination ****************************/ + +template +class linear_combination; + +template +std::ostream& operator<<(std::ostream &out, const linear_combination &lc); + +template +std::istream& operator>>(std::istream &in, linear_combination &lc); + +/** + * A linear combination represents a formal expression of the form "sum_i coeff_i * x_{index_i}". + */ +template +class linear_combination { +public: + + std::vector > terms; + + linear_combination() {}; + linear_combination(const integer_coeff_t int_coeff); + linear_combination(const FieldT &field_coeff); + linear_combination(const variable &var); + linear_combination(const linear_term <); + linear_combination(const std::vector > &all_terms); + + /* for supporting range-based for loops over linear_combination */ + typename std::vector >::const_iterator begin() const; + typename std::vector >::const_iterator end() const; + + void add_term(const variable &var); + void add_term(const variable &var, const integer_coeff_t int_coeff); + void add_term(const variable &var, const FieldT &field_coeff); + + void add_term(const linear_term <); + + FieldT evaluate(const std::vector &assignment) const; + + linear_combination operator*(const integer_coeff_t int_coeff) const; + linear_combination operator*(const FieldT &field_coeff) const; + + linear_combination operator+(const linear_combination &other) const; + + linear_combination operator-(const linear_combination &other) const; + linear_combination operator-() const; + + bool operator==(const linear_combination &other) const; + + bool is_valid(const size_t num_variables) const; + + void print(const std::map &variable_annotations = std::map()) const; + void print_with_assignment(const std::vector &full_assignment, const std::map &variable_annotations = std::map()) const; + + friend std::ostream& operator<< (std::ostream &out, const linear_combination &lc); + friend std::istream& operator>> (std::istream &in, linear_combination &lc); +}; + +template +linear_combination operator*(const integer_coeff_t int_coeff, const linear_combination &lc); + +template +linear_combination operator*(const FieldT &field_coeff, const linear_combination &lc); + +template +linear_combination operator+(const integer_coeff_t int_coeff, const linear_combination &lc); + +template +linear_combination operator+(const FieldT &field_coeff, const linear_combination &lc); + +template +linear_combination operator-(const integer_coeff_t int_coeff, const linear_combination &lc); + +template +linear_combination operator-(const FieldT &field_coeff, const linear_combination &lc); + +} // libsnark + +#include "relations/variable.tcc" + +#endif // VARIABLE_HPP_ diff --git a/privacy/zsl/zsl/relations/variable.tcc b/privacy/zsl/zsl/relations/variable.tcc new file mode 100644 index 0000000..4c4cab9 --- /dev/null +++ b/privacy/zsl/zsl/relations/variable.tcc @@ -0,0 +1,512 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for: + - a variable (i.e., x_i), + - a linear term (i.e., a_i * x_i), and + - a linear combination (i.e., sum_i a_i * x_i). + + See variabe.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef VARIABLE_TCC_ +#define VARIABLE_TCC_ + +#include +#include + +#include "algebra/fields/bigint.hpp" + +namespace libsnark { + +template +linear_term variable::operator*(const integer_coeff_t int_coeff) const +{ + return linear_term(*this, int_coeff); +} + +template +linear_term variable::operator*(const FieldT &field_coeff) const +{ + return linear_term(*this, field_coeff); +} + +template +linear_combination variable::operator+(const linear_combination &other) const +{ + linear_combination result; + + result.add_term(*this); + result.terms.insert(result.terms.begin(), other.terms.begin(), other.terms.end()); + + return result; +} + +template +linear_combination variable::operator-(const linear_combination &other) const +{ + return (*this) + (-other); +} + +template +linear_term variable::operator-() const +{ + return linear_term(*this, -FieldT::one()); +} + +template +bool variable::operator==(const variable &other) const +{ + return (this->index == other.index); +} + +template +linear_term operator*(const integer_coeff_t int_coeff, const variable &var) +{ + return linear_term(var, int_coeff); +} + +template +linear_term operator*(const FieldT &field_coeff, const variable &var) +{ + return linear_term(var, field_coeff); +} + +template +linear_combination operator+(const integer_coeff_t int_coeff, const variable &var) +{ + return linear_combination(int_coeff) + var; +} + +template +linear_combination operator+(const FieldT &field_coeff, const variable &var) +{ + return linear_combination(field_coeff) + var; +} + +template +linear_combination operator-(const integer_coeff_t int_coeff, const variable &var) +{ + return linear_combination(int_coeff) - var; +} + +template +linear_combination operator-(const FieldT &field_coeff, const variable &var) +{ + return linear_combination(field_coeff) - var; +} + +template +linear_term::linear_term(const variable &var) : + index(var.index), coeff(FieldT::one()) +{ +} + +template +linear_term::linear_term(const variable &var, const integer_coeff_t int_coeff) : + index(var.index), coeff(FieldT(int_coeff)) +{ +} + +template +linear_term::linear_term(const variable &var, const FieldT &coeff) : + index(var.index), coeff(coeff) +{ +} + +template +linear_term linear_term::operator*(const integer_coeff_t int_coeff) const +{ + return (this->operator*(FieldT(int_coeff))); +} + +template +linear_term linear_term::operator*(const FieldT &field_coeff) const +{ + return linear_term(this->index, field_coeff * this->coeff); +} + +template +linear_combination operator+(const integer_coeff_t int_coeff, const linear_term <) +{ + return linear_combination(int_coeff) + lt; +} + +template +linear_combination operator+(const FieldT &field_coeff, const linear_term <) +{ + return linear_combination(field_coeff) + lt; +} + +template +linear_combination operator-(const integer_coeff_t int_coeff, const linear_term <) +{ + return linear_combination(int_coeff) - lt; +} + +template +linear_combination operator-(const FieldT &field_coeff, const linear_term <) +{ + return linear_combination(field_coeff) - lt; +} + +template +linear_combination linear_term::operator+(const linear_combination &other) const +{ + return linear_combination(*this) + other; +} + +template +linear_combination linear_term::operator-(const linear_combination &other) const +{ + return (*this) + (-other); +} + +template +linear_term linear_term::operator-() const +{ + return linear_term(this->index, -this->coeff); +} + +template +bool linear_term::operator==(const linear_term &other) const +{ + return (this->index == other.index && + this->coeff == other.coeff); +} + +template +linear_term operator*(const integer_coeff_t int_coeff, const linear_term <) +{ + return FieldT(int_coeff) * lt; +} + +template +linear_term operator*(const FieldT &field_coeff, const linear_term <) +{ + return linear_term(lt.index, field_coeff * lt.coeff); +} + +template +linear_combination::linear_combination(const integer_coeff_t int_coeff) +{ + this->add_term(linear_term(0, int_coeff)); +} + +template +linear_combination::linear_combination(const FieldT &field_coeff) +{ + this->add_term(linear_term(0, field_coeff)); +} + +template +linear_combination::linear_combination(const variable &var) +{ + this->add_term(var); +} + +template +linear_combination::linear_combination(const linear_term <) +{ + this->add_term(lt); +} + +template +typename std::vector >::const_iterator linear_combination::begin() const +{ + return terms.begin(); +} + +template +typename std::vector >::const_iterator linear_combination::end() const +{ + return terms.end(); +} + +template +void linear_combination::add_term(const variable &var) +{ + this->terms.emplace_back(linear_term(var.index, FieldT::one())); +} + +template +void linear_combination::add_term(const variable &var, const integer_coeff_t int_coeff) +{ + this->terms.emplace_back(linear_term(var.index, int_coeff)); +} + +template +void linear_combination::add_term(const variable &var, const FieldT &coeff) +{ + this->terms.emplace_back(linear_term(var.index, coeff)); +} + +template +void linear_combination::add_term(const linear_term &other) +{ + this->terms.emplace_back(other); +} + +template +linear_combination linear_combination::operator*(const integer_coeff_t int_coeff) const +{ + return (*this) * FieldT(int_coeff); +} + +template +FieldT linear_combination::evaluate(const std::vector &assignment) const +{ + FieldT acc = FieldT::zero(); + for (auto < : terms) + { + acc += (lt.index == 0 ? FieldT::one() : assignment[lt.index-1]) * lt.coeff; + } + return acc; +} + +template +linear_combination linear_combination::operator*(const FieldT &field_coeff) const +{ + linear_combination result; + result.terms.reserve(this->terms.size()); + for (const linear_term < : this->terms) + { + result.terms.emplace_back(lt * field_coeff); + } + return result; +} + +template +linear_combination linear_combination::operator+(const linear_combination &other) const +{ + linear_combination result; + + auto it1 = this->terms.begin(); + auto it2 = other.terms.begin(); + + /* invariant: it1 and it2 always point to unprocessed items in the corresponding linear combinations */ + while (it1 != this->terms.end() && it2 != other.terms.end()) + { + if (it1->index < it2->index) + { + result.terms.emplace_back(*it1); + ++it1; + } + else if (it1->index > it2->index) + { + result.terms.emplace_back(*it2); + ++it2; + } + else + { + /* it1->index == it2->index */ + result.terms.emplace_back(linear_term(variable(it1->index), it1->coeff + it2->coeff)); + ++it1; + ++it2; + } + } + + if (it1 != this->terms.end()) + { + result.terms.insert(result.terms.end(), it1, this->terms.end()); + } + else + { + result.terms.insert(result.terms.end(), it2, other.terms.end()); + } + + return result; +} + +template +linear_combination linear_combination::operator-(const linear_combination &other) const +{ + return (*this) + (-other); +} + +template +linear_combination linear_combination::operator-() const +{ + return (*this) * (-FieldT::one()); +} + +template +bool linear_combination::operator==(const linear_combination &other) const +{ + return (this->terms == other.terms); +} + +template +bool linear_combination::is_valid(const size_t num_variables) const +{ + /* check that all terms in linear combination are sorted */ + for (size_t i = 1; i < terms.size(); ++i) + { + if (terms[i-1].index >= terms[i].index) + { + return false; + } + } + + /* check that the variables are in proper range. as the variables + are sorted, it suffices to check the last term */ + if ((--terms.end())->index >= num_variables) + { + return false; + } + + return true; +} + +template +void linear_combination::print(const std::map &variable_annotations) const +{ + for (auto < : terms) + { + if (lt.index == 0) + { + printf(" 1 * "); + lt.coeff.print(); + } + else + { + auto it = variable_annotations.find(lt.index); + printf(" x_%zu (%s) * ", lt.index, (it == variable_annotations.end() ? "no annotation" : it->second.c_str())); + lt.coeff.print(); + } + } +} + +template +void linear_combination::print_with_assignment(const std::vector &full_assignment, const std::map &variable_annotations) const +{ + for (auto < : terms) + { + if (lt.index == 0) + { + printf(" 1 * "); + lt.coeff.print(); + } + else + { + printf(" x_%zu * ", lt.index); + lt.coeff.print(); + + auto it = variable_annotations.find(lt.index); + printf(" where x_%zu (%s) was assigned value ", lt.index, + (it == variable_annotations.end() ? "no annotation" : it->second.c_str())); + full_assignment[lt.index-1].print(); + printf(" i.e. negative of "); + (-full_assignment[lt.index-1]).print(); + } + } +} + +template +std::ostream& operator<<(std::ostream &out, const linear_combination &lc) +{ + out << lc.terms.size() << "\n"; + for (const linear_term& lt : lc.terms) + { + out << lt.index << "\n"; + out << lt.coeff << OUTPUT_NEWLINE; + } + + return out; +} + +template +std::istream& operator>>(std::istream &in, linear_combination &lc) +{ + lc.terms.clear(); + + size_t s; + in >> s; + + consume_newline(in); + + lc.terms.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + linear_term lt; + in >> lt.index; + consume_newline(in); + in >> lt.coeff; + consume_OUTPUT_NEWLINE(in); + lc.terms.emplace_back(lt); + } + + return in; +} + +template +linear_combination operator*(const integer_coeff_t int_coeff, const linear_combination &lc) +{ + return lc * int_coeff; +} + +template +linear_combination operator*(const FieldT &field_coeff, const linear_combination &lc) +{ + return lc * field_coeff; +} + +template +linear_combination operator+(const integer_coeff_t int_coeff, const linear_combination &lc) +{ + return linear_combination(int_coeff) + lc; +} + +template +linear_combination operator+(const FieldT &field_coeff, const linear_combination &lc) +{ + return linear_combination(field_coeff) + lc; +} + +template +linear_combination operator-(const integer_coeff_t int_coeff, const linear_combination &lc) +{ + return linear_combination(int_coeff) - lc; +} + +template +linear_combination operator-(const FieldT &field_coeff, const linear_combination &lc) +{ + return linear_combination(field_coeff) - lc; +} + +template +linear_combination::linear_combination(const std::vector > &all_terms) +{ + if (all_terms.empty()) + { + return; + } + + terms = all_terms; + std::sort(terms.begin(), terms.end(), [](linear_term a, linear_term b) { return a.index < b.index; }); + + auto result_it = terms.begin(); + for (auto it = ++terms.begin(); it != terms.end(); ++it) + { + if (it->index == result_it->index) + { + result_it->coeff += it->coeff; + } + else + { + *(++result_it) = *it; + } + } + terms.resize((result_it - terms.begin()) + 1); +} + +} // libsnark + +#endif // VARIABLE_TCC diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.hpp b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.hpp new file mode 100644 index 0000000..4488d48 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.hpp @@ -0,0 +1,160 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a compliance predicate for R1CS PCD. + + A compliance predicate specifies a local invariant to be enforced, by PCD, + throughout a dynamic distributed computation. A compliance predicate + receives input messages, local data, and an output message (and perhaps some + other auxiliary information), and then either accepts or rejects. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef COMPLIANCE_PREDICATE_HPP_ +#define COMPLIANCE_PREDICATE_HPP_ + +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" + +namespace libsnark { + +/********************************* Message ***********************************/ + +/** + * A message for R1CS PCD. + * + * It is a pair, consisting of + * - a type (a positive integer), and + * - a payload (a vector of field elements). + */ +template +class r1cs_pcd_message { +public: + size_t type; + + r1cs_pcd_message(const size_t type); + virtual r1cs_variable_assignment payload_as_r1cs_variable_assignment() const = 0; + r1cs_variable_assignment as_r1cs_variable_assignment() const; + + virtual void print() const; + virtual ~r1cs_pcd_message() = default; +}; + +/******************************* Local data **********************************/ + +/** + * A local data for R1CS PCD. + */ +template +class r1cs_pcd_local_data { +public: + r1cs_pcd_local_data() = default; + virtual r1cs_variable_assignment as_r1cs_variable_assignment() const = 0; + virtual ~r1cs_pcd_local_data() = default; +}; + +/******************************** Witness ************************************/ + +template +using r1cs_pcd_witness = std::vector; + +/*************************** Compliance predicate ****************************/ + +template +class r1cs_pcd_compliance_predicate; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_pcd_compliance_predicate &cp); + +template +std::istream& operator>>(std::istream &in, r1cs_pcd_compliance_predicate &cp); + +/** + * A compliance predicate for R1CS PCD. + * + * It is a wrapper around R1CS that also specifies how to parse a + * variable assignment as: + * - output message (the input) + * - some number of input messages (part of the witness) + * - local data (also part of the witness) + * - auxiliary information (the remaining variables of the witness) + * + * A compliance predicate also has a type, allegedly the same + * as the type of the output message. + * + * The input wires of R1CS appear in the following order: + * - (1 + outgoing_message_payload_length) wires for outgoing message + * - 1 wire for arity (allegedly, 0 <= arity <= max_arity) + * - for i = 0, ..., max_arity-1: + * - (1 + incoming_message_payload_lengths[i]) wires for i-th message of + * the input (in the array that's padded to max_arity messages) + * - local_data_length wires for local data + * + * The rest witness_length wires of the R1CS constitute the witness. + * + * To allow for optimizations, the compliance predicate also + * specififies a flag, called relies_on_same_type_inputs, denoting + * whether the predicate works under the assumption that all input + * messages have the same type. In such case a member + * accepted_input_types lists all types accepted by the predicate + * (accepted_input_types has no meaning if + * relies_on_same_type_inputs=false). + */ + +template +class r1cs_pcd_compliance_predicate { +public: + + size_t name; + size_t type; + + r1cs_constraint_system constraint_system; + + size_t outgoing_message_payload_length; + size_t max_arity; + std::vector incoming_message_payload_lengths; + size_t local_data_length; + size_t witness_length; + + bool relies_on_same_type_inputs; + std::set accepted_input_types; + + r1cs_pcd_compliance_predicate() = default; + r1cs_pcd_compliance_predicate(r1cs_pcd_compliance_predicate &&other) = default; + r1cs_pcd_compliance_predicate(const r1cs_pcd_compliance_predicate &other) = default; + r1cs_pcd_compliance_predicate(const size_t name, + const size_t type, + const r1cs_constraint_system &constraint_system, + const size_t outgoing_message_payload_length, + const size_t max_arity, + const std::vector &incoming_message_payload_lengths, + const size_t local_data_length, + const size_t witness_length, + const bool relies_on_same_type_inputs, + const std::set accepted_input_types = std::set()); + + r1cs_pcd_compliance_predicate & operator=(const r1cs_pcd_compliance_predicate &other) = default; + + bool is_well_formed() const; + bool has_equal_input_and_output_lengths() const; + bool has_equal_input_lengths() const; + + bool is_satisfied(const std::shared_ptr > &outgoing_message, + const std::vector > > &incoming_messages, + const std::shared_ptr > &local_data, + const r1cs_pcd_witness &witness) const; + + bool operator==(const r1cs_pcd_compliance_predicate &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_pcd_compliance_predicate &cp); + friend std::istream& operator>> (std::istream &in, r1cs_pcd_compliance_predicate &cp); +}; + + +} // libsnark + +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.tcc" + +#endif // COMPLIANCE_PREDICATE_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.tcc b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.tcc new file mode 100644 index 0000000..bca6b9b --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.tcc @@ -0,0 +1,235 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a compliance predicate for R1CS PCD. + + See compliance_predicate.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef COMPLIANCE_PREDICATE_TCC_ +#define COMPLIANCE_PREDICATE_TCC_ + +#include "common/utils.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd_params.hpp" + +namespace libsnark { + +template +class r1cs_pcd_compliance_predicate_primary_input; + +template +class r1cs_pcd_compliance_predicate_auxiliary_input; + +template +r1cs_variable_assignment r1cs_pcd_message::as_r1cs_variable_assignment() const +{ + r1cs_variable_assignment result = this->payload_as_r1cs_variable_assignment(); + result.insert(result.begin(), FieldT(this->type)); + return result; +} + +template +r1cs_pcd_message::r1cs_pcd_message(const size_t type) : type(type) +{ +} + +template +void r1cs_pcd_message::print() const +{ + printf("PCD message (default print routines):\n"); + printf(" Type: %zu\n", this->type); + + printf(" Payload\n"); + const r1cs_variable_assignment payload = this->payload_as_r1cs_variable_assignment(); + for (auto &elt: payload) + { + elt.print(); + } +} + +template +r1cs_pcd_compliance_predicate::r1cs_pcd_compliance_predicate(const size_t name, + const size_t type, + const r1cs_constraint_system &constraint_system, + const size_t outgoing_message_payload_length, + const size_t max_arity, + const std::vector &incoming_message_payload_lengths, + const size_t local_data_length, + const size_t witness_length, + const bool relies_on_same_type_inputs, + const std::set accepted_input_types) : + name(name), + type(type), + constraint_system(constraint_system), + outgoing_message_payload_length(outgoing_message_payload_length), + max_arity(max_arity), + incoming_message_payload_lengths(incoming_message_payload_lengths), + local_data_length(local_data_length), + witness_length(witness_length), + relies_on_same_type_inputs(relies_on_same_type_inputs), + accepted_input_types(accepted_input_types) +{ + assert(max_arity == incoming_message_payload_lengths.size()); +} + +template +bool r1cs_pcd_compliance_predicate::is_well_formed() const +{ + const bool type_not_zero = (type != 0); + const bool incoming_message_payload_lengths_well_specified = (incoming_message_payload_lengths.size() == max_arity); + + size_t all_message_payload_lengths = outgoing_message_payload_length; + for (size_t i = 0; i < incoming_message_payload_lengths.size(); ++i) + { + all_message_payload_lengths += incoming_message_payload_lengths[i]; + } + const size_t type_vec_length = max_arity+1; + const size_t arity_length = 1; + + const bool correct_num_inputs = ((outgoing_message_payload_length + 1) == constraint_system.num_inputs()); + const bool correct_num_variables = ((all_message_payload_lengths + local_data_length + type_vec_length + arity_length + witness_length) == constraint_system.num_variables()); + +#ifdef DEBUG + printf("outgoing_message_payload_length: %zu\n", outgoing_message_payload_length); + printf("incoming_message_payload_lengths:"); + for (auto l : incoming_message_payload_lengths) + { + printf(" %zu", l); + } + printf("\n"); + printf("type_not_zero: %d\n", type_not_zero); + printf("incoming_message_payload_lengths_well_specified: %d\n", incoming_message_payload_lengths_well_specified); + printf("correct_num_inputs: %d (outgoing_message_payload_length = %zu, constraint_system.num_inputs() = %zu)\n", + correct_num_inputs, outgoing_message_payload_length, constraint_system.num_inputs()); + printf("correct_num_variables: %d (all_message_payload_lengths = %zu, local_data_length = %zu, type_vec_length = %zu, arity_length = %zu, witness_length = %zu, constraint_system.num_variables() = %zu)\n", + correct_num_variables, + all_message_payload_lengths, local_data_length, type_vec_length, arity_length, witness_length, + constraint_system.num_variables()); +#endif + + return (type_not_zero && incoming_message_payload_lengths_well_specified && correct_num_inputs && correct_num_variables); +} + +template +bool r1cs_pcd_compliance_predicate::has_equal_input_and_output_lengths() const +{ + for (size_t i = 0; i < incoming_message_payload_lengths.size(); ++i) + { + if (incoming_message_payload_lengths[i] != outgoing_message_payload_length) + { + return false; + } + } + + return true; +} + +template +bool r1cs_pcd_compliance_predicate::has_equal_input_lengths() const +{ + for (size_t i = 1; i < incoming_message_payload_lengths.size(); ++i) + { + if (incoming_message_payload_lengths[i] != incoming_message_payload_lengths[0]) + { + return false; + } + } + + return true; +} + +template +bool r1cs_pcd_compliance_predicate::operator==(const r1cs_pcd_compliance_predicate &other) const +{ + return (this->name == other.name && + this->type == other.type && + this->constraint_system == other.constraint_system && + this->outgoing_message_payload_length == other.outgoing_message_payload_length && + this->max_arity == other.max_arity && + this->incoming_message_payload_lengths == other.incoming_message_payload_lengths && + this->local_data_length == other.local_data_length && + this->witness_length == other.witness_length && + this->relies_on_same_type_inputs == other.relies_on_same_type_inputs && + this->accepted_input_types == other.accepted_input_types); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_pcd_compliance_predicate &cp) +{ + out << cp.name << "\n"; + out << cp.type << "\n"; + out << cp.max_arity << "\n"; + assert(cp.max_arity == cp.incoming_message_payload_lengths.size()); + for (size_t i = 0; i < cp.max_arity; ++i) + { + out << cp.incoming_message_payload_lengths[i] << "\n"; + } + out << cp.outgoing_message_payload_length << "\n"; + out << cp.local_data_length << "\n"; + out << cp.witness_length << "\n"; + output_bool(out, cp.relies_on_same_type_inputs); + out << cp.accepted_input_types << "\n"; + out << cp.constraint_system << "\n"; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_pcd_compliance_predicate &cp) +{ + in >> cp.name; + consume_newline(in); + in >> cp.type; + consume_newline(in); + in >> cp.max_arity; + consume_newline(in); + cp.incoming_message_payload_lengths.resize(cp.max_arity); + for (size_t i = 0; i < cp.max_arity; ++i) + { + in >> cp.incoming_message_payload_lengths[i]; + consume_newline(in); + } + in >> cp.outgoing_message_payload_length; + consume_newline(in); + in >> cp.local_data_length; + consume_newline(in); + in >> cp.witness_length; + consume_newline(in); + input_bool(in, cp.relies_on_same_type_inputs); + in >> cp.accepted_input_types; + consume_newline(in); + in >> cp.constraint_system; + consume_newline(in); + + return in; +} + +template +bool r1cs_pcd_compliance_predicate::is_satisfied(const std::shared_ptr > &outgoing_message, + const std::vector > > &incoming_messages, + const std::shared_ptr > &local_data, + const r1cs_pcd_witness &witness) const +{ + assert(outgoing_message.payload_as_r1cs_variable_assignment().size() == outgoing_message_payload_length); + assert(incoming_messages.size() <= max_arity); + for (size_t i = 0; i < incoming_messages.size(); ++i) + { + assert(incoming_messages[i].payload_as_r1cs_variable_assignment().size() == incoming_message_payload_lengths[i]); + } + assert(local_data.as_r1cs_variable_assignment().size() == local_data_length); + + r1cs_pcd_compliance_predicate_primary_input cp_primary_input(outgoing_message); + r1cs_pcd_compliance_predicate_auxiliary_input cp_auxiliary_input(incoming_messages, local_data, witness); + + return constraint_system.is_satisfied(cp_primary_input.as_r1cs_primary_input(), + cp_auxiliary_input.as_r1cs_auxiliary_input(incoming_message_payload_lengths)); +} + +} // libsnark + +#endif // COMPLIANCE_PREDICATE_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/cp_handler.hpp b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/cp_handler.hpp new file mode 100644 index 0000000..5b841c0 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/cp_handler.hpp @@ -0,0 +1,114 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a compliance predicate handler. + + A compliance predicate handler is a base class for creating compliance predicates. + It relies on classes declared in gadgetlib1. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef CP_HANDLER_HPP_ +#define CP_HANDLER_HPP_ + +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.hpp" +#include "gadgetlib1/protoboard.hpp" + +namespace libsnark { + +/***************************** Message variable ******************************/ + +/** + * A variable to represent an r1cs_pcd_message. + */ +template +class r1cs_pcd_message_variable : public gadget { +protected: + size_t num_vars_at_construction; +public: + + pb_variable type; + + pb_variable_array all_vars; + + r1cs_pcd_message_variable(protoboard &pb, + const std::string &annotation_prefix); + void update_all_vars(); + + void generate_r1cs_witness(const std::shared_ptr > &message); + virtual std::shared_ptr > get_message() const = 0; + + virtual ~r1cs_pcd_message_variable() = default; +}; +/*************************** Local data variable *****************************/ + +/** + * A variable to represent an r1cs_pcd_local_data. + */ +template +class r1cs_pcd_local_data_variable : public gadget { +protected: + size_t num_vars_at_construction; +public: + + pb_variable_array all_vars; + + r1cs_pcd_local_data_variable(protoboard &pb, + const std::string &annotation_prefix); + void update_all_vars(); + + void generate_r1cs_witness(const std::shared_ptr > &local_data); + + virtual ~r1cs_pcd_local_data_variable() = default; +}; + +/*********************** Compliance predicate handler ************************/ + +/** + * A base class for creating compliance predicates. + */ +template +class compliance_predicate_handler { +protected: + protoboardT pb; + + std::shared_ptr > outgoing_message; + pb_variable arity; + std::vector > > incoming_messages; + std::shared_ptr > local_data; +public: + const size_t name; + const size_t type; + const size_t max_arity; + const bool relies_on_same_type_inputs; + const std::set accepted_input_types; + + compliance_predicate_handler(const protoboardT &pb, + const size_t name, + const size_t type, + const size_t max_arity, + const bool relies_on_same_type_inputs, + const std::set accepted_input_types = std::set()); + virtual void generate_r1cs_constraints() = 0; + virtual void generate_r1cs_witness(const std::vector > > &incoming_message_values, + const std::shared_ptr > &local_data_value); + + r1cs_pcd_compliance_predicate get_compliance_predicate() const; + r1cs_variable_assignment get_full_variable_assignment() const; + + std::shared_ptr > get_outgoing_message() const; + size_t get_arity() const; + std::shared_ptr > get_incoming_message(const size_t message_idx) const; + std::shared_ptr > get_local_data() const; + r1cs_variable_assignment get_witness() const; +}; + +} // libsnark + +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/cp_handler.tcc" + +#endif // CP_HANDLER_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/cp_handler.tcc b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/cp_handler.tcc new file mode 100644 index 0000000..431134e --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/cp_handler.tcc @@ -0,0 +1,189 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a compliance predicate handler. + + See cp_handler.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef CP_HANDLER_TCC_ +#define CP_HANDLER_TCC_ + +#include + +namespace libsnark { + +template +r1cs_pcd_message_variable::r1cs_pcd_message_variable(protoboard &pb, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + type.allocate(pb, FMT(annotation_prefix, " type")); + all_vars.emplace_back(type); + + num_vars_at_construction = pb.num_variables(); +} + +template +void r1cs_pcd_message_variable::update_all_vars() +{ + /* NOTE: this assumes that r1cs_pcd_message_variable has been the + * only gadget allocating variables on the protoboard and needs to + * be updated, e.g., in multicore variable allocation scenario. */ + + for (size_t var_idx = num_vars_at_construction + 1; var_idx <= this->pb.num_variables(); ++var_idx) + { + all_vars.emplace_back(pb_variable(var_idx)); + } +} + +template +void r1cs_pcd_message_variable::generate_r1cs_witness(const std::shared_ptr > &message) +{ + all_vars.fill_with_field_elements(this->pb, message->as_r1cs_variable_assignment()); +} + +template +r1cs_pcd_local_data_variable::r1cs_pcd_local_data_variable(protoboard &pb, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + num_vars_at_construction = pb.num_variables(); +} + +template +void r1cs_pcd_local_data_variable::update_all_vars() +{ + /* (the same NOTE as for r1cs_message_variable applies) */ + + for (size_t var_idx = num_vars_at_construction + 1; var_idx <= this->pb.num_variables(); ++var_idx) + { + all_vars.emplace_back(pb_variable(var_idx)); + } +} + +template +void r1cs_pcd_local_data_variable::generate_r1cs_witness(const std::shared_ptr > &local_data) +{ + all_vars.fill_with_field_elements(this->pb, local_data->as_r1cs_variable_assignment()); +} + +template +compliance_predicate_handler::compliance_predicate_handler(const protoboardT &pb, + const size_t name, + const size_t type, + const size_t max_arity, + const bool relies_on_same_type_inputs, + const std::set accepted_input_types) : + pb(pb), name(name), type(type), max_arity(max_arity), relies_on_same_type_inputs(relies_on_same_type_inputs), + accepted_input_types(accepted_input_types) +{ + incoming_messages.resize(max_arity); +} + +template +void compliance_predicate_handler::generate_r1cs_witness(const std::vector > > &incoming_message_values, + const std::shared_ptr > &local_data_value) +{ + pb.clear_values(); + pb.val(outgoing_message->type) = FieldT(type); + pb.val(arity) = FieldT(incoming_message_values.size()); + + for (size_t i = 0; i < incoming_message_values.size(); ++i) + { + incoming_messages[i]->generate_r1cs_witness(incoming_message_values[i]); + } + + local_data->generate_r1cs_witness(local_data_value); +} + + +template +r1cs_pcd_compliance_predicate compliance_predicate_handler::get_compliance_predicate() const +{ + assert(incoming_messages.size() == max_arity); + + const size_t outgoing_message_payload_length = outgoing_message->all_vars.size() - 1; + + std::vector incoming_message_payload_lengths(max_arity); + std::transform(incoming_messages.begin(), incoming_messages.end(), + incoming_message_payload_lengths.begin(), + [] (const std::shared_ptr > &msg) { return msg->all_vars.size() - 1; }); + + const size_t local_data_length = local_data->all_vars.size(); + + const size_t all_but_witness_length = ((1 + outgoing_message_payload_length) + 1 + + (max_arity + std::accumulate(incoming_message_payload_lengths.begin(), + incoming_message_payload_lengths.end(), 0)) + + local_data_length); + const size_t witness_length = pb.num_variables() - all_but_witness_length; + + r1cs_constraint_system constraint_system = pb.get_constraint_system(); + constraint_system.primary_input_size = 1 + outgoing_message_payload_length; + constraint_system.auxiliary_input_size = pb.num_variables() - constraint_system.primary_input_size; + + return r1cs_pcd_compliance_predicate(name, + type, + constraint_system, + outgoing_message_payload_length, + max_arity, + incoming_message_payload_lengths, + local_data_length, + witness_length, + relies_on_same_type_inputs, + accepted_input_types); +} + +template +r1cs_variable_assignment compliance_predicate_handler::get_full_variable_assignment() const +{ + return pb.full_variable_assignment(); +} + +template +std::shared_ptr > compliance_predicate_handler::get_outgoing_message() const +{ + return outgoing_message->get_message(); +} + +template +size_t compliance_predicate_handler::get_arity() const +{ + return pb.val(arity).as_ulong(); +} + +template +std::shared_ptr > compliance_predicate_handler::get_incoming_message(const size_t message_idx) const +{ + assert(message_idx < max_arity); + return incoming_messages[message_idx]->get_message(); +} + +template +std::shared_ptr > compliance_predicate_handler::get_local_data() const +{ + return local_data->get_local_data(); +} + +template +r1cs_pcd_witness compliance_predicate_handler::get_witness() const +{ + const r1cs_variable_assignment va = pb.full_variable_assignment(); + // outgoing_message + arity + incoming_messages + local_data + const size_t witness_pos = (outgoing_message->all_vars.size() + 1 + + std::accumulate(incoming_messages.begin(), incoming_messages.end(), + 0, [](size_t acc, const std::shared_ptr > &msg) { + return acc + msg->all_vars.size(); }) + + local_data->all_vars.size()); + + return r1cs_variable_assignment(va.begin() + witness_pos, va.end()); +} + +} // libsnark + +#endif // CP_HANDLER_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/examples/tally_cp.hpp b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/examples/tally_cp.hpp new file mode 100644 index 0000000..2a6f237 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/examples/tally_cp.hpp @@ -0,0 +1,110 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the tally compliance predicate. + + The tally compliance predicate has two purposes: + (1) it exemplifies the use of interfaces declared in cp_handler.hpp, and + (2) it enables us to test r1cs_pcd functionalities. + + See + - src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/examples/run_r1cs_sp_ppzkpcd.hpp + - src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/examples/run_r1cs_mp_ppzkpcd.hpp + for code that uses the tally compliance predicate. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TALLY_CP_HPP_ +#define TALLY_CP_HPP_ + +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/cp_handler.hpp" + +namespace libsnark { + +/** + * Subclasses a R1CS PCD message to the tally compliance predicate. + */ +template +class tally_pcd_message : public r1cs_pcd_message { +public: + size_t wordsize; + + size_t sum; + size_t count; + + tally_pcd_message(const size_t type, + const size_t wordsize, + const size_t sum, + const size_t count); + r1cs_variable_assignment payload_as_r1cs_variable_assignment() const; + void print() const; + + ~tally_pcd_message() = default; +}; + +template +class tally_pcd_local_data : public r1cs_pcd_local_data { +public: + size_t summand; + + tally_pcd_local_data(const size_t summand); + r1cs_variable_assignment as_r1cs_variable_assignment() const; + void print() const; + + ~tally_pcd_local_data() = default; +}; + +/** + * Subclass a R1CS compliance predicate handler to the tally compliance predicate handler. + */ +template +class tally_cp_handler : public compliance_predicate_handler > { +public: + typedef compliance_predicate_handler > base_handler; + pb_variable_array incoming_types; + + pb_variable sum_out_packed; + pb_variable count_out_packed; + pb_variable_array sum_in_packed; + pb_variable_array count_in_packed; + + pb_variable_array sum_in_packed_aux; + pb_variable_array count_in_packed_aux; + + std::shared_ptr > unpack_sum_out; + std::shared_ptr > unpack_count_out; + std::vector > pack_sum_in; + std::vector > pack_count_in; + + pb_variable type_val_inner_product; + std::shared_ptr > compute_type_val_inner_product; + + pb_variable_array arity_indicators; + + size_t wordsize; + size_t message_length; + + tally_cp_handler(const size_t type, + const size_t max_arity, + const size_t wordsize, + const bool relies_on_same_type_inputs = false, + const std::set accepted_input_types = std::set()); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(const std::vector > > &incoming_messages, + const std::shared_ptr > &local_data); + + std::shared_ptr > get_base_case_message() const; +}; + +} // libsnark + +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/examples/tally_cp.tcc" + +#endif // TALLY_CP_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/examples/tally_cp.tcc b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/examples/tally_cp.tcc new file mode 100644 index 0000000..7712d75 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/examples/tally_cp.tcc @@ -0,0 +1,276 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the tally compliance predicate. + + See tally_cp.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TALLY_CP_TCC_ +#define TALLY_CP_TCC_ + +#include +#include + +namespace libsnark { + +template +tally_pcd_message::tally_pcd_message(const size_t type, + const size_t wordsize, + const size_t sum, + const size_t count) : + r1cs_pcd_message(type), wordsize(wordsize), sum(sum), count(count) +{ +} + +template +r1cs_variable_assignment tally_pcd_message::payload_as_r1cs_variable_assignment() const +{ + std::function bit_to_FieldT = [] (const bool bit) { return bit ? FieldT::one() : FieldT::zero(); }; + + const bit_vector sum_bits = convert_field_element_to_bit_vector(sum, wordsize); + const bit_vector count_bits = convert_field_element_to_bit_vector(count, wordsize); + + r1cs_variable_assignment result(2 * wordsize); + std::transform(sum_bits.begin(), sum_bits.end(), result.begin() , bit_to_FieldT); + std::transform(count_bits.begin(), count_bits.end(), result.begin() + wordsize, bit_to_FieldT); + + return result; +} + +template +void tally_pcd_message::print() const +{ + printf("Tally message of type %zu:\n", this->type); + printf(" wordsize: %zu\n", wordsize); + printf(" sum: %zu\n", sum); + printf(" count: %zu\n", count); +} + +template +tally_pcd_local_data::tally_pcd_local_data(const size_t summand) : + summand(summand) +{ +} + +template +r1cs_variable_assignment tally_pcd_local_data::as_r1cs_variable_assignment() const +{ + const r1cs_variable_assignment result = { FieldT(summand) }; + return result; +} + +template +void tally_pcd_local_data::print() const +{ + printf("Tally PCD local data:\n"); + printf(" summand: %zu\n", summand); +} + +template +class tally_pcd_message_variable: public r1cs_pcd_message_variable { +public: + pb_variable_array sum_bits; + pb_variable_array count_bits; + size_t wordsize; + + tally_pcd_message_variable(protoboard &pb, + const size_t wordsize, + const std::string &annotation_prefix) : + r1cs_pcd_message_variable(pb, annotation_prefix), wordsize(wordsize) + { + sum_bits.allocate(pb, wordsize, FMT(annotation_prefix, " sum_bits")); + count_bits.allocate(pb, wordsize, FMT(annotation_prefix, " count_bits")); + + this->update_all_vars(); + } + + std::shared_ptr > get_message() const + { + const size_t type_val = this->pb.val(this->type).as_ulong(); + const size_t sum_val = sum_bits.get_field_element_from_bits(this->pb).as_ulong(); + const size_t count_val = count_bits.get_field_element_from_bits(this->pb).as_ulong(); + + std::shared_ptr > result; + result.reset(new tally_pcd_message(type_val, wordsize, sum_val, count_val)); + return result; + } + + ~tally_pcd_message_variable() = default; +}; + +template +class tally_pcd_local_data_variable : public r1cs_pcd_local_data_variable { +public: + + pb_variable summand; + + tally_pcd_local_data_variable(protoboard &pb, + const std::string &annotation_prefix) : + r1cs_pcd_local_data_variable(pb, annotation_prefix) + { + summand.allocate(pb, FMT(annotation_prefix, " summand")); + + this->update_all_vars(); + } + + std::shared_ptr > get_local_data() const + { + const size_t summand_val = this->pb.val(summand).as_ulong(); + + std::shared_ptr > result; + result.reset(new tally_pcd_local_data(summand_val)); + return result; + } + + ~tally_pcd_local_data_variable() = default; +}; + +template +tally_cp_handler::tally_cp_handler(const size_t type, const size_t max_arity, const size_t wordsize, + const bool relies_on_same_type_inputs, + const std::set accepted_input_types) : + compliance_predicate_handler >(protoboard(), + type*100, + type, + max_arity, + relies_on_same_type_inputs, + accepted_input_types), + wordsize(wordsize) +{ + this->outgoing_message.reset(new tally_pcd_message_variable(this->pb, wordsize, "outgoing_message")); + this->arity.allocate(this->pb, "arity"); + + for (size_t i = 0; i < max_arity; ++i) + { + this->incoming_messages[i].reset(new tally_pcd_message_variable(this->pb, wordsize, FMT("", "incoming_messages_%zu", i))); + } + + this->local_data.reset(new tally_pcd_local_data_variable(this->pb, "local_data")); + + sum_out_packed.allocate(this->pb, "sum_out_packed"); + count_out_packed.allocate(this->pb, "count_out_packed"); + + sum_in_packed.allocate(this->pb, max_arity, "sum_in_packed"); + count_in_packed.allocate(this->pb, max_arity, "count_in_packed"); + + sum_in_packed_aux.allocate(this->pb, max_arity, "sum_in_packed_aux"); + count_in_packed_aux.allocate(this->pb, max_arity, "count_in_packed_aux"); + + type_val_inner_product.allocate(this->pb, "type_val_inner_product"); + for (auto &msg : this->incoming_messages) + { + incoming_types.emplace_back(msg->type); + } + + compute_type_val_inner_product.reset(new inner_product_gadget(this->pb, incoming_types, sum_in_packed, type_val_inner_product, "compute_type_val_inner_product")); + + unpack_sum_out.reset(new packing_gadget(this->pb, std::dynamic_pointer_cast >(this->outgoing_message)->sum_bits, sum_out_packed, "pack_sum_out")); + unpack_count_out.reset(new packing_gadget(this->pb, std::dynamic_pointer_cast >(this->outgoing_message)->count_bits, count_out_packed, "pack_count_out")); + + for (size_t i = 0; i < max_arity; ++i) + { + pack_sum_in.emplace_back(packing_gadget(this->pb, std::dynamic_pointer_cast >(this->incoming_messages[i])->sum_bits, sum_in_packed[i], FMT("", "pack_sum_in_%zu", i))); + pack_count_in.emplace_back(packing_gadget(this->pb, std::dynamic_pointer_cast >(this->incoming_messages[i])->sum_bits, count_in_packed[i], FMT("", "pack_count_in_%zu", i))); + } + + arity_indicators.allocate(this->pb, max_arity+1, "arity_indicators"); +} + +template +void tally_cp_handler::generate_r1cs_constraints() +{ + unpack_sum_out->generate_r1cs_constraints(true); + unpack_count_out->generate_r1cs_constraints(true); + + for (size_t i = 0; i < this->max_arity; ++i) + { + pack_sum_in[i].generate_r1cs_constraints(true); + pack_count_in[i].generate_r1cs_constraints(true); + } + + for (size_t i = 0; i < this->max_arity; ++i) + { + this->pb.add_r1cs_constraint(r1cs_constraint(incoming_types[i], sum_in_packed_aux[i], sum_in_packed[i]), FMT("", "initial_sum_%zu_is_zero", i)); + this->pb.add_r1cs_constraint(r1cs_constraint(incoming_types[i], count_in_packed_aux[i], count_in_packed[i]), FMT("", "initial_sum_%zu_is_zero", i)); + } + + /* constrain arity indicator variables so that arity_indicators[arity] = 1 and arity_indicators[i] = 0 for any other i */ + for (size_t i = 0; i < this->max_arity; ++i) + { + this->pb.add_r1cs_constraint(r1cs_constraint(this->arity - FieldT(i), arity_indicators[i], 0), FMT("", "arity_indicators_%zu", i)); + } + + this->pb.add_r1cs_constraint(r1cs_constraint(1, pb_sum(arity_indicators), 1), "arity_indicators"); + + /* require that types of messages that are past arity (i.e. unbound wires) carry 0 */ + for (size_t i = 0; i < this->max_arity; ++i) + { + this->pb.add_r1cs_constraint(r1cs_constraint(0 + pb_sum(pb_variable_array(arity_indicators.begin(), arity_indicators.begin() + i)), incoming_types[i], 0), FMT("", "unbound_types_%zu", i)); + } + + /* sum_out = local_data + \sum_i type[i] * sum_in[i] */ + compute_type_val_inner_product->generate_r1cs_constraints(); + this->pb.add_r1cs_constraint(r1cs_constraint(1, type_val_inner_product + std::dynamic_pointer_cast >(this->local_data)->summand, sum_out_packed), "update_sum"); + + /* count_out = 1 + \sum_i count_in[i] */ + this->pb.add_r1cs_constraint(r1cs_constraint(1, 1 + pb_sum(count_in_packed), count_out_packed), "update_count"); +} + +template +void tally_cp_handler::generate_r1cs_witness(const std::vector > > &incoming_messages, + const std::shared_ptr > &local_data) +{ + base_handler::generate_r1cs_witness(incoming_messages, local_data); + + for (size_t i = 0; i < this->max_arity; ++i) + { + pack_sum_in[i].generate_r1cs_witness_from_bits(); + pack_count_in[i].generate_r1cs_witness_from_bits(); + + if (!this->pb.val(incoming_types[i]).is_zero()) + { + this->pb.val(sum_in_packed_aux[i]) = this->pb.val(sum_in_packed[i]) * this->pb.val(incoming_types[i]).inverse(); + this->pb.val(count_in_packed_aux[i]) = this->pb.val(count_in_packed[i]) * this->pb.val(incoming_types[i]).inverse(); + } + } + + for (size_t i = 0; i < this->max_arity + 1; ++i) + { + this->pb.val(arity_indicators[i]) = (incoming_messages.size() == i ? FieldT::one() : FieldT::zero()); + } + + compute_type_val_inner_product->generate_r1cs_witness(); + this->pb.val(sum_out_packed) = this->pb.val(std::dynamic_pointer_cast >(this->local_data)->summand) + this->pb.val(type_val_inner_product); + + this->pb.val(count_out_packed) = FieldT::one(); + for (size_t i = 0; i < this->max_arity; ++i) + { + this->pb.val(count_out_packed) += this->pb.val(count_in_packed[i]); + } + + unpack_sum_out->generate_r1cs_witness_from_packed(); + unpack_count_out->generate_r1cs_witness_from_packed(); +} + +template +std::shared_ptr > tally_cp_handler::get_base_case_message() const +{ + const size_t type = 0; + const size_t sum = 0; + const size_t count = 0; + + std::shared_ptr > result; + result.reset(new tally_pcd_message(type, wordsize, sum, count)); + + return result; +} + +} // libsnark + +#endif // TALLY_CP_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/ppzkpcd_compliance_predicate.hpp b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/ppzkpcd_compliance_predicate.hpp new file mode 100644 index 0000000..b605b83 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/ppzkpcd_compliance_predicate.hpp @@ -0,0 +1,37 @@ +/** @file + ***************************************************************************** + + Template aliasing for prettifying R1CS PCD interfaces. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PPZKPCD_COMPLIANCE_PREDICATE_HPP_ +#define PPZKPCD_COMPLIANCE_PREDICATE_HPP_ + +#include "algebra/curves/public_params.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.hpp" + +namespace libsnark { + +/* template aliasing for R1CS (multi-predicate) ppzkPCD: */ + +template +using r1cs_mp_ppzkpcd_compliance_predicate = r1cs_pcd_compliance_predicate >; + +template +using r1cs_mp_ppzkpcd_message = r1cs_pcd_message >; + +template +using r1cs_mp_ppzkpcd_local_data = r1cs_pcd_local_data >; + +template +using r1cs_mp_ppzkpcd_variable_assignment = r1cs_variable_assignment >; + +} + +#endif // PPZKPCD_COMPLIANCE_PREDICATE_HPP_ + diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/examples/run_r1cs_mp_ppzkpcd.hpp b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/examples/run_r1cs_mp_ppzkpcd.hpp new file mode 100644 index 0000000..961bdd7 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/examples/run_r1cs_mp_ppzkpcd.hpp @@ -0,0 +1,39 @@ +/** @file + ***************************************************************************** + + Declaration of functionality that runs the R1CS multi-predicate ppzkPCD + for a compliance predicate example. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_R1CS_MP_PPZKPCD_HPP_ +#define RUN_R1CS_MP_PPZKPCD_HPP_ + +namespace libsnark { + +/** + * Runs the multi-predicate ppzkPCD (generator, prover, and verifier) for the + * "tally compliance predicate", of a given wordsize, arity, and depth. + * + * Optionally, also test the serialization routines for keys and proofs. + * (This takes additional time.) + * + * Optionally, also test the case of compliance predicates with different types. + */ +template +bool run_r1cs_mp_ppzkpcd_tally_example(const size_t wordsize, + const size_t max_arity, + const size_t depth, + const bool test_serialization, + const bool test_multi_type, + const bool test_same_type_optimization); + +} // libsnark + +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/examples/run_r1cs_mp_ppzkpcd.tcc" + +#endif // RUN_R1CS_MP_PPZKPCD_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/examples/run_r1cs_mp_ppzkpcd.tcc b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/examples/run_r1cs_mp_ppzkpcd.tcc new file mode 100644 index 0000000..7645273 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/examples/run_r1cs_mp_ppzkpcd.tcc @@ -0,0 +1,206 @@ +/** @file + ***************************************************************************** + + Implementation of functionality that runs the R1CS multi-predicate ppzkPCD + for a compliance predicate example. + + See run_r1cs_mp_ppzkpcd.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_R1CS_MP_PPZKPCD_TCC_ +#define RUN_R1CS_MP_PPZKPCD_TCC_ + +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd.hpp" + +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/examples/tally_cp.hpp" + +namespace libsnark { + +template +bool run_r1cs_mp_ppzkpcd_tally_example(const size_t wordsize, + const size_t max_arity, + const size_t depth, + const bool test_serialization, + const bool test_multi_type, + const bool test_same_type_optimization) +{ + enter_block("Call to run_r1cs_mp_ppzkpcd_tally_example"); + + typedef Fr FieldT; + + bool all_accept = true; + + enter_block("Generate all messages"); + size_t tree_size = 0; + size_t nodes_in_layer = 1; + for (size_t layer = 0; layer <= depth; ++layer) + { + tree_size += nodes_in_layer; + nodes_in_layer *= max_arity; + } + + std::vector tree_types(tree_size); + std::vector tree_elems(tree_size); + std::vector tree_arity(tree_size); + + nodes_in_layer = 1; + size_t node_idx = 0; + for (size_t layer = 0; layer <= depth; ++layer) + { + for (size_t id_in_layer = 0; id_in_layer < nodes_in_layer; ++id_in_layer, ++node_idx) + { + if (!test_multi_type) + { + tree_types[node_idx] = 1; + } + else + { + if (test_same_type_optimization) + { + tree_types[node_idx] = 1 + ((depth-layer) & 1); + } + else + { + tree_types[node_idx] = 1 + (std::rand() % 2); + } + } + + tree_elems[node_idx] = std::rand() % 100; + tree_arity[node_idx] = 1 + (std::rand() % max_arity); /* we will just skip below this threshold */ + printf("tree_types[%zu] = %zu\n", node_idx, tree_types[node_idx]); + printf("tree_elems[%zu] = %zu\n", node_idx, tree_elems[node_idx]); + printf("tree_arity[%zu] = %zu\n", node_idx, tree_arity[node_idx]); + + } + nodes_in_layer *= max_arity; + } + + leave_block("Generate all messages"); + + std::vector > tree_proofs(tree_size); + std::vector > > tree_messages(tree_size); + + enter_block("Generate compliance predicates"); + std::set tally_1_accepted_types, tally_2_accepted_types; + if (test_same_type_optimization) + { + if (!test_multi_type) + { + /* only tally 1 is going to be used */ + tally_1_accepted_types.insert(1); + } + else + { + tally_1_accepted_types.insert(2); + tally_2_accepted_types.insert(1); + } + } + + tally_cp_handler tally_1(1, max_arity, wordsize, test_same_type_optimization, tally_1_accepted_types); + tally_cp_handler tally_2(2, max_arity, wordsize, test_same_type_optimization, tally_2_accepted_types); + tally_1.generate_r1cs_constraints(); + tally_2.generate_r1cs_constraints(); + r1cs_pcd_compliance_predicate cp_1 = tally_1.get_compliance_predicate(); + r1cs_pcd_compliance_predicate cp_2 = tally_2.get_compliance_predicate(); + leave_block("Generate compliance predicates"); + + print_header("R1CS ppzkPCD Generator"); + r1cs_mp_ppzkpcd_keypair keypair = r1cs_mp_ppzkpcd_generator({ cp_1, cp_2 }); + + print_header("Process verification key"); + r1cs_mp_ppzkpcd_processed_verification_key pvk = r1cs_mp_ppzkpcd_process_vk(keypair.vk); + + if (test_serialization) + { + enter_block("Test serialization of keys"); + keypair.pk = reserialize >(keypair.pk); + keypair.vk = reserialize >(keypair.vk); + pvk = reserialize >(pvk); + leave_block("Test serialization of keys"); + } + + std::shared_ptr > base_msg = tally_1.get_base_case_message(); /* we choose the base to always be tally_1 */ + nodes_in_layer /= max_arity; + for (long layer = depth; layer >= 0; --layer, nodes_in_layer /= max_arity) + { + for (size_t i = 0; i < nodes_in_layer; ++i) + { + const size_t cur_idx = (nodes_in_layer - 1) / (max_arity - 1) + i; + + tally_cp_handler &cur_tally = (tree_types[cur_idx] == 1 ? tally_1 : tally_2); + r1cs_pcd_compliance_predicate &cur_cp = (tree_types[cur_idx] == 1 ? cp_1 : cp_2); + + const bool base_case = (max_arity * cur_idx + max_arity >= tree_size); + + std::vector > > msgs(max_arity, base_msg); + std::vector > proofs(max_arity); + + if (!base_case) + { + for (size_t i = 0; i < max_arity; ++i) + { + msgs[i] = tree_messages[max_arity*cur_idx + i + 1]; + proofs[i] = tree_proofs[max_arity*cur_idx + i + 1]; + } + } + msgs.resize(tree_arity[i]); + proofs.resize(tree_arity[i]); + + std::shared_ptr > ld; + ld.reset(new tally_pcd_local_data(tree_elems[cur_idx])); + cur_tally.generate_r1cs_witness(msgs, ld); + + const r1cs_pcd_compliance_predicate_primary_input tally_primary_input(cur_tally.get_outgoing_message()); + const r1cs_pcd_compliance_predicate_auxiliary_input tally_auxiliary_input(msgs, ld, cur_tally.get_witness()); + + print_header("R1CS ppzkPCD Prover"); + r1cs_mp_ppzkpcd_proof proof = r1cs_mp_ppzkpcd_prover(keypair.pk, cur_cp.name, tally_primary_input, tally_auxiliary_input, proofs); + + if (test_serialization) + { + enter_block("Test serialization of proof"); + proof = reserialize >(proof); + leave_block("Test serialization of proof"); + } + + tree_proofs[cur_idx] = proof; + tree_messages[cur_idx] = cur_tally.get_outgoing_message(); + + print_header("R1CS ppzkPCD Verifier"); + const r1cs_mp_ppzkpcd_primary_input pcd_verifier_input(tree_messages[cur_idx]); + const bool ans = r1cs_mp_ppzkpcd_verifier(keypair.vk, pcd_verifier_input, tree_proofs[cur_idx]); + + print_header("R1CS ppzkPCD Online Verifier"); + const bool ans2 = r1cs_mp_ppzkpcd_online_verifier(pvk, pcd_verifier_input, tree_proofs[cur_idx]); + assert(ans == ans2); + + all_accept = all_accept && ans; + + printf("\n"); + for (size_t i = 0; i < msgs.size(); ++i) + { + printf("Message %zu was:\n", i); + msgs[i]->print(); + } + printf("Summand at this node:\n%zu\n", tree_elems[cur_idx]); + printf("Outgoing message is:\n"); + tree_messages[cur_idx]->print(); + printf("\n"); + printf("Current node = %zu. Current proof verifies = %s\n", cur_idx, ans ? "YES" : "NO"); + printf("\n\n\n ================================================================================\n\n\n"); + } + } + + leave_block("Call to run_r1cs_mp_ppzkpcd_tally_example"); + + return all_accept; +} + +} // libsnark + +#endif // RUN_R1CS_MP_PPZKPCD_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/mp_pcd_circuits.hpp b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/mp_pcd_circuits.hpp new file mode 100644 index 0000000..7981056 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/mp_pcd_circuits.hpp @@ -0,0 +1,183 @@ +/** @file + ***************************************************************************** + + Declaration of functionality for creating and using the two PCD circuits in + a multi-predicate PCD construction. + + The implementation follows, extends, and optimizes the approach described + in \[CTV15]. At high level, there is a "compliance step" circuit and a + "translation step" circuit, for each compliance predicate. For more details, + see \[CTV15]. + + + References: + + \[CTV15]: + "Cluster Computing in Zero Knowledge", + Alessandro Chiesa, Eran Tromer, Madars Virza + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MP_PCD_CIRCUITS_HPP_ +#define MP_PCD_CIRCUITS_HPP_ + +#include "gadgetlib1/gadget.hpp" +#include "gadgetlib1/gadgets/gadget_from_r1cs.hpp" +#include "gadgetlib1/gadgets/hashes/crh_gadget.hpp" +#include "gadgetlib1/gadgets/set_commitment/set_commitment_gadget.hpp" +#include "gadgetlib1/gadgets/verifiers/r1cs_ppzksnark_verifier_gadget.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/cp_handler.hpp" + +namespace libsnark { + +/**************************** Compliance step ********************************/ + +/** + * A compliance-step PCD circuit. + * + * The circuit is an R1CS that checks compliance (for the given compliance predicate) + * and validity of previous proofs. + */ +template +class mp_compliance_step_pcd_circuit_maker { +public: + typedef Fr FieldT; + + r1cs_pcd_compliance_predicate compliance_predicate; + + protoboard pb; + + pb_variable zero; + + std::shared_ptr > block_for_outgoing_message; + std::shared_ptr > hash_outgoing_message; + + std::vector > block_for_incoming_messages; + std::vector > commitment_and_incoming_message_digests; + std::vector > unpack_commitment_and_incoming_message_digests; + std::vector > commitment_and_incoming_messages_digest_bits; + std::vector > hash_incoming_messages; + + std::vector > translation_step_vks; + std::vector > translation_step_vks_bits; + + pb_variable outgoing_message_type; + pb_variable_array outgoing_message_payload; + pb_variable_array outgoing_message_vars; + + pb_variable arity; + std::vector > incoming_message_types; + std::vector > incoming_message_payloads; + std::vector > incoming_message_vars; + + pb_variable_array local_data; + pb_variable_array cp_witness; + std::shared_ptr > compliance_predicate_as_gadget; + + pb_variable_array outgoing_message_bits; + std::shared_ptr > unpack_outgoing_message; + + std::vector > incoming_messages_bits; + std::vector > unpack_incoming_messages; + + pb_variable_array mp_compliance_step_pcd_circuit_input; + pb_variable_array padded_translation_step_vk_and_outgoing_message_digest; + std::vector > padded_commitment_and_incoming_messages_digest; + + std::shared_ptr > > commitment; + std::vector > > membership_proofs; + std::vector > > membership_checkers; + pb_variable_array membership_check_results; + pb_variable common_type; + pb_variable_array common_type_check_aux; + + std::vector > verifier_input; + std::vector > proof; + pb_variable_array verification_results; + std::vector > verifier; + + mp_compliance_step_pcd_circuit_maker(const r1cs_pcd_compliance_predicate &compliance_predicate, + const size_t max_number_of_predicates); + void generate_r1cs_constraints(); + r1cs_constraint_system get_circuit() const; + + void generate_r1cs_witness(const set_commitment &commitment_to_translation_step_r1cs_vks, + const std::vector > > &mp_translation_step_pcd_circuit_vks, + const std::vector &vk_membership_proofs, + const r1cs_pcd_compliance_predicate_primary_input &compliance_predicate_primary_input, + const r1cs_pcd_compliance_predicate_auxiliary_input &compliance_predicate_auxiliary_input, + const std::vector > > &translation_step_proofs); + r1cs_primary_input get_primary_input() const; + r1cs_auxiliary_input get_auxiliary_input() const; + + static size_t field_logsize(); + static size_t field_capacity(); + static size_t input_size_in_elts(); + static size_t input_capacity_in_bits(); + static size_t input_size_in_bits(); +}; + +/*************************** Translation step ********************************/ + +/** + * A translation-step PCD circuit. + * + * The circuit is an R1CS that checks validity of previous proofs. + */ +template +class mp_translation_step_pcd_circuit_maker { +public: + typedef Fr FieldT; + + protoboard pb; + + pb_variable_array mp_translation_step_pcd_circuit_input; + pb_variable_array unpacked_mp_translation_step_pcd_circuit_input; + pb_variable_array verifier_input; + std::shared_ptr > unpack_mp_translation_step_pcd_circuit_input; + + std::shared_ptr > hardcoded_compliance_step_vk; + std::shared_ptr > proof; + std::shared_ptr > online_verifier; + + mp_translation_step_pcd_circuit_maker(const r1cs_ppzksnark_verification_key > &compliance_step_vk); + void generate_r1cs_constraints(); + r1cs_constraint_system get_circuit() const; + + void generate_r1cs_witness(const r1cs_primary_input > translation_step_input, + const r1cs_ppzksnark_proof > &prev_proof); + r1cs_primary_input get_primary_input() const; + r1cs_auxiliary_input get_auxiliary_input() const; + + static size_t field_logsize(); + static size_t field_capacity(); + static size_t input_size_in_elts(); + static size_t input_capacity_in_bits(); + static size_t input_size_in_bits(); +}; + +/****************************** Input maps ***********************************/ + +/** + * Obtain the primary input for a compliance-step PCD circuit. + */ +template +r1cs_primary_input > get_mp_compliance_step_pcd_circuit_input(const set_commitment &commitment_to_translation_step_r1cs_vks, + const r1cs_pcd_compliance_predicate_primary_input > &primary_input); + +/** + * Obtain the primary input for a translation-step PCD circuit. + */ +template +r1cs_primary_input > get_mp_translation_step_pcd_circuit_input(const set_commitment &commitment_to_translation_step_r1cs_vks, + const r1cs_pcd_compliance_predicate_primary_input > > &primary_input); + +} // libsnark + +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/mp_pcd_circuits.tcc" + +#endif // MP_PCD_CIRCUITS_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/mp_pcd_circuits.tcc b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/mp_pcd_circuits.tcc new file mode 100644 index 0000000..713225d --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/mp_pcd_circuits.tcc @@ -0,0 +1,679 @@ +/** @file + ***************************************************************************** + + Implementation of functionality for creating and using the two PCD circuits in + a multi-predicate PCD construction. + + See mp_pcd_circuits.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MP_PCD_CIRCUITS_TCC_ +#define MP_PCD_CIRCUITS_TCC_ + +#include +#include "common/utils.hpp" +#include "gadgetlib1/constraint_profiling.hpp" + +namespace libsnark { + +template +mp_compliance_step_pcd_circuit_maker::mp_compliance_step_pcd_circuit_maker(const r1cs_pcd_compliance_predicate &compliance_predicate, + const size_t max_number_of_predicates) : + compliance_predicate(compliance_predicate) +{ + /* calculate some useful sizes */ + const size_t digest_size = CRH_with_field_out_gadget::get_digest_len(); + const size_t outgoing_msg_size_in_bits = field_logsize() * (1 + compliance_predicate.outgoing_message_payload_length); + assert(compliance_predicate.has_equal_input_lengths()); + const size_t translation_step_vk_size_in_bits = r1cs_ppzksnark_verification_key_variable::size_in_bits(mp_translation_step_pcd_circuit_maker >::input_size_in_elts()); + const size_t padded_verifier_input_size = mp_translation_step_pcd_circuit_maker >::input_capacity_in_bits(); + const size_t commitment_size = set_commitment_gadget >::root_size_in_bits(); + + const size_t output_block_size = commitment_size + outgoing_msg_size_in_bits; + const size_t max_incoming_payload_length = *std::max_element(compliance_predicate.incoming_message_payload_lengths.begin(), compliance_predicate.incoming_message_payload_lengths.end()); + const size_t max_input_block_size = commitment_size + field_logsize() * (1 + max_incoming_payload_length); + + CRH_with_bit_out_gadget::sample_randomness(std::max(output_block_size, max_input_block_size)); + + /* allocate input of the compliance MP_PCD circuit */ + mp_compliance_step_pcd_circuit_input.allocate(pb, input_size_in_elts(), "mp_compliance_step_pcd_circuit_input"); + + /* allocate inputs to the compliance predicate */ + outgoing_message_type.allocate(pb, "outgoing_message_type"); + outgoing_message_payload.allocate(pb, compliance_predicate.outgoing_message_payload_length, "outgoing_message_payload"); + + outgoing_message_vars.insert(outgoing_message_vars.end(), outgoing_message_type); + outgoing_message_vars.insert(outgoing_message_vars.end(), outgoing_message_payload.begin(), outgoing_message_payload.end()); + + arity.allocate(pb, "arity"); + + incoming_message_types.resize(compliance_predicate.max_arity); + incoming_message_payloads.resize(compliance_predicate.max_arity); + incoming_message_vars.resize(compliance_predicate.max_arity); + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + incoming_message_types[i].allocate(pb, FMT("", "incoming_message_type_%zu", i)); + incoming_message_payloads[i].allocate(pb, compliance_predicate.incoming_message_payload_lengths[i], FMT("", "incoming_message_payloads_%zu", i)); + + incoming_message_vars[i].insert(incoming_message_vars[i].end(), incoming_message_types[i]); + incoming_message_vars[i].insert(incoming_message_vars[i].end(), incoming_message_payloads[i].begin(), incoming_message_payloads[i].end()); + } + + local_data.allocate(pb, compliance_predicate.local_data_length, "local_data"); + cp_witness.allocate(pb, compliance_predicate.witness_length, "cp_witness"); + + /* convert compliance predicate from a constraint system into a gadget */ + pb_variable_array incoming_messages_concat; + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + incoming_messages_concat.insert(incoming_messages_concat.end(), incoming_message_vars[i].begin(), incoming_message_vars[i].end()); + } + + compliance_predicate_as_gadget.reset(new gadget_from_r1cs(pb, + { outgoing_message_vars, + pb_variable_array(1, arity), + incoming_messages_concat, + local_data, + cp_witness }, + compliance_predicate.constraint_system, "compliance_predicate_as_gadget")); + + /* unpack messages to bits */ + outgoing_message_bits.allocate(pb, outgoing_msg_size_in_bits, "outgoing_message_bits"); + unpack_outgoing_message.reset(new multipacking_gadget(pb, outgoing_message_bits, outgoing_message_vars, field_logsize(), "unpack_outgoing_message")); + + incoming_messages_bits.resize(compliance_predicate.max_arity); + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + const size_t incoming_msg_size_in_bits = field_logsize() * (1 + compliance_predicate.incoming_message_payload_lengths[i]); + + incoming_messages_bits[i].allocate(pb, incoming_msg_size_in_bits, FMT("", "incoming_messages_bits_%zu", i)); + unpack_incoming_messages.emplace_back(multipacking_gadget(pb, incoming_messages_bits[i], incoming_message_vars[i], field_logsize(), FMT("", "unpack_incoming_messages_%zu", i))); + } + + /* allocate digests */ + commitment_and_incoming_message_digests.resize(compliance_predicate.max_arity); + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + commitment_and_incoming_message_digests[i].allocate(pb, digest_size, FMT("", "commitment_and_incoming_message_digests_%zu", i)); + } + + /* allocate commitment, verification key(s) and membership checker(s)/proof(s) */ + commitment.reset(new set_commitment_variable >(pb, commitment_size, "commitment")); + + print_indent(); printf("* %s perform same type optimization for compliance predicate with type %zu\n", + (compliance_predicate.relies_on_same_type_inputs ? "Will" : "Will NOT"), + compliance_predicate.type); + if (compliance_predicate.relies_on_same_type_inputs) + { + /* only one set_commitment_gadget is needed */ + common_type.allocate(pb, "common_type"); + common_type_check_aux.allocate(pb, compliance_predicate.accepted_input_types.size(), "common_type_check_aux"); + + translation_step_vks_bits.resize(1); + translation_step_vks_bits[0].allocate(pb, translation_step_vk_size_in_bits, "translation_step_vk_bits"); + membership_check_results.allocate(pb, 1, "membership_check_results"); + + membership_proofs.emplace_back(set_membership_proof_variable>(pb, + max_number_of_predicates, + "membership_proof")); + membership_checkers.emplace_back(set_commitment_gadget>(pb, + max_number_of_predicates, + translation_step_vks_bits[0], + *commitment, + membership_proofs[0], + membership_check_results[0], "membership_checker")); + } + else + { + /* check for max_arity possibly different VKs */ + translation_step_vks_bits.resize(compliance_predicate.max_arity); + membership_check_results.allocate(pb, compliance_predicate.max_arity, "membership_check_results"); + + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + translation_step_vks_bits[i].allocate(pb, translation_step_vk_size_in_bits, FMT("", "translation_step_vks_bits_%zu", i)); + + membership_proofs.emplace_back(set_membership_proof_variable >(pb, + max_number_of_predicates, + FMT("", "membership_proof_%zu", i))); + membership_checkers.emplace_back(set_commitment_gadget >(pb, + max_number_of_predicates, + translation_step_vks_bits[i], + *commitment, + membership_proofs[i], + membership_check_results[i], + FMT("", "membership_checkers_%zu", i))); + } + } + + /* allocate blocks */ + block_for_outgoing_message.reset(new block_variable(pb, { commitment->bits, outgoing_message_bits }, "block_for_outgoing_message")); + + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + block_for_incoming_messages.emplace_back(block_variable(pb, { commitment->bits, incoming_messages_bits[i] }, FMT("", "block_for_incoming_messages_%zu", i))); + } + + /* allocate hash checkers */ + hash_outgoing_message.reset(new CRH_with_field_out_gadget(pb, output_block_size, *block_for_outgoing_message, mp_compliance_step_pcd_circuit_input, "hash_outgoing_message")); + + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + const size_t input_block_size = commitment_size + incoming_messages_bits[i].size(); + hash_incoming_messages.emplace_back(CRH_with_field_out_gadget(pb, input_block_size, block_for_incoming_messages[i], commitment_and_incoming_message_digests[i], FMT("", "hash_incoming_messages_%zu", i))); + } + + /* allocate useful zero variable */ + zero.allocate(pb, "zero"); + + /* prepare arguments for the verifier */ + if (compliance_predicate.relies_on_same_type_inputs) + { + translation_step_vks.emplace_back(r1cs_ppzksnark_verification_key_variable(pb, translation_step_vks_bits[0], mp_translation_step_pcd_circuit_maker >::input_size_in_elts(), "translation_step_vk")); + } + else + { + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + translation_step_vks.emplace_back(r1cs_ppzksnark_verification_key_variable(pb, translation_step_vks_bits[i], mp_translation_step_pcd_circuit_maker >::input_size_in_elts(), FMT("", "translation_step_vks_%zu", i))); + } + } + + verification_results.allocate(pb, compliance_predicate.max_arity, "verification_results"); + commitment_and_incoming_messages_digest_bits.resize(compliance_predicate.max_arity); + + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + commitment_and_incoming_messages_digest_bits[i].allocate(pb, digest_size * field_logsize(), FMT("", "commitment_and_incoming_messages_digest_bits_%zu", i)); + unpack_commitment_and_incoming_message_digests.emplace_back(multipacking_gadget(pb, + commitment_and_incoming_messages_digest_bits[i], + commitment_and_incoming_message_digests[i], + field_logsize(), + FMT("", "unpack_commitment_and_incoming_message_digests_%zu", i))); + + verifier_input.emplace_back(commitment_and_incoming_messages_digest_bits[i]); + while (verifier_input[i].size() < padded_verifier_input_size) + { + verifier_input[i].emplace_back(zero); + } + + proof.emplace_back(r1cs_ppzksnark_proof_variable(pb, FMT("", "proof_%zu", i))); + const r1cs_ppzksnark_verification_key_variable &vk_to_be_used = (compliance_predicate.relies_on_same_type_inputs ? translation_step_vks[0] : translation_step_vks[i]); + verifier.emplace_back(r1cs_ppzksnark_verifier_gadget(pb, + vk_to_be_used, + verifier_input[i], + mp_translation_step_pcd_circuit_maker >::field_capacity(), + proof[i], + verification_results[i], + FMT("", "verifier_%zu", i))); + } + + pb.set_input_sizes(input_size_in_elts()); +} + +template +void mp_compliance_step_pcd_circuit_maker::generate_r1cs_constraints() +{ + const size_t digest_size = CRH_with_bit_out_gadget::get_digest_len(); + const size_t dimension = knapsack_dimension::dimension; + print_indent(); printf("* Knapsack dimension: %zu\n", dimension); + + print_indent(); printf("* Compliance predicate arity: %zu\n", compliance_predicate.max_arity); + print_indent(); printf("* Compliance predicate outgoing payload length: %zu\n", compliance_predicate.outgoing_message_payload_length); + print_indent(); printf("* Compliance predicate inncoming payload lengts:"); + for (auto l : compliance_predicate.incoming_message_payload_lengths) + { + printf(" %zu", l); + } + printf("\n"); + print_indent(); printf("* Compliance predicate local data length: %zu\n", compliance_predicate.local_data_length); + print_indent(); printf("* Compliance predicate witness length: %zu\n", compliance_predicate.witness_length); + + PROFILE_CONSTRAINTS(pb, "booleanity") + { + PROFILE_CONSTRAINTS(pb, "booleanity: unpack outgoing_message") + { + unpack_outgoing_message->generate_r1cs_constraints(true); + } + + PROFILE_CONSTRAINTS(pb, "booleanity: unpack s incoming_messages") + { + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + unpack_incoming_messages[i].generate_r1cs_constraints(true); + } + } + + PROFILE_CONSTRAINTS(pb, "booleanity: unpack verification key") + { + for (size_t i = 0; i < translation_step_vks.size(); ++i) + { + translation_step_vks[i].generate_r1cs_constraints(true); + } + } + } + + PROFILE_CONSTRAINTS(pb, "(1+s) copies of hash") + { + print_indent(); printf("* Digest-size: %zu\n", digest_size); + hash_outgoing_message->generate_r1cs_constraints(); + + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + hash_incoming_messages[i].generate_r1cs_constraints(); + } + } + + PROFILE_CONSTRAINTS(pb, "s copies of repacking circuit for verifier") + { + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + unpack_commitment_and_incoming_message_digests[i].generate_r1cs_constraints(true); + } + } + + PROFILE_CONSTRAINTS(pb, "set membership check") + { + for (auto &membership_proof : membership_proofs) + { + membership_proof.generate_r1cs_constraints(); + } + + for (auto &membership_checker : membership_checkers) + { + membership_checker.generate_r1cs_constraints(); + } + } + + PROFILE_CONSTRAINTS(pb, "compliance predicate") + { + compliance_predicate_as_gadget->generate_r1cs_constraints(); + } + + PROFILE_CONSTRAINTS(pb, "s copies of verifier for translated proofs") + { + PROFILE_CONSTRAINTS(pb, "check that s proofs lie on the curve") + { + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + proof[i].generate_r1cs_constraints(); + } + } + + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + verifier[i].generate_r1cs_constraints(); + } + } + + PROFILE_CONSTRAINTS(pb, "miscellaneous") + { + generate_r1cs_equals_const_constraint(pb, zero, FieldT::zero(), "zero"); + + PROFILE_CONSTRAINTS(pb, "check that s proofs lie on the curve") + { + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + generate_boolean_r1cs_constraint(pb, verification_results[i], FMT("", "verification_results_%zu", i)); + } + } + + /* either type = 0 or proof verified w.r.t. a valid verification key */ + PROFILE_CONSTRAINTS(pb, "check that s messages have valid proofs (or are base case)") + { + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + pb.add_r1cs_constraint(r1cs_constraint(incoming_message_types[i], 1 - verification_results[i], 0), FMT("", "not_base_case_implies_valid_proof_%zu", i)); + } + } + + if (compliance_predicate.relies_on_same_type_inputs) + { + PROFILE_CONSTRAINTS(pb, "check that all non-base case messages are of same type and that VK is validly selected") + { + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + pb.add_r1cs_constraint(r1cs_constraint(incoming_message_types[i], incoming_message_types[i] - common_type, 0), FMT("", "non_base_types_equal_%zu", i)); + } + + pb.add_r1cs_constraint(r1cs_constraint(common_type, 1 - membership_check_results[0], 0), "valid_vk_for_the_common_type"); + + auto it = compliance_predicate.accepted_input_types.begin(); + for (size_t i = 0; i < compliance_predicate.accepted_input_types.size(); ++i, ++it) + { + pb.add_r1cs_constraint(r1cs_constraint((i == 0 ? common_type : common_type_check_aux[i-1]), + common_type - FieldT(*it), + (i == compliance_predicate.accepted_input_types.size() - 1 ? 0 * ONE : common_type_check_aux[i])), + FMT("", "common_type_in_prescribed_set_%zu_must_equal_%zu", i, *it)); + } + } + } + else + { + PROFILE_CONSTRAINTS(pb, "check that all s messages have validly selected VKs") + { + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + pb.add_r1cs_constraint(r1cs_constraint(incoming_message_types[i], 1 - membership_check_results[i], 0), FMT("", "not_base_case_implies_valid_vk_%zu", i)); + } + } + } + pb.add_r1cs_constraint(r1cs_constraint(1, outgoing_message_type, FieldT(compliance_predicate.type)), "enforce_outgoing_type"); + } + + PRINT_CONSTRAINT_PROFILING(); + print_indent(); printf("* Number of constraints in mp_compliance_step_pcd_circuit: %zu\n", pb.num_constraints()); +} + +template +r1cs_constraint_system > mp_compliance_step_pcd_circuit_maker::get_circuit() const +{ + return pb.get_constraint_system(); +} + +template +r1cs_primary_input > mp_compliance_step_pcd_circuit_maker::get_primary_input() const +{ + return pb.primary_input(); +} + +template +r1cs_auxiliary_input > mp_compliance_step_pcd_circuit_maker::get_auxiliary_input() const +{ + return pb.auxiliary_input(); +} + +template +void mp_compliance_step_pcd_circuit_maker::generate_r1cs_witness(const set_commitment &commitment_to_translation_step_r1cs_vks, + const std::vector > > &mp_translation_step_pcd_circuit_vks, + const std::vector &vk_membership_proofs, + const r1cs_pcd_compliance_predicate_primary_input &compliance_predicate_primary_input, + const r1cs_pcd_compliance_predicate_auxiliary_input &compliance_predicate_auxiliary_input, + const std::vector > > &translation_step_proofs) +{ + this->pb.clear_values(); + this->pb.val(zero) = FieldT::zero(); + + compliance_predicate_as_gadget->generate_r1cs_witness(compliance_predicate_primary_input.as_r1cs_primary_input(), + compliance_predicate_auxiliary_input.as_r1cs_auxiliary_input(compliance_predicate.incoming_message_payload_lengths)); + + unpack_outgoing_message->generate_r1cs_witness_from_packed(); + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + unpack_incoming_messages[i].generate_r1cs_witness_from_packed(); + } + + for (size_t i = 0; i < translation_step_vks.size(); ++i) + { + translation_step_vks[i].generate_r1cs_witness(mp_translation_step_pcd_circuit_vks[i]); + } + + commitment->generate_r1cs_witness(commitment_to_translation_step_r1cs_vks); + + if (compliance_predicate.relies_on_same_type_inputs) + { + /* all messages (except base case) must be of the same type */ + this->pb.val(common_type) = FieldT::zero(); + size_t nonzero_type_idx = 0; + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + if (this->pb.val(incoming_message_types[i]) == 0) + { + continue; + } + + if (this->pb.val(common_type).is_zero()) + { + this->pb.val(common_type) = this->pb.val(incoming_message_types[i]); + nonzero_type_idx = i; + } + else + { + assert(this->pb.val(common_type) == this->pb.val(incoming_message_types[i])); + } + } + + this->pb.val(membership_check_results[0]) = (this->pb.val(common_type).is_zero() ? FieldT::zero() : FieldT::one()); + membership_proofs[0].generate_r1cs_witness(vk_membership_proofs[nonzero_type_idx]); + membership_checkers[0].generate_r1cs_witness(); + + auto it = compliance_predicate.accepted_input_types.begin(); + for (size_t i = 0; i < compliance_predicate.accepted_input_types.size(); ++i, ++it) + { + pb.val(common_type_check_aux[i]) = ((i == 0 ? pb.val(common_type) : pb.val(common_type_check_aux[i-1])) * + (pb.val(common_type) - FieldT(*it))); + } + } + else + { + for (size_t i = 0; i < membership_checkers.size(); ++i) + { + this->pb.val(membership_check_results[i]) = (this->pb.val(incoming_message_types[i]).is_zero() ? FieldT::zero() : FieldT::one()); + membership_proofs[i].generate_r1cs_witness(vk_membership_proofs[i]); + membership_checkers[i].generate_r1cs_witness(); + } + } + + hash_outgoing_message->generate_r1cs_witness(); + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + hash_incoming_messages[i].generate_r1cs_witness(); + unpack_commitment_and_incoming_message_digests[i].generate_r1cs_witness_from_packed(); + } + + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + proof[i].generate_r1cs_witness(translation_step_proofs[i]); + verifier[i].generate_r1cs_witness(); + } + +#ifdef DEBUG + get_circuit(); // force generating constraints + assert(this->pb.is_satisfied()); +#endif +} + +template +size_t mp_compliance_step_pcd_circuit_maker::field_logsize() +{ + return Fr::size_in_bits(); +} + +template +size_t mp_compliance_step_pcd_circuit_maker::field_capacity() +{ + return Fr::capacity(); +} + +template +size_t mp_compliance_step_pcd_circuit_maker::input_size_in_elts() +{ + const size_t digest_size = CRH_with_field_out_gadget::get_digest_len(); + return digest_size; +} + +template +size_t mp_compliance_step_pcd_circuit_maker::input_capacity_in_bits() +{ + return input_size_in_elts() * field_capacity(); +} + +template +size_t mp_compliance_step_pcd_circuit_maker::input_size_in_bits() +{ + return input_size_in_elts() * field_logsize(); +} + +template +mp_translation_step_pcd_circuit_maker::mp_translation_step_pcd_circuit_maker(const r1cs_ppzksnark_verification_key > &compliance_step_vk) +{ + /* allocate input of the translation MP_PCD circuit */ + mp_translation_step_pcd_circuit_input.allocate(pb, input_size_in_elts(), "mp_translation_step_pcd_circuit_input"); + + /* unpack translation step MP_PCD circuit input */ + unpacked_mp_translation_step_pcd_circuit_input.allocate(pb, mp_compliance_step_pcd_circuit_maker >::input_size_in_bits(), "unpacked_mp_translation_step_pcd_circuit_input"); + unpack_mp_translation_step_pcd_circuit_input.reset(new multipacking_gadget(pb, unpacked_mp_translation_step_pcd_circuit_input, mp_translation_step_pcd_circuit_input, field_capacity(), "unpack_mp_translation_step_pcd_circuit_input")); + + /* prepare arguments for the verifier */ + hardcoded_compliance_step_vk.reset(new r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable(pb, compliance_step_vk, "hardcoded_compliance_step_vk")); + proof.reset(new r1cs_ppzksnark_proof_variable(pb, "proof")); + + /* verify previous proof */ + online_verifier.reset(new r1cs_ppzksnark_online_verifier_gadget(pb, + *hardcoded_compliance_step_vk, + unpacked_mp_translation_step_pcd_circuit_input, + mp_compliance_step_pcd_circuit_maker >::field_logsize(), + *proof, + ONE, // must always accept + "verifier")); + + pb.set_input_sizes(input_size_in_elts()); +} + +template +void mp_translation_step_pcd_circuit_maker::generate_r1cs_constraints() +{ + PROFILE_CONSTRAINTS(pb, "repacking: unpack circuit input") + { + unpack_mp_translation_step_pcd_circuit_input->generate_r1cs_constraints(true); + } + + PROFILE_CONSTRAINTS(pb, "verifier for compliance proofs") + { + PROFILE_CONSTRAINTS(pb, "check that proof lies on the curve") + { + proof->generate_r1cs_constraints(); + } + + online_verifier->generate_r1cs_constraints(); + } + + PRINT_CONSTRAINT_PROFILING(); + print_indent(); printf("* Number of constraints in mp_translation_step_pcd_circuit: %zu\n", pb.num_constraints()); +} + +template +r1cs_constraint_system > mp_translation_step_pcd_circuit_maker::get_circuit() const +{ + return pb.get_constraint_system(); +} + +template +void mp_translation_step_pcd_circuit_maker::generate_r1cs_witness(const r1cs_primary_input > translation_step_input, + const r1cs_ppzksnark_proof > &prev_proof) +{ + this->pb.clear_values(); + mp_translation_step_pcd_circuit_input.fill_with_field_elements(pb, translation_step_input); + unpack_mp_translation_step_pcd_circuit_input->generate_r1cs_witness_from_packed(); + + proof->generate_r1cs_witness(prev_proof); + online_verifier->generate_r1cs_witness(); + +#ifdef DEBUG + get_circuit(); // force generating constraints + assert(this->pb.is_satisfied()); +#endif +} + +template +r1cs_primary_input > mp_translation_step_pcd_circuit_maker::get_primary_input() const +{ + return pb.primary_input(); +} + +template +r1cs_auxiliary_input > mp_translation_step_pcd_circuit_maker::get_auxiliary_input() const +{ + return pb.auxiliary_input(); +} + +template +size_t mp_translation_step_pcd_circuit_maker::field_logsize() +{ + return Fr::size_in_bits(); +} + +template +size_t mp_translation_step_pcd_circuit_maker::field_capacity() +{ + return Fr::capacity(); +} + +template +size_t mp_translation_step_pcd_circuit_maker::input_size_in_elts() +{ + return div_ceil(mp_compliance_step_pcd_circuit_maker >::input_size_in_bits(), mp_translation_step_pcd_circuit_maker::field_capacity()); +} + +template +size_t mp_translation_step_pcd_circuit_maker::input_capacity_in_bits() +{ + return input_size_in_elts() * field_capacity(); +} + +template +size_t mp_translation_step_pcd_circuit_maker::input_size_in_bits() +{ + return input_size_in_elts() * field_logsize(); +} + +template +r1cs_primary_input > get_mp_compliance_step_pcd_circuit_input(const set_commitment &commitment_to_translation_step_r1cs_vks, + const r1cs_pcd_compliance_predicate_primary_input > &primary_input) +{ + enter_block("Call to get_mp_compliance_step_pcd_circuit_input"); + typedef Fr FieldT; + + const r1cs_variable_assignment outgoing_message_as_va = primary_input.outgoing_message->as_r1cs_variable_assignment(); + bit_vector msg_bits; + for (const FieldT &elt : outgoing_message_as_va) + { + const bit_vector elt_bits = convert_field_element_to_bit_vector(elt); + msg_bits.insert(msg_bits.end(), elt_bits.begin(), elt_bits.end()); + } + + bit_vector block; + block.insert(block.end(), commitment_to_translation_step_r1cs_vks.begin(), commitment_to_translation_step_r1cs_vks.end()); + block.insert(block.end(), msg_bits.begin(), msg_bits.end()); + + enter_block("Sample CRH randomness"); + CRH_with_field_out_gadget::sample_randomness(block.size()); + leave_block("Sample CRH randomness"); + + const std::vector digest = CRH_with_field_out_gadget::get_hash(block); + leave_block("Call to get_mp_compliance_step_pcd_circuit_input"); + + return digest; +} + +template +r1cs_primary_input > get_mp_translation_step_pcd_circuit_input(const set_commitment &commitment_to_translation_step_r1cs_vks, + const r1cs_pcd_compliance_predicate_primary_input > > &primary_input) +{ + enter_block("Call to get_mp_translation_step_pcd_circuit_input"); + typedef Fr FieldT; + + const std::vector > > mp_compliance_step_pcd_circuit_input = get_mp_compliance_step_pcd_circuit_input >(commitment_to_translation_step_r1cs_vks, primary_input); + bit_vector mp_compliance_step_pcd_circuit_input_bits; + for (const Fr > &elt : mp_compliance_step_pcd_circuit_input) + { + const bit_vector elt_bits = convert_field_element_to_bit_vector > >(elt); + mp_compliance_step_pcd_circuit_input_bits.insert(mp_compliance_step_pcd_circuit_input_bits.end(), elt_bits.begin(), elt_bits.end()); + } + + mp_compliance_step_pcd_circuit_input_bits.resize(mp_translation_step_pcd_circuit_maker::input_capacity_in_bits(), false); + + const r1cs_primary_input result = pack_bit_vector_into_field_element_vector(mp_compliance_step_pcd_circuit_input_bits, mp_translation_step_pcd_circuit_maker::field_capacity()); + leave_block("Call to get_mp_translation_step_pcd_circuit_input"); + + return result; +} + +} // libsnark + +#endif // MP_PCD_CIRCUITS_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/profiling/profile_r1cs_mp_ppzkpcd.cpp b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/profiling/profile_r1cs_mp_ppzkpcd.cpp new file mode 100644 index 0000000..a7467c7 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/profiling/profile_r1cs_mp_ppzkpcd.cpp @@ -0,0 +1,35 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include "common/default_types/r1cs_ppzkpcd_pp.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/examples/run_r1cs_mp_ppzkpcd.hpp" + +using namespace libsnark; + +template +void profile_tally(const size_t arity, const size_t max_layer) +{ + const size_t wordsize = 32; + const bool test_serialization = true; + const bool test_multi_type = true; + const bool test_same_type_optimization = false; + const bool bit = run_r1cs_mp_ppzkpcd_tally_example(wordsize, arity, max_layer, test_serialization, test_multi_type, test_same_type_optimization); + assert(bit); +} + +int main(void) +{ + typedef default_r1cs_ppzkpcd_pp PCD_pp; + + start_profiling(); + PCD_pp::init_public_params(); + + const size_t arity = 2; + const size_t max_layer = 2; + + profile_tally(arity, max_layer); +} diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd.hpp b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd.hpp new file mode 100644 index 0000000..0dc0fc9 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd.hpp @@ -0,0 +1,328 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a *multi-predicate* ppzkPCD for R1CS. + + This includes: + - class for proving key + - class for verification key + - class for processed verification key + - class for key pair (proving key & verification key) + - class for proof + - generator algorithm + - prover algorithm + - verifier algorithm + - online verifier algorithm + + The implementation follows, extends, and optimizes the approach described + in \[CTV15]. Thus, PCD is constructed from two "matched" ppzkSNARKs for R1CS. + + Acronyms: + + "R1CS" = "Rank-1 Constraint Systems" + "ppzkSNARK" = "PreProcessing Zero-Knowledge Succinct Non-interactive ARgument of Knowledge" + "ppzkPCD" = "Pre-Processing Zero-Knowledge Proof-Carrying Data" + + References: + + \[CTV15]: + "Cluster Computing in Zero Knowledge", + Alessandro Chiesa, Eran Tromer, Madars Virza, + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_MP_PPZKPCD_HPP_ +#define R1CS_MP_PPZKPCD_HPP_ + +#include +#include + +#include "common/data_structures/set_commitment.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/ppzkpcd_compliance_predicate.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd_params.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" + +namespace libsnark { + +/******************************** Proving key ********************************/ + +template +class r1cs_mp_ppzkpcd_proving_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_mp_ppzkpcd_proving_key &pk); + +template +std::istream& operator>>(std::istream &in, r1cs_mp_ppzkpcd_proving_key &pk); + +/** + * A proving key for the R1CS (multi-predicate) ppzkPCD. + */ +template +class r1cs_mp_ppzkpcd_proving_key { +public: + typedef typename PCD_ppT::curve_A_pp A_pp; + typedef typename PCD_ppT::curve_B_pp B_pp; + + std::vector > compliance_predicates; + + std::vector > compliance_step_r1cs_pks; + std::vector > translation_step_r1cs_pks; + + std::vector > compliance_step_r1cs_vks; + std::vector > translation_step_r1cs_vks; + + set_commitment commitment_to_translation_step_r1cs_vks; + std::vector compliance_step_r1cs_vk_membership_proofs; + + std::map compliance_predicate_name_to_idx; + + r1cs_mp_ppzkpcd_proving_key() {}; + r1cs_mp_ppzkpcd_proving_key(const r1cs_mp_ppzkpcd_proving_key &other) = default; + r1cs_mp_ppzkpcd_proving_key(r1cs_mp_ppzkpcd_proving_key &&other) = default; + r1cs_mp_ppzkpcd_proving_key(const std::vector > &compliance_predicates, + const std::vector > &compliance_step_r1cs_pk, + const std::vector > &translation_step_r1cs_pk, + const std::vector > &compliance_step_r1cs_vk, + const std::vector > &translation_step_r1cs_vk, + const set_commitment &commitment_to_translation_step_r1cs_vks, + const std::vector &compliance_step_r1cs_vk_membership_proofs, + const std::map &compliance_predicate_name_to_idx) : + compliance_predicates(compliance_predicates), + compliance_step_r1cs_pks(compliance_step_r1cs_pks), + translation_step_r1cs_pks(translation_step_r1cs_pks), + compliance_step_r1cs_vks(compliance_step_r1cs_vks), + translation_step_r1cs_vks(translation_step_r1cs_vks), + commitment_to_translation_step_r1cs_vks(commitment_to_translation_step_r1cs_vks), + compliance_step_r1cs_vk_membership_proofs(compliance_step_r1cs_vk_membership_proofs), + compliance_predicate_name_to_idx(compliance_predicate_name_to_idx) + {} + + r1cs_mp_ppzkpcd_proving_key& operator=(const r1cs_mp_ppzkpcd_proving_key &other) = default; + + size_t size_in_bits() const; + + bool is_well_formed() const; + + bool operator==(const r1cs_mp_ppzkpcd_proving_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_mp_ppzkpcd_proving_key &pk); + friend std::istream& operator>> (std::istream &in, r1cs_mp_ppzkpcd_proving_key &pk); +}; + + +/******************************* Verification key ****************************/ + +template +class r1cs_mp_ppzkpcd_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_mp_ppzkpcd_verification_key &vk); + +template +std::istream& operator>>(std::istream &in, r1cs_mp_ppzkpcd_verification_key &vk); + +/** + * A verification key for the R1CS (multi-predicate) ppzkPCD. + */ +template +class r1cs_mp_ppzkpcd_verification_key { +public: + typedef typename PCD_ppT::curve_A_pp A_pp; + typedef typename PCD_ppT::curve_B_pp B_pp; + + std::vector > compliance_step_r1cs_vks; + std::vector > translation_step_r1cs_vks; + set_commitment commitment_to_translation_step_r1cs_vks; + + r1cs_mp_ppzkpcd_verification_key() = default; + r1cs_mp_ppzkpcd_verification_key(const r1cs_mp_ppzkpcd_verification_key &other) = default; + r1cs_mp_ppzkpcd_verification_key(r1cs_mp_ppzkpcd_verification_key &&other) = default; + r1cs_mp_ppzkpcd_verification_key(const std::vector > &compliance_step_r1cs_vks, + const std::vector > &translation_step_r1cs_vks, + const set_commitment &commitment_to_translation_step_r1cs_vks) : + compliance_step_r1cs_vks(compliance_step_r1cs_vks), + translation_step_r1cs_vks(translation_step_r1cs_vks), + commitment_to_translation_step_r1cs_vks(commitment_to_translation_step_r1cs_vks) + {} + + r1cs_mp_ppzkpcd_verification_key& operator=(const r1cs_mp_ppzkpcd_verification_key &other) = default; + + size_t size_in_bits() const; + + bool operator==(const r1cs_mp_ppzkpcd_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_mp_ppzkpcd_verification_key &vk); + friend std::istream& operator>> (std::istream &in, r1cs_mp_ppzkpcd_verification_key &vk); +}; + + +/************************* Processed verification key **************************/ + +template +class r1cs_mp_ppzkpcd_processed_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_mp_ppzkpcd_processed_verification_key &pvk); + +template +std::istream& operator>>(std::istream &in, r1cs_mp_ppzkpcd_processed_verification_key &pvk); + +/** + * A processed verification key for the R1CS (multi-predicate) ppzkPCD. + * + * Compared to a (non-processed) verification key, a processed verification key + * contains a small constant amount of additional pre-computed information that + * enables a faster verification time. + */ +template +class r1cs_mp_ppzkpcd_processed_verification_key { +public: + typedef typename PCD_ppT::curve_A_pp A_pp; + typedef typename PCD_ppT::curve_B_pp B_pp; + + std::vector > compliance_step_r1cs_pvks; + std::vector > translation_step_r1cs_pvks; + set_commitment commitment_to_translation_step_r1cs_vks; + + r1cs_mp_ppzkpcd_processed_verification_key() = default; + r1cs_mp_ppzkpcd_processed_verification_key(const r1cs_mp_ppzkpcd_processed_verification_key &other) = default; + r1cs_mp_ppzkpcd_processed_verification_key(r1cs_mp_ppzkpcd_processed_verification_key &&other) = default; + r1cs_mp_ppzkpcd_processed_verification_key(std::vector > &&compliance_step_r1cs_pvks, + std::vector > &&translation_step_r1cs_pvks, + const set_commitment &commitment_to_translation_step_r1cs_vks) : + compliance_step_r1cs_pvks(std::move(compliance_step_r1cs_pvks)), + translation_step_r1cs_pvks(std::move(translation_step_r1cs_pvks)), + commitment_to_translation_step_r1cs_vks(commitment_to_translation_step_r1cs_vks) + {}; + + r1cs_mp_ppzkpcd_processed_verification_key& operator=(const r1cs_mp_ppzkpcd_processed_verification_key &other) = default; + + size_t size_in_bits() const; + + bool operator==(const r1cs_mp_ppzkpcd_processed_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_mp_ppzkpcd_processed_verification_key &pvk); + friend std::istream& operator>> (std::istream &in, r1cs_mp_ppzkpcd_processed_verification_key &pvk); +}; + + +/********************************** Key pair *********************************/ + +/** + * A key pair for the R1CS (multi-predicate) ppzkPC, which consists of a proving key and a verification key. + */ +template +class r1cs_mp_ppzkpcd_keypair { +public: + r1cs_mp_ppzkpcd_proving_key pk; + r1cs_mp_ppzkpcd_verification_key vk; + + r1cs_mp_ppzkpcd_keypair() = default; + r1cs_mp_ppzkpcd_keypair(r1cs_mp_ppzkpcd_keypair &&other) = default; + r1cs_mp_ppzkpcd_keypair(r1cs_mp_ppzkpcd_proving_key &&pk, + r1cs_mp_ppzkpcd_verification_key &&vk) : + pk(std::move(pk)), + vk(std::move(vk)) + {}; +}; + + +/*********************************** Proof ***********************************/ + +template +class r1cs_mp_ppzkpcd_proof; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_mp_ppzkpcd_proof &proof); + +template +std::istream& operator>>(std::istream &in, r1cs_mp_ppzkpcd_proof &proof); + +/** + * A proof for the R1CS (multi-predicate) ppzkPCD. + */ +template +class r1cs_mp_ppzkpcd_proof { +public: + size_t compliance_predicate_idx; + r1cs_ppzksnark_proof r1cs_proof; + + r1cs_mp_ppzkpcd_proof() = default; + r1cs_mp_ppzkpcd_proof(const size_t compliance_predicate_idx, + const r1cs_ppzksnark_proof &r1cs_proof) : + compliance_predicate_idx(compliance_predicate_idx), + r1cs_proof(r1cs_proof) + {} + + size_t size_in_bits() const; + + bool operator==(const r1cs_mp_ppzkpcd_proof &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_mp_ppzkpcd_proof &proof); + friend std::istream& operator>> (std::istream &in, r1cs_mp_ppzkpcd_proof &proof); +}; + + +/***************************** Main algorithms *******************************/ + +/** + * A generator algorithm for the R1CS (multi-predicate) ppzkPCD. + * + * Given a vector of compliance predicates, this algorithm produces proving and verification keys for the vector. + */ +template +r1cs_mp_ppzkpcd_keypair r1cs_mp_ppzkpcd_generator(const std::vector > &compliance_predicates); + +/** + * A prover algorithm for the R1CS (multi-predicate) ppzkPCD. + * + * Given a proving key, name of chosen compliance predicate, inputs for the + * compliance predicate, and proofs for the predicate's input messages, this + * algorithm produces a proof (of knowledge) that attests to the compliance of + * the output message. + */ +template +r1cs_mp_ppzkpcd_proof r1cs_mp_ppzkpcd_prover(const r1cs_mp_ppzkpcd_proving_key &pk, + const size_t compliance_predicate_name, + const r1cs_mp_ppzkpcd_primary_input &primary_input, + const r1cs_mp_ppzkpcd_auxiliary_input &auxiliary_input, + const std::vector > &incoming_proofs); + +/* + Below are two variants of verifier algorithm for the R1CS (multi-predicate) ppzkPCD. + + These are the two cases that arise from whether the verifier accepts a + (non-processed) verification key or, instead, a processed verification key. + In the latter case, we call the algorithm an "online verifier". +*/ + +/** + * A verifier algorithm for the R1CS (multi-predicate) ppzkPCD that + * accepts a non-processed verification key. + */ +template +bool r1cs_mp_ppzkpcd_verifier(const r1cs_mp_ppzkpcd_verification_key &vk, + const r1cs_mp_ppzkpcd_primary_input &primary_input, + const r1cs_mp_ppzkpcd_proof &proof); + +/** + * Convert a (non-processed) verification key into a processed verification key. + */ +template +r1cs_mp_ppzkpcd_processed_verification_key r1cs_mp_ppzkpcd_process_vk(const r1cs_mp_ppzkpcd_verification_key &vk); + +/** + * A verifier algorithm for the R1CS (multi-predicate) ppzkPCD that + * accepts a processed verification key. + */ +template +bool r1cs_mp_ppzkpcd_online_verifier(const r1cs_mp_ppzkpcd_processed_verification_key &pvk, + const r1cs_mp_ppzkpcd_primary_input &primary_input, + const r1cs_mp_ppzkpcd_proof &proof); + +} // libsnark + +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd.tcc" + +#endif // R1CS_MP_PPZKPCD_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd.tcc b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd.tcc new file mode 100644 index 0000000..407a612 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd.tcc @@ -0,0 +1,517 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a *multi-predicate* ppzkPCD for R1CS. + + See r1cs_mp_ppzkpcd.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_MP_PPZKPCD_TCC_ +#define R1CS_MP_PPZKPCD_TCC_ + +#include +#include +#include + +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/mp_pcd_circuits.hpp" + +namespace libsnark { + +template +size_t r1cs_mp_ppzkpcd_proving_key::size_in_bits() const +{ + const size_t num_predicates = compliance_predicates.size(); + + size_t result = 0; + for (size_t i = 0; i < num_predicates; ++i) + { + result += (compliance_predicates[i].size_in_bits() + + compliance_step_r1cs_pks[i].size_in_bits() + + translation_step_r1cs_pks[i].size_in_bits() + + compliance_step_r1cs_vks[i].size_in_bits() + + translation_step_r1cs_vks[i].size_in_bits() + + compliance_step_r1cs_vk_membership_proofs[i].size_in_bits()); + } + result += commitment_to_translation_step_r1cs_vks.size(); + + return result; +} + +template +bool r1cs_mp_ppzkpcd_proving_key::is_well_formed() const +{ + const size_t num_predicates = compliance_predicates.size(); + + bool result; + result = result && (compliance_step_r1cs_pks.size() == num_predicates); + result = result && (translation_step_r1cs_pks.size() == num_predicates); + result = result && (compliance_step_r1cs_vks.size() == num_predicates); + result = result && (translation_step_r1cs_vks.size() == num_predicates); + result = result && (compliance_step_r1cs_vk_membership_proofs.size() == num_predicates); + + return result; +} + +template +bool r1cs_mp_ppzkpcd_proving_key::operator==(const r1cs_mp_ppzkpcd_proving_key &other) const +{ + return (this->compliance_predicates == other.compliance_predicates && + this->compliance_step_r1cs_pks == other.compliance_step_r1cs_pks && + this->translation_step_r1cs_pks == other.translation_step_r1cs_pks && + this->compliance_step_r1cs_vks == other.compliance_step_r1cs_vks && + this->translation_step_r1cs_vks == other.translation_step_r1cs_vks && + this->commitment_to_translation_step_r1cs_vks == other.commitment_to_translation_step_r1cs_vks && + this->compliance_step_r1cs_vk_membership_proofs == other.compliance_step_r1cs_vk_membership_proofs && + this->compliance_predicate_name_to_idx == other.compliance_predicate_name_to_idx); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_mp_ppzkpcd_proving_key &pk) +{ + out << pk.compliance_predicates; + out << pk.compliance_step_r1cs_pks; + out << pk.translation_step_r1cs_pks; + out << pk.compliance_step_r1cs_vks; + out << pk.translation_step_r1cs_vks; + output_bool_vector(out, pk.commitment_to_translation_step_r1cs_vks); + out << pk.compliance_step_r1cs_vk_membership_proofs; + out << pk.compliance_predicate_name_to_idx; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_mp_ppzkpcd_proving_key &pk) +{ + in >> pk.compliance_predicates; + in >> pk.compliance_step_r1cs_pks; + in >> pk.translation_step_r1cs_pks; + in >> pk.compliance_step_r1cs_vks; + in >> pk.translation_step_r1cs_vks; + input_bool_vector(in, pk.commitment_to_translation_step_r1cs_vks); + in >> pk.compliance_step_r1cs_vk_membership_proofs; + in >> pk.compliance_predicate_name_to_idx; + + return in; +} + +template +size_t r1cs_mp_ppzkpcd_verification_key::size_in_bits() const +{ + const size_t num_predicates = compliance_step_r1cs_vks.size(); + + size_t result = 0; + for (size_t i = 0; i < num_predicates; ++i) + { + result += (compliance_step_r1cs_vks[i].size_in_bits() + + translation_step_r1cs_vks[i].size_in_bits()); + } + + result += commitment_to_translation_step_r1cs_vks.size(); + + return result; +} + +template +bool r1cs_mp_ppzkpcd_verification_key::operator==(const r1cs_mp_ppzkpcd_verification_key &other) const +{ + return (this->compliance_step_r1cs_vks == other.compliance_step_r1cs_vks && + this->translation_step_r1cs_vks == other.translation_step_r1cs_vks && + this->commitment_to_translation_step_r1cs_vks == other.commitment_to_translation_step_r1cs_vks); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_mp_ppzkpcd_verification_key &vk) +{ + out << vk.compliance_step_r1cs_vks; + out << vk.translation_step_r1cs_vks; + output_bool_vector(out, vk.commitment_to_translation_step_r1cs_vks); + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_mp_ppzkpcd_verification_key &vk) +{ + in >> vk.compliance_step_r1cs_vks; + in >> vk.translation_step_r1cs_vks; + input_bool_vector(in, vk.commitment_to_translation_step_r1cs_vks); + + return in; +} + +template +size_t r1cs_mp_ppzkpcd_processed_verification_key::size_in_bits() const +{ + const size_t num_predicates = compliance_step_r1cs_pvks.size(); + + size_t result = 0; + for (size_t i = 0; i < num_predicates; ++i) + { + result += (compliance_step_r1cs_pvks[i].size_in_bits() + + translation_step_r1cs_pvks[i].size_in_bits()); + } + + result += commitment_to_translation_step_r1cs_vks.size(); + + return result; +} + +template +bool r1cs_mp_ppzkpcd_processed_verification_key::operator==(const r1cs_mp_ppzkpcd_processed_verification_key &other) const +{ + return (this->compliance_step_r1cs_pvks == other.compliance_step_r1cs_pvks && + this->translation_step_r1cs_pvks == other.translation_step_r1cs_pvks && + this->commitment_to_translation_step_r1cs_vks == other.commitment_to_translation_step_r1cs_vks); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_mp_ppzkpcd_processed_verification_key &pvk) +{ + out << pvk.compliance_step_r1cs_pvks; + out << pvk.translation_step_r1cs_pvks; + output_bool_vector(out, pvk.commitment_to_translation_step_r1cs_vks); + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_mp_ppzkpcd_processed_verification_key &pvk) +{ + in >> pvk.compliance_step_r1cs_pvks; + in >> pvk.translation_step_r1cs_pvks; + input_bool_vector(in, pvk.commitment_to_translation_step_r1cs_vks); + + return in; +} + +template +bool r1cs_mp_ppzkpcd_proof::operator==(const r1cs_mp_ppzkpcd_proof &other) const +{ + return (this->compliance_predicate_idx == other.compliance_predicate_idx && + this->r1cs_proof == other.r1cs_proof); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_mp_ppzkpcd_proof &proof) +{ + out << proof.compliance_predicate_idx << "\n"; + out << proof.r1cs_proof; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_mp_ppzkpcd_proof &proof) +{ + in >> proof.compliance_predicate_idx; + consume_newline(in); + in >> proof.r1cs_proof; + + return in; +} + +template +r1cs_mp_ppzkpcd_keypair r1cs_mp_ppzkpcd_generator(const std::vector > &compliance_predicates) +{ + assert(Fr::mod == Fq::mod); + assert(Fq::mod == Fr::mod); + + typedef typename PCD_ppT::curve_A_pp curve_A_pp; + typedef typename PCD_ppT::curve_B_pp curve_B_pp; + + typedef Fr FieldT_A; + typedef Fr FieldT_B; + + enter_block("Call to r1cs_mp_ppzkpcd_generator"); + + r1cs_mp_ppzkpcd_keypair keypair; + const size_t translation_input_size = mp_translation_step_pcd_circuit_maker::input_size_in_elts(); + const size_t vk_size_in_bits = r1cs_ppzksnark_verification_key_variable::size_in_bits(translation_input_size); + printf("%zu %zu\n", translation_input_size, vk_size_in_bits); + + set_commitment_accumulator > all_translation_vks(compliance_predicates.size(), vk_size_in_bits); + + enter_block("Perform type checks"); + std::map type_counts; + + for (auto &cp : compliance_predicates) + { + type_counts[cp.type] += 1; + } + + for (auto &cp : compliance_predicates) + { + if (cp.relies_on_same_type_inputs) + { + for (size_t type : cp.accepted_input_types) + { + assert(type_counts[type] == 1); /* each of accepted_input_types must be unique */ + } + } + else + { + assert(cp.accepted_input_types.empty()); + } + } + leave_block("Perform type checks"); + + for (size_t i = 0; i < compliance_predicates.size(); ++i) + { + enter_block(FORMAT("", "Process predicate %zu (with name %zu and type %zu)", i, compliance_predicates[i].name, compliance_predicates[i].type)); + assert(compliance_predicates[i].is_well_formed()); + + enter_block("Construct compliance step PCD circuit"); + mp_compliance_step_pcd_circuit_maker mp_compliance_step_pcd_circuit(compliance_predicates[i], compliance_predicates.size()); + mp_compliance_step_pcd_circuit.generate_r1cs_constraints(); + r1cs_constraint_system mp_compliance_step_pcd_circuit_cs = mp_compliance_step_pcd_circuit.get_circuit(); + leave_block("Construct compliance step PCD circuit"); + + enter_block("Generate key pair for compliance step PCD circuit"); + r1cs_ppzksnark_keypair mp_compliance_step_keypair = r1cs_ppzksnark_generator(mp_compliance_step_pcd_circuit_cs); + leave_block("Generate key pair for compliance step PCD circuit"); + + enter_block("Construct translation step PCD circuit"); + mp_translation_step_pcd_circuit_maker mp_translation_step_pcd_circuit(mp_compliance_step_keypair.vk); + mp_translation_step_pcd_circuit.generate_r1cs_constraints(); + r1cs_constraint_system mp_translation_step_pcd_circuit_cs = mp_translation_step_pcd_circuit.get_circuit(); + leave_block("Construct translation step PCD circuit"); + + enter_block("Generate key pair for translation step PCD circuit"); + r1cs_ppzksnark_keypair mp_translation_step_keypair = r1cs_ppzksnark_generator(mp_translation_step_pcd_circuit_cs); + leave_block("Generate key pair for translation step PCD circuit"); + + enter_block("Augment set of translation step verification keys"); + const bit_vector vk_bits = r1cs_ppzksnark_verification_key_variable::get_verification_key_bits(mp_translation_step_keypair.vk); + all_translation_vks.add(vk_bits); + leave_block("Augment set of translation step verification keys"); + + enter_block("Update r1cs_mp_ppzkpcd keypair"); + keypair.pk.compliance_predicates.emplace_back(compliance_predicates[i]); + keypair.pk.compliance_step_r1cs_pks.emplace_back(mp_compliance_step_keypair.pk); + keypair.pk.translation_step_r1cs_pks.emplace_back(mp_translation_step_keypair.pk); + keypair.pk.compliance_step_r1cs_vks.emplace_back(mp_compliance_step_keypair.vk); + keypair.pk.translation_step_r1cs_vks.emplace_back(mp_translation_step_keypair.vk); + const size_t cp_name = compliance_predicates[i].name; + assert(keypair.pk.compliance_predicate_name_to_idx.find(cp_name) == keypair.pk.compliance_predicate_name_to_idx.end()); // all names must be distinct + keypair.pk.compliance_predicate_name_to_idx[cp_name] = i; + + keypair.vk.compliance_step_r1cs_vks.emplace_back(mp_compliance_step_keypair.vk); + keypair.vk.translation_step_r1cs_vks.emplace_back(mp_translation_step_keypair.vk); + leave_block("Update r1cs_mp_ppzkpcd keypair"); + + leave_block(FORMAT("", "Process predicate %zu (with name %zu and type %zu)", i, compliance_predicates[i].name, compliance_predicates[i].type)); + } + + enter_block("Compute set commitment and corresponding membership proofs"); + const set_commitment cm = all_translation_vks.get_commitment(); + keypair.pk.commitment_to_translation_step_r1cs_vks = cm; + keypair.vk.commitment_to_translation_step_r1cs_vks = cm; + for (size_t i = 0; i < compliance_predicates.size(); ++i) + { + const bit_vector vk_bits = r1cs_ppzksnark_verification_key_variable::get_verification_key_bits(keypair.vk.translation_step_r1cs_vks[i]); + const set_membership_proof proof = all_translation_vks.get_membership_proof(vk_bits); + + keypair.pk.compliance_step_r1cs_vk_membership_proofs.emplace_back(proof); + } + leave_block("Compute set commitment and corresponding membership proofs"); + + print_indent(); print_mem("in generator"); + leave_block("Call to r1cs_mp_ppzkpcd_generator"); + + return keypair; +} + +template +r1cs_mp_ppzkpcd_proof r1cs_mp_ppzkpcd_prover(const r1cs_mp_ppzkpcd_proving_key &pk, + const size_t compliance_predicate_name, + const r1cs_mp_ppzkpcd_primary_input &primary_input, + const r1cs_mp_ppzkpcd_auxiliary_input &auxiliary_input, + const std::vector > &prev_proofs) +{ + typedef typename PCD_ppT::curve_A_pp curve_A_pp; + typedef typename PCD_ppT::curve_B_pp curve_B_pp; + + typedef Fr FieldT_A; + typedef Fr FieldT_B; + + enter_block("Call to r1cs_mp_ppzkpcd_prover"); + +#ifdef DEBUG + printf("Compliance predicate name: %zu\n", compliance_predicate_name); +#endif + auto it = pk.compliance_predicate_name_to_idx.find(compliance_predicate_name); + assert(it != pk.compliance_predicate_name_to_idx.end()); + const size_t compliance_predicate_idx = it->second; + +#ifdef DEBUG + printf("Outgoing message:\n"); + primary_input.outgoing_message->print(); +#endif + + enter_block("Prove compliance step"); + assert(compliance_predicate_idx < pk.compliance_predicates.size()); + assert(prev_proofs.size() <= pk.compliance_predicates[compliance_predicate_idx].max_arity); + + const size_t arity = prev_proofs.size(); + const size_t max_arity = pk.compliance_predicates[compliance_predicate_idx].max_arity; + + if (pk.compliance_predicates[compliance_predicate_idx].relies_on_same_type_inputs) + { + const size_t input_predicate_idx = prev_proofs[0].compliance_predicate_idx; + for (size_t i = 1; i < arity; ++i) + { + assert(prev_proofs[i].compliance_predicate_idx == input_predicate_idx); + } + } + + std::vector > padded_proofs(max_arity); + for (size_t i = 0; i < arity; ++i) + { + padded_proofs[i] = prev_proofs[i].r1cs_proof; + } + + std::vector > translation_step_vks; + std::vector membership_proofs; + + for (size_t i = 0; i < arity; ++i) + { + const size_t input_predicate_idx = prev_proofs[i].compliance_predicate_idx; + translation_step_vks.emplace_back(pk.translation_step_r1cs_vks[input_predicate_idx]); + membership_proofs.emplace_back(pk.compliance_step_r1cs_vk_membership_proofs[input_predicate_idx]); + +#ifdef DEBUG + if (auxiliary_input.incoming_messages[i]->type != 0) + { + printf("check proof for message %zu\n", i); + const r1cs_primary_input translated_msg = get_mp_translation_step_pcd_circuit_input(pk.commitment_to_translation_step_r1cs_vks, + auxiliary_input.incoming_messages[i]); + const bool bit = r1cs_ppzksnark_verifier_strong_IC(translation_step_vks[i], translated_msg, padded_proofs[i]); + assert(bit); + } + else + { + printf("message %zu is base case\n", i); + } +#endif + } + + /* pad with dummy vks/membership proofs */ + for (size_t i = arity; i < max_arity; ++i) + { + printf("proof %zu will be a dummy\n", arity); + translation_step_vks.emplace_back(pk.translation_step_r1cs_vks[0]); + membership_proofs.emplace_back(pk.compliance_step_r1cs_vk_membership_proofs[0]); + } + + mp_compliance_step_pcd_circuit_maker mp_compliance_step_pcd_circuit(pk.compliance_predicates[compliance_predicate_idx], pk.compliance_predicates.size()); + + mp_compliance_step_pcd_circuit.generate_r1cs_witness(pk.commitment_to_translation_step_r1cs_vks, + translation_step_vks, + membership_proofs, + primary_input, + auxiliary_input, + padded_proofs); + + const r1cs_primary_input compliance_step_primary_input = mp_compliance_step_pcd_circuit.get_primary_input(); + const r1cs_auxiliary_input compliance_step_auxiliary_input = mp_compliance_step_pcd_circuit.get_auxiliary_input(); + const r1cs_ppzksnark_proof compliance_step_proof = r1cs_ppzksnark_prover(pk.compliance_step_r1cs_pks[compliance_predicate_idx], compliance_step_primary_input, compliance_step_auxiliary_input); + leave_block("Prove compliance step"); + +#ifdef DEBUG + const r1cs_primary_input compliance_step_input = get_mp_compliance_step_pcd_circuit_input(pk.commitment_to_translation_step_r1cs_vks, primary_input.outgoing_message); + const bool compliance_step_ok = r1cs_ppzksnark_verifier_strong_IC(pk.compliance_step_r1cs_vks[compliance_predicate_idx], compliance_step_input, compliance_step_proof); + assert(compliance_step_ok); +#endif + + enter_block("Prove translation step"); + mp_translation_step_pcd_circuit_maker mp_translation_step_pcd_circuit(pk.compliance_step_r1cs_vks[compliance_predicate_idx]); + + const r1cs_primary_input translation_step_primary_input = get_mp_translation_step_pcd_circuit_input(pk.commitment_to_translation_step_r1cs_vks, primary_input); + mp_translation_step_pcd_circuit.generate_r1cs_witness(translation_step_primary_input, compliance_step_proof); + const r1cs_auxiliary_input translation_step_auxiliary_input = mp_translation_step_pcd_circuit.get_auxiliary_input(); + + const r1cs_ppzksnark_proof translation_step_proof = r1cs_ppzksnark_prover(pk.translation_step_r1cs_pks[compliance_predicate_idx], translation_step_primary_input, translation_step_auxiliary_input); + + leave_block("Prove translation step"); + +#ifdef DEBUG + const bool translation_step_ok = r1cs_ppzksnark_verifier_strong_IC(pk.translation_step_r1cs_vks[compliance_predicate_idx], translation_step_primary_input, translation_step_proof); + assert(translation_step_ok); +#endif + + print_indent(); print_mem("in prover"); + leave_block("Call to r1cs_mp_ppzkpcd_prover"); + + r1cs_mp_ppzkpcd_proof result; + result.compliance_predicate_idx = compliance_predicate_idx; + result.r1cs_proof = translation_step_proof; + return result; +} + +template +bool r1cs_mp_ppzkpcd_online_verifier(const r1cs_mp_ppzkpcd_processed_verification_key &pvk, + const r1cs_mp_ppzkpcd_primary_input &primary_input, + const r1cs_mp_ppzkpcd_proof &proof) +{ + typedef typename PCD_ppT::curve_B_pp curve_B_pp; + + enter_block("Call to r1cs_mp_ppzkpcd_online_verifier"); + const r1cs_primary_input > r1cs_input = get_mp_translation_step_pcd_circuit_input(pvk.commitment_to_translation_step_r1cs_vks, primary_input); + const bool result = r1cs_ppzksnark_online_verifier_strong_IC(pvk.translation_step_r1cs_pvks[proof.compliance_predicate_idx], r1cs_input, proof.r1cs_proof); + + print_indent(); print_mem("in online verifier"); + leave_block("Call to r1cs_mp_ppzkpcd_online_verifier"); + return result; +} + +template +r1cs_mp_ppzkpcd_processed_verification_key r1cs_mp_ppzkpcd_process_vk(const r1cs_mp_ppzkpcd_verification_key &vk) +{ + typedef typename PCD_ppT::curve_A_pp curve_A_pp; + typedef typename PCD_ppT::curve_B_pp curve_B_pp; + + enter_block("Call to r1cs_mp_ppzkpcd_processed_verification_key"); + + r1cs_mp_ppzkpcd_processed_verification_key result; + result.commitment_to_translation_step_r1cs_vks = vk.commitment_to_translation_step_r1cs_vks; + + for (size_t i = 0; i < vk.compliance_step_r1cs_vks.size(); ++i) + { + const r1cs_ppzksnark_processed_verification_key compliance_step_r1cs_pvk = r1cs_ppzksnark_verifier_process_vk(vk.compliance_step_r1cs_vks[i]); + const r1cs_ppzksnark_processed_verification_key translation_step_r1cs_pvk = r1cs_ppzksnark_verifier_process_vk(vk.translation_step_r1cs_vks[i]); + + result.compliance_step_r1cs_pvks.emplace_back(compliance_step_r1cs_pvk); + result.translation_step_r1cs_pvks.emplace_back(translation_step_r1cs_pvk); + } + leave_block("Call to r1cs_mp_ppzkpcd_processed_verification_key"); + + return result; +} + + +template +bool r1cs_mp_ppzkpcd_verifier(const r1cs_mp_ppzkpcd_verification_key &vk, + const r1cs_mp_ppzkpcd_primary_input &primary_input, + const r1cs_mp_ppzkpcd_proof &proof) +{ + enter_block("Call to r1cs_mp_ppzkpcd_verifier"); + r1cs_mp_ppzkpcd_processed_verification_key pvk = r1cs_mp_ppzkpcd_process_vk(vk); + const bool result = r1cs_mp_ppzkpcd_online_verifier(pvk, primary_input, proof); + + print_indent(); print_mem("in verifier"); + leave_block("Call to r1cs_mp_ppzkpcd_verifier"); + return result; +} + + +} // libsnark + +#endif // R1CS_MP_PPZKPCD_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd_params.hpp b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd_params.hpp new file mode 100644 index 0000000..b2d9c58 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd_params.hpp @@ -0,0 +1,38 @@ +/** @file + ***************************************************************************** + + Parameters for *multi-predicate* ppzkPCD for R1CS. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_MP_PPZKPCD_PARAMS_HPP_ +#define R1CS_MP_PPZKPCD_PARAMS_HPP_ + +#include "algebra/curves/public_params.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_pcd_params.hpp" + +namespace libsnark { + +template +using r1cs_mp_ppzkpcd_compliance_predicate = r1cs_pcd_compliance_predicate >; + +template +using r1cs_mp_ppzkpcd_message = r1cs_pcd_message >; + +template +using r1cs_mp_ppzkpcd_local_data = r1cs_pcd_local_data >; + +template +using r1cs_mp_ppzkpcd_primary_input = r1cs_pcd_compliance_predicate_primary_input >; + +template +using r1cs_mp_ppzkpcd_auxiliary_input = r1cs_pcd_compliance_predicate_auxiliary_input >; + +} // libsnark + +#endif // R1CS_MP_PPZKPCD_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/tests/test_r1cs_mp_ppzkpcd.cpp b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/tests/test_r1cs_mp_ppzkpcd.cpp new file mode 100644 index 0000000..252e43b --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/tests/test_r1cs_mp_ppzkpcd.cpp @@ -0,0 +1,34 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include "common/default_types/r1cs_ppzkpcd_pp.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/examples/run_r1cs_mp_ppzkpcd.hpp" + +using namespace libsnark; + +template +void test_tally(const size_t arity, const size_t max_layer, const bool test_multi_type, const bool test_same_type_optimization) + +{ + const size_t wordsize = 32; + const bool test_serialization = true; + const bool bit = run_r1cs_mp_ppzkpcd_tally_example(wordsize, arity, max_layer, test_serialization, test_multi_type, test_same_type_optimization); + assert(bit); +} + +int main(void) +{ + start_profiling(); + default_r1cs_ppzkpcd_pp::init_public_params(); + + const size_t max_arity = 2; + const size_t max_layer = 2; + + test_tally(max_arity, max_layer, false, false); + test_tally(max_arity, max_layer, false, true); + test_tally(max_arity, max_layer, true, false); + test_tally(max_arity, max_layer, true, true); +} diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_pcd_params.hpp b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_pcd_params.hpp new file mode 100644 index 0000000..6f634a3 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_pcd_params.hpp @@ -0,0 +1,43 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef R1CS_PCD_PARAMS_HPP_ +#define R1CS_PCD_PARAMS_HPP_ + +#include +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.hpp" + +namespace libsnark { + +template +class r1cs_pcd_compliance_predicate_primary_input { +public: + std::shared_ptr > outgoing_message; + + r1cs_pcd_compliance_predicate_primary_input(const std::shared_ptr > &outgoing_message) : outgoing_message(outgoing_message) {} + r1cs_primary_input as_r1cs_primary_input() const; +}; + +template +class r1cs_pcd_compliance_predicate_auxiliary_input { +public: + std::vector > > incoming_messages; + std::shared_ptr > local_data; + r1cs_pcd_witness witness; + + r1cs_pcd_compliance_predicate_auxiliary_input(const std::vector > > &incoming_messages, + const std::shared_ptr > &local_data, + const r1cs_pcd_witness &witness) : + incoming_messages(incoming_messages), local_data(local_data), witness(witness) {} + + r1cs_auxiliary_input as_r1cs_auxiliary_input(const std::vector &incoming_message_payload_lengths) const; +}; + +} // libsnark + +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_pcd_params.tcc" + +#endif // R1CS_PCD_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_pcd_params.tcc b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_pcd_params.tcc new file mode 100644 index 0000000..5fc927d --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_pcd_params.tcc @@ -0,0 +1,51 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef R1CS_PCD_PARAMS_TCC_ +#define R1CS_PCD_PARAMS_TCC_ + +namespace libsnark { + +template +r1cs_primary_input r1cs_pcd_compliance_predicate_primary_input::as_r1cs_primary_input() const +{ + return outgoing_message->as_r1cs_variable_assignment(); +} + +template +r1cs_auxiliary_input r1cs_pcd_compliance_predicate_auxiliary_input::as_r1cs_auxiliary_input(const std::vector &incoming_message_payload_lengths) const +{ + const size_t arity = incoming_messages.size(); + + r1cs_auxiliary_input result; + result.emplace_back(FieldT(arity)); + + const size_t max_arity = incoming_message_payload_lengths.size(); + assert(arity <= max_arity); + + for (size_t i = 0; i < arity; ++i) + { + const r1cs_variable_assignment msg_as_r1cs_va = incoming_messages[i]->as_r1cs_variable_assignment(); + assert(msg_as_r1cs_va.size() == (1 + incoming_message_payload_lengths[i])); + result.insert(result.end(), msg_as_r1cs_va.begin(), msg_as_r1cs_va.end()); + } + + /* pad with dummy messages of appropriate size */ + for (size_t i = arity; i < max_arity; ++i) + { + result.resize(result.size() + (1 + incoming_message_payload_lengths[i]), FieldT::zero()); + } + + const r1cs_variable_assignment local_data_as_r1cs_va = local_data->as_r1cs_variable_assignment(); + result.insert(result.end(), local_data_as_r1cs_va.begin(), local_data_as_r1cs_va.end()); + result.insert(result.end(), witness.begin(), witness.end()); + + return result; +} + +} // libsnark + +#endif // R1CS_PCD_PARAMS_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/examples/run_r1cs_sp_ppzkpcd.hpp b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/examples/run_r1cs_sp_ppzkpcd.hpp new file mode 100644 index 0000000..1ccd3dd --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/examples/run_r1cs_sp_ppzkpcd.hpp @@ -0,0 +1,35 @@ +/** @file + ***************************************************************************** + + Declaration of functionality that runs the R1CS single-predicate ppzkPCD + for a compliance predicate example. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_R1CS_SP_PPZKPCD_HPP_ +#define RUN_R1CS_SP_PPZKPCD_HPP_ + +namespace libsnark { + +/** + * Runs the single-predicate ppzkPCD (generator, prover, and verifier) for the + * "tally compliance predicate", of a given wordsize, arity, and depth. + * + * Optionally, also test the serialization routines for keys and proofs. + * (This takes additional time.) + */ +template +bool run_r1cs_sp_ppzkpcd_tally_example(const size_t wordsize, + const size_t arity, + const size_t depth, + const bool test_serialization); + +} // libsnark + +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/examples/run_r1cs_sp_ppzkpcd.tcc" + +#endif // RUN_R1CS_SP_PPZKPCD_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/examples/run_r1cs_sp_ppzkpcd.tcc b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/examples/run_r1cs_sp_ppzkpcd.tcc new file mode 100644 index 0000000..42d0084 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/examples/run_r1cs_sp_ppzkpcd.tcc @@ -0,0 +1,151 @@ +/** @file + ***************************************************************************** + + Implementation of functionality that runs the R1CS single-predicate ppzkPCD + for a compliance predicate example. + + See run_r1cs_sp_ppzkpcd.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_R1CS_SP_PPZKPCD_TCC_ +#define RUN_R1CS_SP_PPZKPCD_TCC_ + +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd.hpp" + +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/examples/tally_cp.hpp" + +namespace libsnark { + +template +bool run_r1cs_sp_ppzkpcd_tally_example(const size_t wordsize, + const size_t arity, + const size_t depth, + const bool test_serialization) +{ + enter_block("Call to run_r1cs_sp_ppzkpcd_tally_example"); + + typedef Fr FieldT; + + bool all_accept = true; + + enter_block("Generate all messages"); + size_t tree_size = 0; + size_t nodes_in_layer = 1; + for (size_t layer = 0; layer <= depth; ++layer) + { + tree_size += nodes_in_layer; + nodes_in_layer *= arity; + } + std::vector tree_elems(tree_size); + for (size_t i = 0; i < tree_size; ++i) + { + tree_elems[i] = std::rand() % 10; + printf("tree_elems[%zu] = %zu\n", i, tree_elems[i]); + } + leave_block("Generate all messages"); + + std::vector > tree_proofs(tree_size); + std::vector > > tree_messages(tree_size); + + enter_block("Generate compliance predicate"); + const size_t type = 1; + tally_cp_handler tally(type, arity, wordsize); + tally.generate_r1cs_constraints(); + r1cs_pcd_compliance_predicate tally_cp = tally.get_compliance_predicate(); + leave_block("Generate compliance predicate"); + + print_header("R1CS ppzkPCD Generator"); + r1cs_sp_ppzkpcd_keypair keypair = r1cs_sp_ppzkpcd_generator(tally_cp); + + print_header("Process verification key"); + r1cs_sp_ppzkpcd_processed_verification_key pvk = r1cs_sp_ppzkpcd_process_vk(keypair.vk); + + if (test_serialization) + { + enter_block("Test serialization of keys"); + keypair.pk = reserialize >(keypair.pk); + keypair.vk = reserialize >(keypair.vk); + pvk = reserialize >(pvk); + leave_block("Test serialization of keys"); + } + + std::shared_ptr > base_msg = tally.get_base_case_message(); + nodes_in_layer /= arity; + for (long layer = depth; layer >= 0; --layer, nodes_in_layer /= arity) + { + for (size_t i = 0; i < nodes_in_layer; ++i) + { + const size_t cur_idx = (nodes_in_layer - 1) / (arity - 1) + i; + + std::vector > > msgs(arity, base_msg); + std::vector > proofs(arity); + + const bool base_case = (arity * cur_idx + arity >= tree_size); + + if (!base_case) + { + for (size_t i = 0; i < arity; ++i) + { + msgs[i] = tree_messages[arity*cur_idx + i + 1]; + proofs[i] = tree_proofs[arity*cur_idx + i + 1]; + } + } + + std::shared_ptr > ld; + ld.reset(new tally_pcd_local_data(tree_elems[cur_idx])); + tally.generate_r1cs_witness(msgs, ld); + + const r1cs_pcd_compliance_predicate_primary_input tally_primary_input(tally.get_outgoing_message()); + const r1cs_pcd_compliance_predicate_auxiliary_input tally_auxiliary_input(msgs, ld, tally.get_witness()); + + print_header("R1CS ppzkPCD Prover"); + r1cs_sp_ppzkpcd_proof proof = r1cs_sp_ppzkpcd_prover(keypair.pk, tally_primary_input, tally_auxiliary_input, proofs); + + if (test_serialization) + { + enter_block("Test serialization of proof"); + proof = reserialize >(proof); + leave_block("Test serialization of proof"); + } + + tree_proofs[cur_idx] = proof; + tree_messages[cur_idx] = tally.get_outgoing_message(); + + print_header("R1CS ppzkPCD Verifier"); + const r1cs_sp_ppzkpcd_primary_input pcd_verifier_input(tree_messages[cur_idx]); + const bool ans = r1cs_sp_ppzkpcd_verifier(keypair.vk, pcd_verifier_input, tree_proofs[cur_idx]); + + print_header("R1CS ppzkPCD Online Verifier"); + const bool ans2 = r1cs_sp_ppzkpcd_online_verifier(pvk, pcd_verifier_input, tree_proofs[cur_idx]); + assert(ans == ans2); + + all_accept = all_accept && ans; + + printf("\n"); + for (size_t i = 0; i < arity; ++i) + { + printf("Message %zu was:\n", i); + msgs[i]->print(); + } + printf("Summand at this node:\n%zu\n", tree_elems[cur_idx]); + printf("Outgoing message is:\n"); + tree_messages[cur_idx]->print(); + printf("\n"); + printf("Current node = %zu. Current proof verifies = %s\n", cur_idx, ans ? "YES" : "NO"); + printf("\n\n\n ================================================================================\n\n\n"); + } + } + + leave_block("Call to run_r1cs_sp_ppzkpcd_tally_example"); + + return all_accept; +} + +} // libsnark + +#endif // RUN_R1CS_SP_PPZKPCD_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/profiling/profile_r1cs_sp_ppzkpcd.cpp b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/profiling/profile_r1cs_sp_ppzkpcd.cpp new file mode 100644 index 0000000..0c93394 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/profiling/profile_r1cs_sp_ppzkpcd.cpp @@ -0,0 +1,33 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include "common/default_types/r1cs_ppzkpcd_pp.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/examples/run_r1cs_sp_ppzkpcd.hpp" + +using namespace libsnark; + +template +void profile_tally(const size_t arity, const size_t max_layer) +{ + const size_t wordsize = 32; + const bool test_serialization = true; + const bool bit = run_r1cs_sp_ppzkpcd_tally_example(wordsize, arity, max_layer, test_serialization); + assert(bit); +} + +int main(void) +{ + typedef default_r1cs_ppzkpcd_pp PCD_pp; + + start_profiling(); + PCD_pp::init_public_params(); + + const size_t arity = 2; + const size_t max_layer = 2; + + profile_tally(arity, max_layer); +} diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd.hpp b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd.hpp new file mode 100644 index 0000000..b7746c1 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd.hpp @@ -0,0 +1,308 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a *single-predicate* ppzkPCD for R1CS. + + This includes: + - class for proving key + - class for verification key + - class for processed verification key + - class for key pair (proving key & verification key) + - class for proof + - generator algorithm + - prover algorithm + - verifier algorithm + - online verifier algorithm + + The implementation follows, extends, and optimizes the approach described + in \[BCTV14]. Thus, PCD is constructed from two "matched" ppzkSNARKs for R1CS. + + Acronyms: + + "R1CS" = "Rank-1 Constraint Systems" + "ppzkSNARK" = "PreProcessing Zero-Knowledge Succinct Non-interactive ARgument of Knowledge" + "ppzkPCD" = "Pre-Processing Zero-Knowledge Proof-Carrying Data" + + References: + + \[BCTV14]: + "Scalable Zero Knowledge via Cycles of Elliptic Curves", + Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, + CRYPTO 2014, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_SP_PPZKPCD_HPP_ +#define R1CS_SP_PPZKPCD_HPP_ + +#include + +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd_params.hpp" + +namespace libsnark { + +/******************************** Proving key ********************************/ + +template +class r1cs_sp_ppzkpcd_proving_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_sp_ppzkpcd_proving_key &pk); + +template +std::istream& operator>>(std::istream &in, r1cs_sp_ppzkpcd_proving_key &pk); + +/** + * A proving key for the R1CS (single-predicate) ppzkPCD. + */ +template +class r1cs_sp_ppzkpcd_proving_key { +public: + typedef typename PCD_ppT::curve_A_pp A_pp; + typedef typename PCD_ppT::curve_B_pp B_pp; + + r1cs_sp_ppzkpcd_compliance_predicate compliance_predicate; + + r1cs_ppzksnark_proving_key compliance_step_r1cs_pk; + r1cs_ppzksnark_proving_key translation_step_r1cs_pk; + + r1cs_ppzksnark_verification_key compliance_step_r1cs_vk; + r1cs_ppzksnark_verification_key translation_step_r1cs_vk; + + r1cs_sp_ppzkpcd_proving_key() {}; + r1cs_sp_ppzkpcd_proving_key(const r1cs_sp_ppzkpcd_proving_key &other) = default; + r1cs_sp_ppzkpcd_proving_key(r1cs_sp_ppzkpcd_proving_key &&other) = default; + r1cs_sp_ppzkpcd_proving_key(const r1cs_sp_ppzkpcd_compliance_predicate &compliance_predicate, + r1cs_ppzksnark_proving_key &&compliance_step_r1cs_pk, + r1cs_ppzksnark_proving_key &&translation_step_r1cs_pk, + const r1cs_ppzksnark_verification_key &compliance_step_r1cs_vk, + const r1cs_ppzksnark_verification_key &translation_step_r1cs_vk) : + compliance_predicate(compliance_predicate), + compliance_step_r1cs_pk(std::move(compliance_step_r1cs_pk)), + translation_step_r1cs_pk(std::move(translation_step_r1cs_pk)), + compliance_step_r1cs_vk(std::move(compliance_step_r1cs_vk)), + translation_step_r1cs_vk(std::move(translation_step_r1cs_vk)) + {}; + + r1cs_sp_ppzkpcd_proving_key& operator=(const r1cs_sp_ppzkpcd_proving_key &other) = default; + + size_t size_in_bits() const + { + return (compliance_step_r1cs_pk.size_in_bits() + + translation_step_r1cs_pk.size_in_bits() + + compliance_step_r1cs_vk.size_in_bits() + + translation_step_r1cs_vk.size_in_bits()); + } + + bool operator==(const r1cs_sp_ppzkpcd_proving_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_sp_ppzkpcd_proving_key &pk); + friend std::istream& operator>> (std::istream &in, r1cs_sp_ppzkpcd_proving_key &pk); +}; + + +/******************************* Verification key ****************************/ + +template +class r1cs_sp_ppzkpcd_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_sp_ppzkpcd_verification_key &vk); + +template +std::istream& operator>>(std::istream &in, r1cs_sp_ppzkpcd_verification_key &vk); + +/** + * A verification key for the R1CS (single-predicate) ppzkPCD. + */ +template +class r1cs_sp_ppzkpcd_verification_key { +public: + typedef typename PCD_ppT::curve_A_pp A_pp; + typedef typename PCD_ppT::curve_B_pp B_pp; + + r1cs_ppzksnark_verification_key compliance_step_r1cs_vk; + r1cs_ppzksnark_verification_key translation_step_r1cs_vk; + + r1cs_sp_ppzkpcd_verification_key() = default; + r1cs_sp_ppzkpcd_verification_key(const r1cs_sp_ppzkpcd_verification_key &other) = default; + r1cs_sp_ppzkpcd_verification_key(r1cs_sp_ppzkpcd_verification_key &&other) = default; + r1cs_sp_ppzkpcd_verification_key(const r1cs_ppzksnark_verification_key &compliance_step_r1cs_vk, + const r1cs_ppzksnark_verification_key &translation_step_r1cs_vk) : + compliance_step_r1cs_vk(std::move(compliance_step_r1cs_vk)), + translation_step_r1cs_vk(std::move(translation_step_r1cs_vk)) + {}; + + r1cs_sp_ppzkpcd_verification_key& operator=(const r1cs_sp_ppzkpcd_verification_key &other) = default; + + size_t size_in_bits() const + { + return (compliance_step_r1cs_vk.size_in_bits() + + translation_step_r1cs_vk.size_in_bits()); + } + + bool operator==(const r1cs_sp_ppzkpcd_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_sp_ppzkpcd_verification_key &vk); + friend std::istream& operator>> (std::istream &in, r1cs_sp_ppzkpcd_verification_key &vk); + + static r1cs_sp_ppzkpcd_verification_key dummy_verification_key(); +}; + + +/************************ Processed verification key *************************/ + +template +class r1cs_sp_ppzkpcd_processed_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_sp_ppzkpcd_processed_verification_key &pvk); + +template +std::istream& operator>>(std::istream &in, r1cs_sp_ppzkpcd_processed_verification_key &pvk); + +/** + * A processed verification key for the R1CS (single-predicate) ppzkPCD. + * + * Compared to a (non-processed) verification key, a processed verification key + * contains a small constant amount of additional pre-computed information that + * enables a faster verification time. + */ +template +class r1cs_sp_ppzkpcd_processed_verification_key { +public: + typedef typename PCD_ppT::curve_A_pp A_pp; + typedef typename PCD_ppT::curve_B_pp B_pp; + + r1cs_ppzksnark_processed_verification_key compliance_step_r1cs_pvk; + r1cs_ppzksnark_processed_verification_key translation_step_r1cs_pvk; + bit_vector translation_step_r1cs_vk_bits; + + r1cs_sp_ppzkpcd_processed_verification_key() {}; + r1cs_sp_ppzkpcd_processed_verification_key(const r1cs_sp_ppzkpcd_processed_verification_key &other) = default; + r1cs_sp_ppzkpcd_processed_verification_key(r1cs_sp_ppzkpcd_processed_verification_key &&other) = default; + r1cs_sp_ppzkpcd_processed_verification_key(r1cs_ppzksnark_processed_verification_key &&compliance_step_r1cs_pvk, + r1cs_ppzksnark_processed_verification_key &&translation_step_r1cs_pvk, + const bit_vector &translation_step_r1cs_vk_bits) : + compliance_step_r1cs_pvk(std::move(compliance_step_r1cs_pvk)), + translation_step_r1cs_pvk(std::move(translation_step_r1cs_pvk)), + translation_step_r1cs_vk_bits(std::move(translation_step_r1cs_vk_bits)) + {}; + + r1cs_sp_ppzkpcd_processed_verification_key& operator=(const r1cs_sp_ppzkpcd_processed_verification_key &other) = default; + + size_t size_in_bits() const + { + return (compliance_step_r1cs_pvk.size_in_bits() + + translation_step_r1cs_pvk.size_in_bits() + + translation_step_r1cs_vk_bits.size()); + } + + bool operator==(const r1cs_sp_ppzkpcd_processed_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_sp_ppzkpcd_processed_verification_key &pvk); + friend std::istream& operator>> (std::istream &in, r1cs_sp_ppzkpcd_processed_verification_key &pvk); +}; + + +/********************************* Key pair **********************************/ + +/** + * A key pair for the R1CS (single-predicate) ppzkPC, which consists of a proving key and a verification key. + */ +template +class r1cs_sp_ppzkpcd_keypair { +public: + typedef typename PCD_ppT::curve_A_pp A_pp; + typedef typename PCD_ppT::curve_B_pp B_pp; + + r1cs_sp_ppzkpcd_proving_key pk; + r1cs_sp_ppzkpcd_verification_key vk; + + r1cs_sp_ppzkpcd_keypair() {}; + r1cs_sp_ppzkpcd_keypair(r1cs_sp_ppzkpcd_keypair &&other) = default; + r1cs_sp_ppzkpcd_keypair(r1cs_sp_ppzkpcd_proving_key &&pk, + r1cs_sp_ppzkpcd_verification_key &&vk) : + pk(std::move(pk)), + vk(std::move(vk)) + {}; + r1cs_sp_ppzkpcd_keypair(r1cs_ppzksnark_keypair &&kp_A, + r1cs_ppzksnark_keypair &&kp_B) : + pk(std::move(kp_A.pk),std::move(kp_B.pk)), + vk(std::move(kp_A.vk),std::move(kp_B.vk)) + {}; +}; + + +/*********************************** Proof ***********************************/ + +/** + * A proof for the R1CS (single-predicate) ppzkPCD. + */ +template +using r1cs_sp_ppzkpcd_proof = r1cs_ppzksnark_proof; + + +/***************************** Main algorithms *******************************/ + +/** + * A generator algorithm for the R1CS (single-predicate) ppzkPCD. + * + * Given a compliance predicate, this algorithm produces proving and verification keys for the predicate. + */ +template +r1cs_sp_ppzkpcd_keypair r1cs_sp_ppzkpcd_generator(const r1cs_sp_ppzkpcd_compliance_predicate &compliance_predicate); + +/** + * A prover algorithm for the R1CS (single-predicate) ppzkPCD. + * + * Given a proving key, inputs for the compliance predicate, and proofs for + * the predicate's input messages, this algorithm produces a proof (of knowledge) + * that attests to the compliance of the output message. + */ +template +r1cs_sp_ppzkpcd_proof r1cs_sp_ppzkpcd_prover(const r1cs_sp_ppzkpcd_proving_key &pk, + const r1cs_sp_ppzkpcd_primary_input &primary_input, + const r1cs_sp_ppzkpcd_auxiliary_input &auxiliary_input, + const std::vector > &incoming_proofs); + +/* + Below are two variants of verifier algorithm for the R1CS (single-predicate) ppzkPCD. + + These are the two cases that arise from whether the verifier accepts a + (non-processed) verification key or, instead, a processed verification key. + In the latter case, we call the algorithm an "online verifier". + */ + +/** + * A verifier algorithm for the R1CS (single-predicate) ppzkPCD that + * accepts a non-processed verification key. + */ +template +bool r1cs_sp_ppzkpcd_verifier(const r1cs_sp_ppzkpcd_verification_key &vk, + const r1cs_sp_ppzkpcd_primary_input &primary_input, + const r1cs_sp_ppzkpcd_proof &proof); + +/** + * Convert a (non-processed) verification key into a processed verification key. + */ +template +r1cs_sp_ppzkpcd_processed_verification_key r1cs_sp_ppzkpcd_process_vk(const r1cs_sp_ppzkpcd_verification_key &vk); + +/** + * A verifier algorithm for the R1CS (single-predicate) ppzkPCD that + * accepts a processed verification key. + */ +template +bool r1cs_sp_ppzkpcd_online_verifier(const r1cs_sp_ppzkpcd_processed_verification_key &pvk, + const r1cs_sp_ppzkpcd_primary_input &primary_input, + const r1cs_sp_ppzkpcd_proof &proof); + +} // libsnark + +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd.tcc" + +#endif // R1CS_SP_PPZKPCD_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd.tcc b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd.tcc new file mode 100644 index 0000000..e284819 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd.tcc @@ -0,0 +1,289 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a *single-predicate* ppzkPCD for R1CS. + + See r1cs_sp_ppzkpcd.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_SP_PPZKPCD_TCC_ +#define R1CS_SP_PPZKPCD_TCC_ + +#include +#include +#include + +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/sp_pcd_circuits.hpp" + +namespace libsnark { + +template +bool r1cs_sp_ppzkpcd_proving_key::operator==(const r1cs_sp_ppzkpcd_proving_key &other) const +{ + return (this->compliance_predicate == other.compliance_predicate && + this->compliance_step_r1cs_pk == other.compliance_step_r1cs_pk && + this->translation_step_r1cs_pk == other.translation_step_r1cs_pk && + this->compliance_step_r1cs_vk == other.compliance_step_r1cs_vk && + this->translation_step_r1cs_vk == other.translation_step_r1cs_vk); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_sp_ppzkpcd_proving_key &pk) +{ + out << pk.compliance_predicate; + out << pk.compliance_step_r1cs_pk; + out << pk.translation_step_r1cs_pk; + out << pk.compliance_step_r1cs_vk; + out << pk.translation_step_r1cs_vk; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_sp_ppzkpcd_proving_key &pk) +{ + in >> pk.compliance_predicate; + in >> pk.compliance_step_r1cs_pk; + in >> pk.translation_step_r1cs_pk; + in >> pk.compliance_step_r1cs_vk; + in >> pk.translation_step_r1cs_vk; + + return in; +} + +template +bool r1cs_sp_ppzkpcd_verification_key::operator==(const r1cs_sp_ppzkpcd_verification_key &other) const +{ + return (this->compliance_step_r1cs_vk == other.compliance_step_r1cs_vk && + this->translation_step_r1cs_vk == other.translation_step_r1cs_vk); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_sp_ppzkpcd_verification_key &vk) +{ + out << vk.compliance_step_r1cs_vk; + out << vk.translation_step_r1cs_vk; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_sp_ppzkpcd_verification_key &vk) +{ + in >> vk.compliance_step_r1cs_vk; + in >> vk.translation_step_r1cs_vk; + + return in; +} + +template +r1cs_sp_ppzkpcd_verification_key r1cs_sp_ppzkpcd_verification_key::dummy_verification_key() +{ + typedef typename PCD_ppT::curve_A_pp curve_A_pp; + typedef typename PCD_ppT::curve_B_pp curve_B_pp; + + r1cs_sp_ppzkpcd_verification_key result; + result.compliance_step_r1cs_vk = r1cs_ppzksnark_verification_key::dummy_verification_key(sp_compliance_step_pcd_circuit_maker::input_size_in_elts()); + result.translation_step_r1cs_vk = r1cs_ppzksnark_verification_key::dummy_verification_key(sp_translation_step_pcd_circuit_maker::input_size_in_elts()); + + return result; +} + +template +bool r1cs_sp_ppzkpcd_processed_verification_key::operator==(const r1cs_sp_ppzkpcd_processed_verification_key &other) const +{ + return (this->compliance_step_r1cs_pvk == other.compliance_step_r1cs_pvk && + this->translation_step_r1cs_pvk == other.translation_step_r1cs_pvk && + this->translation_step_r1cs_vk_bits == other.translation_step_r1cs_vk_bits); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_sp_ppzkpcd_processed_verification_key &pvk) +{ + out << pvk.compliance_step_r1cs_pvk; + out << pvk.translation_step_r1cs_pvk; + serialize_bit_vector(out, pvk.translation_step_r1cs_vk_bits); + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_sp_ppzkpcd_processed_verification_key &pvk) +{ + in >> pvk.compliance_step_r1cs_pvk; + in >> pvk.translation_step_r1cs_pvk; + deserialize_bit_vector(in, pvk.translation_step_r1cs_vk_bits); + + return in; +} + +template +r1cs_sp_ppzkpcd_keypair r1cs_sp_ppzkpcd_generator(const r1cs_sp_ppzkpcd_compliance_predicate &compliance_predicate) +{ + assert(Fr::mod == Fq::mod); + assert(Fq::mod == Fr::mod); + + typedef Fr FieldT_A; + typedef Fr FieldT_B; + + typedef typename PCD_ppT::curve_A_pp curve_A_pp; + typedef typename PCD_ppT::curve_B_pp curve_B_pp; + + enter_block("Call to r1cs_sp_ppzkpcd_generator"); + + assert(compliance_predicate.is_well_formed()); + + enter_block("Construct compliance step PCD circuit"); + sp_compliance_step_pcd_circuit_maker compliance_step_pcd_circuit(compliance_predicate); + compliance_step_pcd_circuit.generate_r1cs_constraints(); + const r1cs_constraint_system compliance_step_pcd_circuit_cs = compliance_step_pcd_circuit.get_circuit(); + compliance_step_pcd_circuit_cs.report_linear_constraint_statistics(); + leave_block("Construct compliance step PCD circuit"); + + enter_block("Generate key pair for compliance step PCD circuit"); + r1cs_ppzksnark_keypair compliance_step_keypair = r1cs_ppzksnark_generator(compliance_step_pcd_circuit_cs); + leave_block("Generate key pair for compliance step PCD circuit"); + + enter_block("Construct translation step PCD circuit"); + sp_translation_step_pcd_circuit_maker translation_step_pcd_circuit(compliance_step_keypair.vk); + translation_step_pcd_circuit.generate_r1cs_constraints(); + const r1cs_constraint_system translation_step_pcd_circuit_cs = translation_step_pcd_circuit.get_circuit(); + translation_step_pcd_circuit_cs.report_linear_constraint_statistics(); + leave_block("Construct translation step PCD circuit"); + + enter_block("Generate key pair for translation step PCD circuit"); + r1cs_ppzksnark_keypair translation_step_keypair = r1cs_ppzksnark_generator(translation_step_pcd_circuit_cs); + leave_block("Generate key pair for translation step PCD circuit"); + + print_indent(); print_mem("in generator"); + leave_block("Call to r1cs_sp_ppzkpcd_generator"); + + return r1cs_sp_ppzkpcd_keypair(r1cs_sp_ppzkpcd_proving_key(compliance_predicate, + std::move(compliance_step_keypair.pk), + std::move(translation_step_keypair.pk), + compliance_step_keypair.vk, + translation_step_keypair.vk), + r1cs_sp_ppzkpcd_verification_key(compliance_step_keypair.vk, + translation_step_keypair.vk)); +} + +template +r1cs_sp_ppzkpcd_proof r1cs_sp_ppzkpcd_prover(const r1cs_sp_ppzkpcd_proving_key &pk, + const r1cs_sp_ppzkpcd_primary_input &primary_input, + const r1cs_sp_ppzkpcd_auxiliary_input &auxiliary_input, + const std::vector > &incoming_proofs) +{ + typedef Fr FieldT_A; + typedef Fr FieldT_B; + + typedef typename PCD_ppT::curve_A_pp curve_A_pp; + typedef typename PCD_ppT::curve_B_pp curve_B_pp; + + enter_block("Call to r1cs_sp_ppzkpcd_prover"); + + const bit_vector translation_step_r1cs_vk_bits = r1cs_ppzksnark_verification_key_variable::get_verification_key_bits(pk.translation_step_r1cs_vk); +#ifdef DEBUG + printf("Outgoing message:\n"); + primary_input.outgoing_message->print(); +#endif + + enter_block("Prove compliance step"); + sp_compliance_step_pcd_circuit_maker compliance_step_pcd_circuit(pk.compliance_predicate); + compliance_step_pcd_circuit.generate_r1cs_witness(pk.translation_step_r1cs_vk, + primary_input, + auxiliary_input, + incoming_proofs); + + const r1cs_primary_input compliance_step_primary_input = compliance_step_pcd_circuit.get_primary_input(); + const r1cs_auxiliary_input compliance_step_auxiliary_input = compliance_step_pcd_circuit.get_auxiliary_input(); + + const r1cs_ppzksnark_proof compliance_step_proof = r1cs_ppzksnark_prover(pk.compliance_step_r1cs_pk, compliance_step_primary_input, compliance_step_auxiliary_input); + leave_block("Prove compliance step"); + +#ifdef DEBUG + const r1cs_primary_input compliance_step_input = get_sp_compliance_step_pcd_circuit_input(translation_step_r1cs_vk_bits, primary_input); + const bool compliance_step_ok = r1cs_ppzksnark_verifier_strong_IC(pk.compliance_step_r1cs_vk, compliance_step_input, compliance_step_proof); + assert(compliance_step_ok); +#endif + + enter_block("Prove translation step"); + sp_translation_step_pcd_circuit_maker translation_step_pcd_circuit(pk.compliance_step_r1cs_vk); + + const r1cs_primary_input translation_step_primary_input = get_sp_translation_step_pcd_circuit_input(translation_step_r1cs_vk_bits, primary_input); + translation_step_pcd_circuit.generate_r1cs_witness(translation_step_primary_input, compliance_step_proof); // TODO: potential for better naming + + const r1cs_auxiliary_input translation_step_auxiliary_input = translation_step_pcd_circuit.get_auxiliary_input(); + const r1cs_ppzksnark_proof translation_step_proof = r1cs_ppzksnark_prover(pk.translation_step_r1cs_pk, translation_step_primary_input, translation_step_auxiliary_input); + leave_block("Prove translation step"); + +#ifdef DEBUG + const bool translation_step_ok = r1cs_ppzksnark_verifier_strong_IC(pk.translation_step_r1cs_vk, translation_step_primary_input, translation_step_proof); + assert(translation_step_ok); +#endif + + print_indent(); print_mem("in prover"); + leave_block("Call to r1cs_sp_ppzkpcd_prover"); + + return translation_step_proof; +} + +template +bool r1cs_sp_ppzkpcd_online_verifier(const r1cs_sp_ppzkpcd_processed_verification_key &pvk, + const r1cs_sp_ppzkpcd_primary_input &primary_input, + const r1cs_sp_ppzkpcd_proof &proof) + +{ + typedef typename PCD_ppT::curve_B_pp curve_B_pp; + + enter_block("Call to r1cs_sp_ppzkpcd_online_verifier"); + const r1cs_primary_input > r1cs_input = get_sp_translation_step_pcd_circuit_input(pvk.translation_step_r1cs_vk_bits, primary_input); + const bool result = r1cs_ppzksnark_online_verifier_strong_IC(pvk.translation_step_r1cs_pvk, r1cs_input, proof); + print_indent(); print_mem("in online verifier"); + leave_block("Call to r1cs_sp_ppzkpcd_online_verifier"); + + return result; +} + +template +r1cs_sp_ppzkpcd_processed_verification_key r1cs_sp_ppzkpcd_process_vk(const r1cs_sp_ppzkpcd_verification_key &vk) +{ + typedef typename PCD_ppT::curve_A_pp curve_A_pp; + typedef typename PCD_ppT::curve_B_pp curve_B_pp; + + enter_block("Call to r1cs_sp_ppzkpcd_processed_verification_key"); + r1cs_ppzksnark_processed_verification_key compliance_step_r1cs_pvk = r1cs_ppzksnark_verifier_process_vk(vk.compliance_step_r1cs_vk); + r1cs_ppzksnark_processed_verification_key translation_step_r1cs_pvk = r1cs_ppzksnark_verifier_process_vk(vk.translation_step_r1cs_vk); + const bit_vector translation_step_r1cs_vk_bits = r1cs_ppzksnark_verification_key_variable::get_verification_key_bits(vk.translation_step_r1cs_vk); + leave_block("Call to r1cs_sp_ppzkpcd_processed_verification_key"); + + return r1cs_sp_ppzkpcd_processed_verification_key(std::move(compliance_step_r1cs_pvk), + std::move(translation_step_r1cs_pvk), + translation_step_r1cs_vk_bits); +} + + +template +bool r1cs_sp_ppzkpcd_verifier(const r1cs_sp_ppzkpcd_verification_key &vk, + const r1cs_sp_ppzkpcd_primary_input &primary_input, + const r1cs_sp_ppzkpcd_proof &proof) +{ + enter_block("Call to r1cs_sp_ppzkpcd_verifier"); + const r1cs_sp_ppzkpcd_processed_verification_key pvk = r1cs_sp_ppzkpcd_process_vk(vk); + const bool result = r1cs_sp_ppzkpcd_online_verifier(pvk, primary_input, proof); + print_indent(); print_mem("in verifier"); + leave_block("Call to r1cs_sp_ppzkpcd_verifier"); + + return result; +} + + +} // libsnark + +#endif // R1CS_SP_PPZKPCD_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd_params.hpp b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd_params.hpp new file mode 100644 index 0000000..16d41a8 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd_params.hpp @@ -0,0 +1,38 @@ +/** @file + ***************************************************************************** + + Parameters for *single-predicate* ppzkPCD for R1CS. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_SP_PPZKPCD_PARAMS_HPP_ +#define R1CS_SP_PPZKPCD_PARAMS_HPP_ + +#include "algebra/curves/public_params.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_pcd_params.hpp" + +namespace libsnark { + +template +using r1cs_sp_ppzkpcd_compliance_predicate = r1cs_pcd_compliance_predicate >; + +template +using r1cs_sp_ppzkpcd_message = r1cs_pcd_message >; + +template +using r1cs_sp_ppzkpcd_local_data = r1cs_pcd_local_data >; + +template +using r1cs_sp_ppzkpcd_primary_input = r1cs_pcd_compliance_predicate_primary_input >; + +template +using r1cs_sp_ppzkpcd_auxiliary_input = r1cs_pcd_compliance_predicate_auxiliary_input >; + +} // libsnark + +#endif // R1CS_SP_PPZKPCD_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/sp_pcd_circuits.hpp b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/sp_pcd_circuits.hpp new file mode 100644 index 0000000..ee7d9c2 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/sp_pcd_circuits.hpp @@ -0,0 +1,174 @@ +/** @file + ***************************************************************************** + + Declaration of functionality for creating and using the two PCD circuits in + a single-predicate PCD construction. + + The implementation follows, extends, and optimizes the approach described + in \[BCTV14]. At high level, there is a "compliance step" circuit and a + "translation step" circuit. For more details see Section 4 of \[BCTV14]. + + + References: + + \[BCTV14]: + "Scalable Zero Knowledge via Cycles of Elliptic Curves", + Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, + CRYPTO 2014, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SP_PCD_CIRCUITS_HPP_ +#define SP_PCD_CIRCUITS_HPP_ + +#include "gadgetlib1/protoboard.hpp" +#include "gadgetlib1/gadgets/gadget_from_r1cs.hpp" +#include "gadgetlib1/gadgets/hashes/crh_gadget.hpp" +#include "gadgetlib1/gadgets/pairing/pairing_params.hpp" +#include "gadgetlib1/gadgets/verifiers/r1cs_ppzksnark_verifier_gadget.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/cp_handler.hpp" + +namespace libsnark { + +/**************************** Compliance step ********************************/ + +/** + * A compliance-step PCD circuit. + * + * The circuit is an R1CS that checks compliance (for the given compliance predicate) + * and validity of previous proofs. + */ +template +class sp_compliance_step_pcd_circuit_maker { +public: + typedef Fr FieldT; + + r1cs_pcd_compliance_predicate compliance_predicate; + + protoboard pb; + + pb_variable zero; + + std::shared_ptr > block_for_outgoing_message; + std::shared_ptr > hash_outgoing_message; + + std::vector > blocks_for_incoming_messages; + std::vector > sp_translation_step_vk_and_incoming_message_payload_digests; + std::vector > unpack_sp_translation_step_vk_and_incoming_message_payload_digests; + std::vector > sp_translation_step_vk_and_incoming_message_payload_digest_bits; + std::vector > hash_incoming_messages; + + std::shared_ptr > sp_translation_step_vk; + pb_variable_array sp_translation_step_vk_bits; + + pb_variable outgoing_message_type; + pb_variable_array outgoing_message_payload; + pb_variable_array outgoing_message_vars; + + pb_variable arity; + std::vector > incoming_message_types; + std::vector > incoming_message_payloads; + std::vector > incoming_message_vars; + + pb_variable_array local_data; + pb_variable_array cp_witness; + std::shared_ptr > compliance_predicate_as_gadget; + + pb_variable_array outgoing_message_bits; + std::shared_ptr > unpack_outgoing_message; + + std::vector > incoming_messages_bits; + std::vector > unpack_incoming_messages; + + pb_variable_array sp_compliance_step_pcd_circuit_input; + pb_variable_array padded_translation_step_vk_and_outgoing_message_digest; + std::vector > padded_translation_step_vk_and_incoming_messages_digests; + + std::vector > verifier_input; + std::vector > proof; + pb_variable verification_result; + std::vector > verifiers; + + sp_compliance_step_pcd_circuit_maker(const r1cs_pcd_compliance_predicate &compliance_predicate); + void generate_r1cs_constraints(); + r1cs_constraint_system get_circuit() const; + + void generate_r1cs_witness(const r1cs_ppzksnark_verification_key > &translation_step_pcd_circuit_vk, + const r1cs_pcd_compliance_predicate_primary_input &compliance_predicate_primary_input, + const r1cs_pcd_compliance_predicate_auxiliary_input &compliance_predicate_auxiliary_input, + const std::vector > > &incoming_proofs); + r1cs_primary_input get_primary_input() const; + r1cs_auxiliary_input get_auxiliary_input() const; + + static size_t field_logsize(); + static size_t field_capacity(); + static size_t input_size_in_elts(); + static size_t input_capacity_in_bits(); + static size_t input_size_in_bits(); +}; + +/*************************** Translation step ********************************/ + +/** + * A translation-step PCD circuit. + * + * The circuit is an R1CS that checks validity of previous proofs. + */ +template +class sp_translation_step_pcd_circuit_maker { +public: + typedef Fr FieldT; + + protoboard pb; + + pb_variable_array sp_translation_step_pcd_circuit_input; + pb_variable_array unpacked_sp_translation_step_pcd_circuit_input; + pb_variable_array verifier_input; + std::shared_ptr > unpack_sp_translation_step_pcd_circuit_input; + + std::shared_ptr > hardcoded_sp_compliance_step_vk; + std::shared_ptr > proof; + std::shared_ptr > online_verifier; + + sp_translation_step_pcd_circuit_maker(const r1cs_ppzksnark_verification_key > &compliance_step_vk); + void generate_r1cs_constraints(); + r1cs_constraint_system get_circuit() const; + + void generate_r1cs_witness(const r1cs_primary_input > translation_step_input, + const r1cs_ppzksnark_proof > &compliance_step_proof); + r1cs_primary_input get_primary_input() const; + r1cs_auxiliary_input get_auxiliary_input() const; + + static size_t field_logsize(); + static size_t field_capacity(); + static size_t input_size_in_elts(); + static size_t input_capacity_in_bits(); + static size_t input_size_in_bits(); +}; + +/****************************** Input maps ***********************************/ + +/** + * Obtain the primary input for a compliance-step PCD circuit. + */ +template +r1cs_primary_input > get_sp_compliance_step_pcd_circuit_input(const bit_vector &sp_translation_step_vk_bits, + const r1cs_pcd_compliance_predicate_primary_input > &primary_input); + +/** + * Obtain the primary input for a translation-step PCD circuit. + */ +template +r1cs_primary_input > get_sp_translation_step_pcd_circuit_input(const bit_vector &sp_translation_step_vk_bits, + const r1cs_pcd_compliance_predicate_primary_input > > &primary_input); + +} // libsnark + +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/sp_pcd_circuits.tcc" + +#endif // SP_PCD_CIRCUITS_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/sp_pcd_circuits.tcc b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/sp_pcd_circuits.tcc new file mode 100644 index 0000000..7a607dc --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/sp_pcd_circuits.tcc @@ -0,0 +1,529 @@ +/** @file + ***************************************************************************** + + Implementation of functionality for creating and using the two PCD circuits in + a single-predicate PCD construction. + + See sp_pcd_circuits.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SP_PCD_CIRCUITS_TCC_ +#define SP_PCD_CIRCUITS_TCC_ + +#include "common/utils.hpp" +#include "gadgetlib1/constraint_profiling.hpp" + +namespace libsnark { + +template +sp_compliance_step_pcd_circuit_maker::sp_compliance_step_pcd_circuit_maker(const r1cs_pcd_compliance_predicate &compliance_predicate) : + compliance_predicate(compliance_predicate) +{ + /* calculate some useful sizes */ + assert(compliance_predicate.is_well_formed()); + assert(compliance_predicate.has_equal_input_and_output_lengths()); + + const size_t compliance_predicate_arity = compliance_predicate.max_arity; + const size_t digest_size = CRH_with_field_out_gadget::get_digest_len(); + const size_t msg_size_in_bits = field_logsize() * (1+compliance_predicate.outgoing_message_payload_length); + const size_t sp_translation_step_vk_size_in_bits = r1cs_ppzksnark_verification_key_variable::size_in_bits(sp_translation_step_pcd_circuit_maker >::input_size_in_elts()); + const size_t padded_verifier_input_size = sp_translation_step_pcd_circuit_maker >::input_capacity_in_bits(); + + printf("other curve input size = %zu\n", sp_translation_step_pcd_circuit_maker >::input_size_in_elts()); + printf("translation_vk_bits = %zu\n", sp_translation_step_vk_size_in_bits); + printf("padded verifier input size = %zu\n", padded_verifier_input_size); + + const size_t block_size = msg_size_in_bits + sp_translation_step_vk_size_in_bits; + CRH_with_bit_out_gadget::sample_randomness(block_size); + + /* allocate input of the compliance PCD circuit */ + sp_compliance_step_pcd_circuit_input.allocate(pb, input_size_in_elts(), "sp_compliance_step_pcd_circuit_input"); + + /* allocate inputs to the compliance predicate */ + outgoing_message_type.allocate(pb, "outgoing_message_type"); + outgoing_message_payload.allocate(pb, compliance_predicate.outgoing_message_payload_length, "outgoing_message_payload"); + + outgoing_message_vars.insert(outgoing_message_vars.end(), outgoing_message_type); + outgoing_message_vars.insert(outgoing_message_vars.end(), outgoing_message_payload.begin(), outgoing_message_payload.end()); + + arity.allocate(pb, "arity"); + + incoming_message_types.resize(compliance_predicate_arity); + incoming_message_payloads.resize(compliance_predicate_arity); + incoming_message_vars.resize(compliance_predicate_arity); + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + incoming_message_types[i].allocate(pb, FMT("", "incoming_message_type_%zu", i)); + incoming_message_payloads[i].allocate(pb, compliance_predicate.outgoing_message_payload_length, FMT("", "incoming_message_payloads_%zu", i)); + + incoming_message_vars[i].insert(incoming_message_vars[i].end(), incoming_message_types[i]); + incoming_message_vars[i].insert(incoming_message_vars[i].end(), incoming_message_payloads[i].begin(), incoming_message_payloads[i].end()); + } + + local_data.allocate(pb, compliance_predicate.local_data_length, "local_data"); + cp_witness.allocate(pb, compliance_predicate.witness_length, "cp_witness"); + + /* convert compliance predicate from a constraint system into a gadget */ + pb_variable_array incoming_messages_concat; + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + incoming_messages_concat.insert(incoming_messages_concat.end(), incoming_message_vars[i].begin(), incoming_message_vars[i].end()); + } + + compliance_predicate_as_gadget.reset(new gadget_from_r1cs(pb, + { outgoing_message_vars, + pb_variable_array(1, arity), + incoming_messages_concat, + local_data, + cp_witness }, + compliance_predicate.constraint_system, "compliance_predicate_as_gadget")); + + /* unpack messages to bits */ + outgoing_message_bits.allocate(pb, msg_size_in_bits, "outgoing_message_bits"); + unpack_outgoing_message.reset(new multipacking_gadget(pb, outgoing_message_bits, outgoing_message_vars, field_logsize(), "unpack_outgoing_message")); + + incoming_messages_bits.resize(compliance_predicate_arity); + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + incoming_messages_bits[i].allocate(pb, msg_size_in_bits, FMT("", "incoming_messages_bits_%zu", i)); + unpack_incoming_messages.emplace_back(multipacking_gadget(pb, incoming_messages_bits[i], incoming_message_vars[i], field_logsize(), FMT("", "unpack_incoming_messages_%zu", i))); + } + + /* allocate digests */ + sp_translation_step_vk_and_incoming_message_payload_digests.resize(compliance_predicate_arity); + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + sp_translation_step_vk_and_incoming_message_payload_digests[i].allocate(pb, digest_size, FMT("", "sp_translation_step_vk_and_incoming_message_payload_digests_%zu", i)); + } + + /* allocate blocks */ + sp_translation_step_vk_bits.allocate(pb, sp_translation_step_vk_size_in_bits, "sp_translation_step_vk_bits"); + + block_for_outgoing_message.reset(new block_variable(pb, { + sp_translation_step_vk_bits, + outgoing_message_bits }, "block_for_outgoing_message")); + + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + blocks_for_incoming_messages.emplace_back(block_variable(pb, { + sp_translation_step_vk_bits, + incoming_messages_bits[i] }, FMT("", "blocks_for_incoming_messages_zu", i))); + } + + /* allocate hash checkers */ + hash_outgoing_message.reset(new CRH_with_field_out_gadget(pb, block_size, *block_for_outgoing_message, sp_compliance_step_pcd_circuit_input, "hash_outgoing_message")); + + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + hash_incoming_messages.emplace_back(CRH_with_field_out_gadget(pb, block_size, blocks_for_incoming_messages[i], sp_translation_step_vk_and_incoming_message_payload_digests[i], FMT("", "hash_incoming_messages_%zu", i))); + } + + /* allocate useful zero variable */ + zero.allocate(pb, "zero"); + + /* prepare arguments for the verifier */ + sp_translation_step_vk.reset(new r1cs_ppzksnark_verification_key_variable(pb, sp_translation_step_vk_bits, sp_translation_step_pcd_circuit_maker >::input_size_in_elts(), "sp_translation_step_vk")); + + verification_result.allocate(pb, "verification_result"); + sp_translation_step_vk_and_incoming_message_payload_digest_bits.resize(compliance_predicate_arity); + + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + sp_translation_step_vk_and_incoming_message_payload_digest_bits[i].allocate(pb, digest_size * field_logsize(), FMT("", "sp_translation_step_vk_and_incoming_message_payload_digest_bits_%zu", i)); + unpack_sp_translation_step_vk_and_incoming_message_payload_digests.emplace_back(multipacking_gadget(pb, + sp_translation_step_vk_and_incoming_message_payload_digest_bits[i], + sp_translation_step_vk_and_incoming_message_payload_digests[i], + field_logsize(), + FMT("", "unpack_sp_translation_step_vk_and_incoming_message_payload_digests_%zu", i))); + + verifier_input.emplace_back(sp_translation_step_vk_and_incoming_message_payload_digest_bits[i]); + while (verifier_input[i].size() < padded_verifier_input_size) + { + verifier_input[i].emplace_back(zero); + } + + proof.emplace_back(r1cs_ppzksnark_proof_variable(pb, FMT("", "proof_%zu", i))); + verifiers.emplace_back(r1cs_ppzksnark_verifier_gadget(pb, + *sp_translation_step_vk, + verifier_input[i], + sp_translation_step_pcd_circuit_maker >::field_capacity(), + proof[i], + verification_result, + FMT("", "verifiers_%zu", i))); + } + + pb.set_input_sizes(input_size_in_elts()); + printf("done compliance\n"); +} + +template +void sp_compliance_step_pcd_circuit_maker::generate_r1cs_constraints() +{ + const size_t digest_size = CRH_with_bit_out_gadget::get_digest_len(); + const size_t dimension = knapsack_dimension::dimension; + print_indent(); printf("* Knapsack dimension: %zu\n", dimension); + + const size_t compliance_predicate_arity = compliance_predicate.max_arity; + print_indent(); printf("* Compliance predicate arity: %zu\n", compliance_predicate_arity); + print_indent(); printf("* Compliance predicate payload length: %zu\n", compliance_predicate.outgoing_message_payload_length); + print_indent(); printf("* Compliance predicate local data length: %zu\n", compliance_predicate.local_data_length); + print_indent(); printf("* Compliance predicate witness length: %zu\n", compliance_predicate.witness_length); + + PROFILE_CONSTRAINTS(pb, "booleanity") + { + PROFILE_CONSTRAINTS(pb, "booleanity: unpack outgoing_message") + { + unpack_outgoing_message->generate_r1cs_constraints(true); + } + + PROFILE_CONSTRAINTS(pb, "booleanity: unpack s incoming_message") + { + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + unpack_incoming_messages[i].generate_r1cs_constraints(true); + } + } + + PROFILE_CONSTRAINTS(pb, "booleanity: unpack verification key") + { + sp_translation_step_vk->generate_r1cs_constraints(true); + } + } + + PROFILE_CONSTRAINTS(pb, "(1+s) copies of hash") + { + print_indent(); printf("* Digest-size: %zu\n", digest_size); + hash_outgoing_message->generate_r1cs_constraints(); + + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + hash_incoming_messages[i].generate_r1cs_constraints(); + } + } + + PROFILE_CONSTRAINTS(pb, "s copies of repacking circuit") + { + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + unpack_sp_translation_step_vk_and_incoming_message_payload_digests[i].generate_r1cs_constraints(true); + } + } + + PROFILE_CONSTRAINTS(pb, "compliance predicate") + { + compliance_predicate_as_gadget->generate_r1cs_constraints(); + } + + PROFILE_CONSTRAINTS(pb, "s copies of verifier for translated proofs") + { + PROFILE_CONSTRAINTS(pb, "check that s proofs lie on the curve") + { + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + proof[i].generate_r1cs_constraints(); + } + } + + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + verifiers[i].generate_r1cs_constraints(); + } + } + + PROFILE_CONSTRAINTS(pb, "miscellaneous") + { + generate_r1cs_equals_const_constraint(pb, zero, FieldT::zero(), "zero"); + generate_boolean_r1cs_constraint(pb, verification_result, "verification_result"); + + /* type * (1-verification_result) = 0 */ + pb.add_r1cs_constraint(r1cs_constraint(incoming_message_types[0], 1 - verification_result, 0), "not_base_case_implies_valid_proofs"); + + /* all types equal */ + for (size_t i = 1; i < compliance_predicate.max_arity; ++i) + { + pb.add_r1cs_constraint(r1cs_constraint(1, incoming_message_types[0], incoming_message_types[i]), + FMT("", "type_%zu_equal_to_type_0", i)); + } + + pb.add_r1cs_constraint(r1cs_constraint(1, arity, compliance_predicate_arity), "full_arity"); + pb.add_r1cs_constraint(r1cs_constraint(1, outgoing_message_type, FieldT(compliance_predicate.type)), "enforce_outgoing_type"); + } + + PRINT_CONSTRAINT_PROFILING(); + print_indent(); printf("* Number of constraints in sp_compliance_step_pcd_circuit: %zu\n", pb.num_constraints()); +} + +template +r1cs_constraint_system > sp_compliance_step_pcd_circuit_maker::get_circuit() const +{ + return pb.get_constraint_system(); +} + +template +r1cs_primary_input > sp_compliance_step_pcd_circuit_maker::get_primary_input() const +{ + return pb.primary_input(); +} + +template +r1cs_auxiliary_input > sp_compliance_step_pcd_circuit_maker::get_auxiliary_input() const +{ + return pb.auxiliary_input(); +} + +template +void sp_compliance_step_pcd_circuit_maker::generate_r1cs_witness(const r1cs_ppzksnark_verification_key > &sp_translation_step_pcd_circuit_vk, + const r1cs_pcd_compliance_predicate_primary_input &compliance_predicate_primary_input, + const r1cs_pcd_compliance_predicate_auxiliary_input &compliance_predicate_auxiliary_input, + const std::vector > > &incoming_proofs) +{ + const size_t compliance_predicate_arity = compliance_predicate.max_arity; + this->pb.clear_values(); + this->pb.val(zero) = FieldT::zero(); + + compliance_predicate_as_gadget->generate_r1cs_witness(compliance_predicate_primary_input.as_r1cs_primary_input(), + compliance_predicate_auxiliary_input.as_r1cs_auxiliary_input(compliance_predicate.incoming_message_payload_lengths)); + this->pb.val(arity) = FieldT(compliance_predicate_arity); + unpack_outgoing_message->generate_r1cs_witness_from_packed(); + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + unpack_incoming_messages[i].generate_r1cs_witness_from_packed(); + } + + sp_translation_step_vk->generate_r1cs_witness(sp_translation_step_pcd_circuit_vk); + hash_outgoing_message->generate_r1cs_witness(); + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + hash_incoming_messages[i].generate_r1cs_witness(); + unpack_sp_translation_step_vk_and_incoming_message_payload_digests[i].generate_r1cs_witness_from_packed(); + } + + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + proof[i].generate_r1cs_witness(incoming_proofs[i]); + verifiers[i].generate_r1cs_witness(); + } + + if (this->pb.val(incoming_message_types[0]) != FieldT::zero()) + { + this->pb.val(verification_result) = FieldT::one(); + } + +#ifdef DEBUG + generate_r1cs_constraints(); // force generating constraints + assert(this->pb.is_satisfied()); +#endif +} + +template +size_t sp_compliance_step_pcd_circuit_maker::field_logsize() +{ + return Fr::size_in_bits(); +} + +template +size_t sp_compliance_step_pcd_circuit_maker::field_capacity() +{ + return Fr::capacity(); +} + +template +size_t sp_compliance_step_pcd_circuit_maker::input_size_in_elts() +{ + const size_t digest_size = CRH_with_field_out_gadget::get_digest_len(); + return digest_size; +} + +template +size_t sp_compliance_step_pcd_circuit_maker::input_capacity_in_bits() +{ + return input_size_in_elts() * field_capacity(); +} + +template +size_t sp_compliance_step_pcd_circuit_maker::input_size_in_bits() +{ + return input_size_in_elts() * field_logsize(); +} + +template +sp_translation_step_pcd_circuit_maker::sp_translation_step_pcd_circuit_maker(const r1cs_ppzksnark_verification_key > &sp_compliance_step_vk) +{ + /* allocate input of the translation PCD circuit */ + sp_translation_step_pcd_circuit_input.allocate(pb, input_size_in_elts(), "sp_translation_step_pcd_circuit_input"); + + /* unpack translation step PCD circuit input */ + unpacked_sp_translation_step_pcd_circuit_input.allocate(pb, sp_compliance_step_pcd_circuit_maker >::input_size_in_bits(), "unpacked_sp_translation_step_pcd_circuit_input"); + unpack_sp_translation_step_pcd_circuit_input.reset(new multipacking_gadget(pb, unpacked_sp_translation_step_pcd_circuit_input, sp_translation_step_pcd_circuit_input, field_capacity(), "unpack_sp_translation_step_pcd_circuit_input")); + + /* prepare arguments for the verifier */ + hardcoded_sp_compliance_step_vk.reset(new r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable(pb, sp_compliance_step_vk, "hardcoded_sp_compliance_step_vk")); + proof.reset(new r1cs_ppzksnark_proof_variable(pb, "proof")); + + /* verify previous proof */ + online_verifier.reset(new r1cs_ppzksnark_online_verifier_gadget(pb, + *hardcoded_sp_compliance_step_vk, + unpacked_sp_translation_step_pcd_circuit_input, + sp_compliance_step_pcd_circuit_maker >::field_logsize(), + *proof, + ONE, // must always accept + "verifier")); + pb.set_input_sizes(input_size_in_elts()); + + printf("done translation\n"); +} + +template +void sp_translation_step_pcd_circuit_maker::generate_r1cs_constraints() +{ + PROFILE_CONSTRAINTS(pb, "repacking: unpack circuit input") + { + unpack_sp_translation_step_pcd_circuit_input->generate_r1cs_constraints(true); + } + + PROFILE_CONSTRAINTS(pb, "verifier for compliance proofs") + { + PROFILE_CONSTRAINTS(pb, "check that proof lies on the curve") + { + proof->generate_r1cs_constraints(); + } + + online_verifier->generate_r1cs_constraints(); + } + + PRINT_CONSTRAINT_PROFILING(); + print_indent(); printf("* Number of constraints in sp_translation_step_pcd_circuit: %zu\n", pb.num_constraints()); +} + +template +r1cs_constraint_system > sp_translation_step_pcd_circuit_maker::get_circuit() const +{ + return pb.get_constraint_system(); +} + +template +void sp_translation_step_pcd_circuit_maker::generate_r1cs_witness(const r1cs_primary_input > sp_translation_step_input, + const r1cs_ppzksnark_proof > &compliance_step_proof) +{ + this->pb.clear_values(); + sp_translation_step_pcd_circuit_input.fill_with_field_elements(pb, sp_translation_step_input); + unpack_sp_translation_step_pcd_circuit_input->generate_r1cs_witness_from_packed(); + + proof->generate_r1cs_witness(compliance_step_proof); + online_verifier->generate_r1cs_witness(); + +#ifdef DEBUG + generate_r1cs_constraints(); // force generating constraints + + printf("Input to the translation circuit:\n"); + for (size_t i = 0; i < this->pb.num_inputs(); ++i) + { + this->pb.val(pb_variable(i+1)).print(); + } + + assert(this->pb.is_satisfied()); +#endif +} + +template +r1cs_primary_input > sp_translation_step_pcd_circuit_maker::get_primary_input() const +{ + return pb.primary_input(); +} + +template +r1cs_auxiliary_input > sp_translation_step_pcd_circuit_maker::get_auxiliary_input() const +{ + return pb.auxiliary_input(); +} + +template +size_t sp_translation_step_pcd_circuit_maker::field_logsize() +{ + return Fr::size_in_bits(); +} + +template +size_t sp_translation_step_pcd_circuit_maker::field_capacity() +{ + return Fr::capacity(); +} + +template +size_t sp_translation_step_pcd_circuit_maker::input_size_in_elts() +{ + return div_ceil(sp_compliance_step_pcd_circuit_maker >::input_size_in_bits(), sp_translation_step_pcd_circuit_maker::field_capacity()); +} + +template +size_t sp_translation_step_pcd_circuit_maker::input_capacity_in_bits() +{ + return input_size_in_elts() * field_capacity(); +} + +template +size_t sp_translation_step_pcd_circuit_maker::input_size_in_bits() +{ + return input_size_in_elts() * field_logsize(); +} + +template +r1cs_primary_input > get_sp_compliance_step_pcd_circuit_input(const bit_vector &sp_translation_step_vk_bits, + const r1cs_pcd_compliance_predicate_primary_input > &primary_input) +{ + enter_block("Call to get_sp_compliance_step_pcd_circuit_input"); + typedef Fr FieldT; + + const r1cs_variable_assignment outgoing_message_as_va = primary_input.outgoing_message->as_r1cs_variable_assignment(); + bit_vector msg_bits; + for (const FieldT &elt : outgoing_message_as_va) + { + const bit_vector elt_bits = convert_field_element_to_bit_vector(elt); + msg_bits.insert(msg_bits.end(), elt_bits.begin(), elt_bits.end()); + } + + bit_vector block; + block.insert(block.end(), sp_translation_step_vk_bits.begin(), sp_translation_step_vk_bits.end()); + block.insert(block.end(), msg_bits.begin(), msg_bits.end()); + + enter_block("Sample CRH randomness"); + CRH_with_field_out_gadget::sample_randomness(block.size()); + leave_block("Sample CRH randomness"); + + const std::vector digest = CRH_with_field_out_gadget::get_hash(block); + leave_block("Call to get_sp_compliance_step_pcd_circuit_input"); + + return digest; +} + +template +r1cs_primary_input > get_sp_translation_step_pcd_circuit_input(const bit_vector &sp_translation_step_vk_bits, + const r1cs_pcd_compliance_predicate_primary_input > > &primary_input) +{ + enter_block("Call to get_sp_translation_step_pcd_circuit_input"); + typedef Fr FieldT; + + const std::vector > > sp_compliance_step_pcd_circuit_input = get_sp_compliance_step_pcd_circuit_input >(sp_translation_step_vk_bits, primary_input); + bit_vector sp_compliance_step_pcd_circuit_input_bits; + for (const Fr > &elt : sp_compliance_step_pcd_circuit_input) + { + const bit_vector elt_bits = convert_field_element_to_bit_vector > >(elt); + sp_compliance_step_pcd_circuit_input_bits.insert(sp_compliance_step_pcd_circuit_input_bits.end(), elt_bits.begin(), elt_bits.end()); + } + + sp_compliance_step_pcd_circuit_input_bits.resize(sp_translation_step_pcd_circuit_maker::input_capacity_in_bits(), false); + + const r1cs_primary_input result = pack_bit_vector_into_field_element_vector(sp_compliance_step_pcd_circuit_input_bits, sp_translation_step_pcd_circuit_maker::field_capacity()); + leave_block("Call to get_sp_translation_step_pcd_circuit_input"); + + return result; +} + +} // libsnark + +#endif // SP_PCD_CIRCUITS_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/tests/test_r1cs_sp_ppzkpcd.cpp b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/tests/test_r1cs_sp_ppzkpcd.cpp new file mode 100644 index 0000000..1169804 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/tests/test_r1cs_sp_ppzkpcd.cpp @@ -0,0 +1,32 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include "common/default_types/r1cs_ppzkpcd_pp.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/examples/run_r1cs_sp_ppzkpcd.hpp" + +using namespace libsnark; + +template +void test_tally(const size_t arity, const size_t max_layer) +{ + const size_t wordsize = 32; + const bool test_serialization = true; + const bool bit = run_r1cs_sp_ppzkpcd_tally_example(wordsize, arity, max_layer, test_serialization); + assert(bit); +} + +int main(void) +{ + typedef default_r1cs_ppzkpcd_pp PCD_pp; + + start_profiling(); + PCD_pp::init_public_params(); + + const size_t arity = 2; + const size_t max_layer = 2; + + test_tally(arity, max_layer); +} diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/demo_r1cs_ppzkadsnark.cpp b/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/demo_r1cs_ppzkadsnark.cpp new file mode 100644 index 0000000..717fce4 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/demo_r1cs_ppzkadsnark.cpp @@ -0,0 +1,56 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include +#include +#include +#include + +#include "common/default_types/r1cs_ppzkadsnark_pp.hpp" +#include "common/profiling.hpp" +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/run_r1cs_ppzkadsnark.hpp" + +using namespace libsnark; + +int main(int argc, const char * argv[]) +{ + default_r1cs_ppzkadsnark_pp::init_public_params(); + start_profiling(); + + if (argc == 2 && strcmp(argv[1], "-v") == 0) + { + print_compilation_info(); + return 0; + } + + if (argc != 3 && argc != 4) + { + printf("usage: %s num_constraints input_size [Fr|bytes]\n", argv[0]); + return 1; + } + const int num_constraints = atoi(argv[1]); + int input_size = atoi(argv[2]); + if (argc == 4) + { + assert(strcmp(argv[3], "Fr") == 0 || strcmp(argv[3], "bytes") == 0); + if (strcmp(argv[3], "bytes") == 0) + { + input_size = div_ceil(8 * input_size, Fr>::num_bits - 1); + } + } + + enter_block("Generate R1CS example"); + r1cs_example>> example = + generate_r1cs_example_with_field_input>> + (num_constraints, input_size); + leave_block("Generate R1CS example"); + + print_header("(enter) Profile R1CS ppzkADSNARK"); + const bool test_serialization = true; + run_r1cs_ppzkadsnark(example, test_serialization); + print_header("(leave) Profile R1CS ppzkADSNARK"); +} diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/prf/aes_ctr_prf.hpp b/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/prf/aes_ctr_prf.hpp new file mode 100644 index 0000000..28a655d --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/prf/aes_ctr_prf.hpp @@ -0,0 +1,26 @@ +/** @file + ***************************************************************************** + + AES-Based PRF for ADSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef AESCTRPRF_HPP_ +#define AESCTRPRF_HPP_ + +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_prf.hpp" + +namespace libsnark { + +class aesPrfKeyT { +public: + unsigned char key_bytes[32]; +}; + +} // libsnark + +#endif // AESCTRPRF_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/prf/aes_ctr_prf.tcc b/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/prf/aes_ctr_prf.tcc new file mode 100644 index 0000000..c5b5d45 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/prf/aes_ctr_prf.tcc @@ -0,0 +1,68 @@ +/** @file + ***************************************************************************** + + AES-Based PRF for ADSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "common/default_types/r1cs_ppzkadsnark_pp.hpp" +#include "supercop/crypto_core_aes128encrypt.h" +#include "supercop/randombytes.h" +#include "gmp.h" + +namespace libsnark { + +template <> +aesPrfKeyT prfGen() { + aesPrfKeyT key; + randombytes(key.key_bytes,32); + return key; +} + +template<> +Fr> prfCompute( + const aesPrfKeyT &key, const labelT &label) { + unsigned char seed_bytes[16]; + mpz_t aux,Fr_mod; + unsigned char random_bytes[16*3]; + size_t exp_len; + + mpz_init (aux); + mpz_init (Fr_mod); + + // compute random seed using AES as PRF + crypto_core_aes128encrypt_openssl(seed_bytes,label.label_bytes,key.key_bytes,NULL); + + // use first 128 bits of output to seed AES-CTR + // PRG to expand to 3*128 bits + crypto_core_aes128encrypt_openssl(random_bytes,seed_bytes,key.key_bytes+16,NULL); + + mpz_import(aux, 16, 0, 1, 0, 0, seed_bytes); + mpz_add_ui(aux,aux,1); + mpz_export(seed_bytes, &exp_len, 0, 1, 0, 0, aux); + while (exp_len < 16) + seed_bytes[exp_len++] = 0; + + crypto_core_aes128encrypt_openssl(random_bytes+16,seed_bytes,key.key_bytes+16,NULL); + + mpz_add_ui(aux,aux,1); + mpz_export(seed_bytes, &exp_len, 0, 1, 0, 0, aux); + while (exp_len < 16) + seed_bytes[exp_len++] = 0; + + crypto_core_aes128encrypt_openssl(random_bytes+32,seed_bytes,key.key_bytes+16,NULL); + + // see output as integer and reduce modulo r + mpz_import(aux, 16*3, 0, 1, 0, 0, random_bytes); + Fr>::mod.to_mpz(Fr_mod); + mpz_mod(aux,aux,Fr_mod); + + return Fr>( + bigint>::num_limbs>(aux)); +} + +} // libsnark diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/run_r1cs_ppzkadsnark.hpp b/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/run_r1cs_ppzkadsnark.hpp new file mode 100644 index 0000000..2a919b0 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/run_r1cs_ppzkadsnark.hpp @@ -0,0 +1,35 @@ +/** @file + ***************************************************************************** + + Declaration of functionality that runs the R1CS ppzkADSNARK for + a given R1CS example. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_R1CS_PPZKADSNARK_HPP_ +#define RUN_R1CS_PPZKADSNARK_HPP_ + +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" + +namespace libsnark { + +/** + * Runs the ppzkADSNARK (generator, prover, and verifier) for a given + * R1CS example (specified by a constraint system, input, and witness). + * + * Optionally, also test the serialization routines for keys and proofs. + * (This takes additional time.) + */ +template +bool run_r1cs_ppzkadsnark(const r1cs_example> > &example, + const bool test_serialization); + +} // libsnark + +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/run_r1cs_ppzkadsnark.tcc" + +#endif // RUN_R1CS_PPZKADSNARK_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/run_r1cs_ppzkadsnark.tcc b/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/run_r1cs_ppzkadsnark.tcc new file mode 100644 index 0000000..a69ed53 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/run_r1cs_ppzkadsnark.tcc @@ -0,0 +1,123 @@ +/** @file + ***************************************************************************** + + Implementation of functionality that runs the R1CS ppzkADSNARK for + a given R1CS example. + + See run_r1cs_ppzkadsnark.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_R1CS_PPZKADSNARK_TCC_ +#define RUN_R1CS_PPZKADSNARK_TCC_ + +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark.hpp" +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/prf/aes_ctr_prf.tcc" +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/signature/ed25519_signature.tcc" + +#include +#include + +#include "common/profiling.hpp" + +namespace libsnark { + +/** + * The code below provides an example of all stages of running a R1CS ppzkADSNARK. + * + * Of course, in a real-life scenario, we would have three distinct entities, + * mangled into one in the demonstration below. The three entities are as follows. + * (1) The "generator", which runs the ppzkADSNARK generator on input a given + * constraint system CS to create a proving and a verification key for CS. + * (2) The "prover", which runs the ppzkADSNARK prover on input the proving key, + * a primary input for CS, and an auxiliary input for CS. + * (3) The "verifier", which runs the ppzkADSNARK verifier on input the verification key, + * a primary input for CS, and a proof. + */ +template +bool run_r1cs_ppzkadsnark(const r1cs_example> > &example, + const bool test_serialization) +{ + enter_block("Call to run_r1cs_ppzkadsnark"); + + r1cs_ppzkadsnark_auth_keys auth_keys = r1cs_ppzkadsnark_auth_generator(); + + print_header("R1CS ppzkADSNARK Generator"); + r1cs_ppzkadsnark_keypair keypair = r1cs_ppzkadsnark_generator(example.constraint_system,auth_keys.pap); + printf("\n"); print_indent(); print_mem("after generator"); + + print_header("Preprocess verification key"); + r1cs_ppzkadsnark_processed_verification_key pvk = r1cs_ppzkadsnark_verifier_process_vk(keypair.vk); + + if (test_serialization) + { + enter_block("Test serialization of keys"); + keypair.pk = reserialize >(keypair.pk); + keypair.vk = reserialize >(keypair.vk); + pvk = reserialize >(pvk); + leave_block("Test serialization of keys"); + } + + print_header("R1CS ppzkADSNARK Authenticate"); + std::vector>> data; + data.reserve(example.constraint_system.num_inputs()); + std::vector labels; + labels.reserve(example.constraint_system.num_inputs()); + for (size_t i = 0; i < example.constraint_system.num_inputs(); i++) { + labels.emplace_back(labelT()); + data.emplace_back(example.primary_input[i]); + } + std::vector> auth_data = + r1cs_ppzkadsnark_auth_sign(data,auth_keys.sak,labels); + + print_header("R1CS ppzkADSNARK Verify Symmetric"); + bool auth_res = + r1cs_ppzkadsnark_auth_verify(data,auth_data,auth_keys.sak,labels); + printf("* The verification result is: %s\n", (auth_res ? "PASS" : "FAIL")); + + print_header("R1CS ppzkADSNARK Verify Public"); + bool auth_resp = + r1cs_ppzkadsnark_auth_verify(data,auth_data,auth_keys.pak,labels); + assert (auth_res == auth_resp); + + print_header("R1CS ppzkADSNARK Prover"); + r1cs_ppzkadsnark_proof proof = r1cs_ppzkadsnark_prover(keypair.pk, example.primary_input, example.auxiliary_input,auth_data); + printf("\n"); print_indent(); print_mem("after prover"); + + if (test_serialization) + { + enter_block("Test serialization of proof"); + proof = reserialize >(proof); + leave_block("Test serialization of proof"); + } + + print_header("R1CS ppzkADSNARK Symmetric Verifier"); + bool ans = r1cs_ppzkadsnark_verifier(keypair.vk, proof,auth_keys.sak,labels); + printf("\n"); print_indent(); print_mem("after verifier"); + printf("* The verification result is: %s\n", (ans ? "PASS" : "FAIL")); + + print_header("R1CS ppzkADSNARK Symmetric Online Verifier"); + bool ans2 = r1cs_ppzkadsnark_online_verifier(pvk, proof,auth_keys.sak,labels); + assert(ans == ans2); + + print_header("R1CS ppzkADSNARK Public Verifier"); + ans = r1cs_ppzkadsnark_verifier(keypair.vk, auth_data, proof,auth_keys.pak,labels); + printf("\n"); print_indent(); print_mem("after verifier"); + printf("* The verification result is: %s\n", (ans ? "PASS" : "FAIL")); + + print_header("R1CS ppzkADSNARK Public Online Verifier"); + ans2 = r1cs_ppzkadsnark_online_verifier(pvk, auth_data, proof,auth_keys.pak,labels); + assert(ans == ans2); + + leave_block("Call to run_r1cs_ppzkadsnark"); + + return ans; +} + +} // libsnark + +#endif // RUN_R1CS_PPZKADSNARK_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/signature/ed25519_signature.hpp b/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/signature/ed25519_signature.hpp new file mode 100644 index 0000000..560b08c --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/signature/ed25519_signature.hpp @@ -0,0 +1,42 @@ +/** @file + ***************************************************************************** + + Fast batch verification signature for ADSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +/** @file + ***************************************************************************** + * @author This file was deed to libsnark by Manuel Barbosa. + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ED25519SIG_HPP_ +#define ED25519SIG_HPP_ + +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_signature.hpp" + +namespace libsnark { + +class ed25519_sigT { +public: + unsigned char sig_bytes[64]; +}; + +class ed25519_vkT { +public: + unsigned char vk_bytes[32]; +}; + +class ed25519_skT { +public: + unsigned char sk_bytes[64]; +}; + +} // libsnark + +#endif // ED25519SIG_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/signature/ed25519_signature.tcc b/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/signature/ed25519_signature.tcc new file mode 100644 index 0000000..4183570 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/signature/ed25519_signature.tcc @@ -0,0 +1,149 @@ +/** @file + ***************************************************************************** + + Fast batch verification signature for ADSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +/** @file + ***************************************************************************** + * @author This file was deed to libsnark by Manuel Barbosa. + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "common/default_types/r1cs_ppzkadsnark_pp.hpp" +#include "supercop/crypto_sign.h" + +namespace libsnark { + +template<> +kpT sigGen(void) { + kpT keys; + crypto_sign_ed25519_amd64_51_30k_keypair(keys.vk.vk_bytes,keys.sk.sk_bytes); + return keys; +} + +template<> +ed25519_sigT sigSign(const ed25519_skT &sk, const labelT &label, + const G2> &Lambda) { + ed25519_sigT sigma; + unsigned long long sigmalen; + unsigned char signature[64+16+320]; + unsigned char message[16+320]; + + G2> Lambda_copy(Lambda); + Lambda_copy.to_affine_coordinates(); + + for(size_t i = 0; i<16;i++) + message[i] = label.label_bytes[i]; + + // More efficient way to get canonical point rep? + std::stringstream stream; + stream.rdbuf()->pubsetbuf(((char*)message)+16, 320); + stream << Lambda_copy; + size_t written = stream.tellp(); + while (written<320) + message[16+written++] = 0; + + crypto_sign_ed25519_amd64_51_30k(signature,&sigmalen,message,16+320,sk.sk_bytes); + + assert(sigmalen == 64+16+320); + + for(size_t i = 0; i<64;i++) + sigma.sig_bytes[i] = signature[i]; + + return sigma; +} + +template<> +bool sigVerif(const ed25519_vkT &vk, const labelT &label, + const G2> &Lambda, + const ed25519_sigT &sig) { + unsigned long long msglen; + unsigned char message[64+16+320]; + unsigned char signature[64+16+320]; + + G2> Lambda_copy(Lambda); + Lambda_copy.to_affine_coordinates(); + + for(size_t i = 0; i<64;i++) + signature[i] = sig.sig_bytes[i]; + + for(size_t i = 0; i<16;i++) + signature[64+i] = label.label_bytes[i]; + + // More efficient way to get canonical point rep? + std::stringstream stream; + stream.rdbuf()->pubsetbuf(((char*)signature)+64+16, 320); + stream << Lambda_copy; + size_t written = stream.tellp(); + while (written<320) + signature[64+16+written++] = 0; + + int res = crypto_sign_ed25519_amd64_51_30k_open(message,&msglen,signature,64+16+320,vk.vk_bytes); + return (res==0); +} + +template<> +bool sigBatchVerif(const ed25519_vkT &vk, const std::vector &labels, + const std::vector>> &Lambdas, + const std::vector &sigs) { + std::stringstream stream; + + assert(labels.size() == Lambdas.size()); + assert(labels.size() == sigs.size()); + + unsigned long long msglen[labels.size()]; + unsigned long long siglen[labels.size()]; + unsigned char *messages[labels.size()]; + unsigned char *signatures[labels.size()]; + unsigned char *pks[labels.size()]; + + unsigned char pk_copy[32]; + for(size_t i = 0; i < 32; i++) { + pk_copy[i] = vk.vk_bytes[i]; + } + + unsigned char *messagemem = (unsigned char*)malloc(labels.size()*(64+16+320)); + assert(messagemem != NULL); + unsigned char *signaturemem = (unsigned char*)malloc(labels.size()*(64+16+320)); + assert(signaturemem != NULL); + + for(size_t i = 0; i < labels.size(); i++) { + siglen[i] = 64+16+320; + messages[i] = messagemem+(64+16+320)*i; + signatures[i] = signaturemem+(64+16+320)*i; + pks[i] = pk_copy; + + for(size_t j = 0; j<64;j++) + signaturemem[i*(64+16+320)+j] = sigs[i].sig_bytes[j]; + + for(size_t j = 0; j<16;j++) + signaturemem[i*(64+16+320)+64+j] = labels[i].label_bytes[j]; + + // More efficient way to get canonical point rep? + G2> Lambda_copy(Lambdas[i]); + Lambda_copy.to_affine_coordinates(); + stream.clear(); + stream.rdbuf()->pubsetbuf((char*)(signaturemem+i*(64+16+320)+64+16), 320); + stream << Lambda_copy; + size_t written = stream.tellp(); + while (written<320) + signaturemem[i*(64+16+320)+64+16+written++] = 0; + + } + + int res = crypto_sign_ed25519_amd64_51_30k_open_batch( + messages,msglen, + signatures,siglen, + pks, + labels.size()); + + return (res==0); +} + +} // libsnark diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark.hpp b/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark.hpp new file mode 100644 index 0000000..bcf3465 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark.hpp @@ -0,0 +1,674 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a ppzkADSNARK for R1CS. + + This includes: + - class for authentication key (public and symmetric) + - class for authentication verification key (public and symmetric) + - class for proving key + - class for verification key + - class for processed verification key + - class for key tuple (authentication key & proving key & verification key) + - class for authenticated data + - class for proof + - generator algorithm + - authentication key generator algorithm + - prover algorithm + - verifier algorithm (public and symmetric) + - online verifier algorithm (public and symmetric) + + The implementation instantiates the construction in \[BBFR15], which in turn + is based on the r1cs_ppzkadsnark proof system. + + Acronyms: + + - R1CS = "Rank-1 Constraint Systems" + - ppzkADSNARK = "PreProcessing Zero-Knowledge Succinct Non-interactive ARgument of Knowledge Over Authenticated Data" + + References: + +\[BBFR15] +"ADSNARK: Nearly Practical and Privacy-Preserving Proofs on Authenticated Data", +Michael Backes, Manuel Barbosa, Dario Fiore, Raphael M. Reischuk, +IEEE Symposium on Security and Privacy 2015, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_PPZKADSNARK_HPP_ +#define R1CS_PPZKADSNARK_HPP_ + +#include + +#include "algebra/curves/public_params.hpp" +#include "common/data_structures/accumulation_vector.hpp" +#include "algebra/knowledge_commitment/knowledge_commitment.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_params.hpp" +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_signature.hpp" +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_prf.hpp" + +namespace libsnark { + +/******************************** Public authentication parameters ********************************/ + +template +class r1cs_ppzkadsnark_pub_auth_prms; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_pub_auth_prms &pap); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_pub_auth_prms &pap); + +/** + * Public authentication parameters for the R1CS ppzkADSNARK + */ +template +class r1cs_ppzkadsnark_pub_auth_prms { +public: + G1> I1; + + r1cs_ppzkadsnark_pub_auth_prms() {}; + r1cs_ppzkadsnark_pub_auth_prms& operator=(const r1cs_ppzkadsnark_pub_auth_prms &other) = default; + r1cs_ppzkadsnark_pub_auth_prms(const r1cs_ppzkadsnark_pub_auth_prms &other) = default; + r1cs_ppzkadsnark_pub_auth_prms(r1cs_ppzkadsnark_pub_auth_prms &&other) = default; + r1cs_ppzkadsnark_pub_auth_prms(G1> &&I1) : I1(std::move(I1)) {}; + + bool operator==(const r1cs_ppzkadsnark_pub_auth_prms &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzkadsnark_pub_auth_prms &pap); + friend std::istream& operator>> (std::istream &in, r1cs_ppzkadsnark_pub_auth_prms &pap); +}; + +/******************************** Secret authentication key ********************************/ + +template +class r1cs_ppzkadsnark_sec_auth_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_sec_auth_key &key); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_sec_auth_key &key); + +/** + * Secret authentication key for the R1CS ppzkADSNARK + */ +template +class r1cs_ppzkadsnark_sec_auth_key { +public: + Fr> i; + r1cs_ppzkadsnark_skTskp; + r1cs_ppzkadsnark_prfKeyTS; + + r1cs_ppzkadsnark_sec_auth_key() {}; + r1cs_ppzkadsnark_sec_auth_key& operator=(const r1cs_ppzkadsnark_sec_auth_key &other) = default; + r1cs_ppzkadsnark_sec_auth_key(const r1cs_ppzkadsnark_sec_auth_key &other) = default; + r1cs_ppzkadsnark_sec_auth_key(r1cs_ppzkadsnark_sec_auth_key &&other) = default; + r1cs_ppzkadsnark_sec_auth_key(Fr> &&i, + r1cs_ppzkadsnark_skT&&skp, r1cs_ppzkadsnark_prfKeyT&&S) : + i(std::move(i)), + skp(std::move(skp)), + S(std::move(S)) {}; + + bool operator==(const r1cs_ppzkadsnark_sec_auth_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzkadsnark_sec_auth_key &key); + friend std::istream& operator>> (std::istream &in, r1cs_ppzkadsnark_sec_auth_key &key); +}; + +/******************************** Public authentication key ********************************/ + +template +class r1cs_ppzkadsnark_pub_auth_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_pub_auth_key &key); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_pub_auth_key &key); + +/** + * Public authentication key for the R1CS ppzkADSNARK + */ +template +class r1cs_ppzkadsnark_pub_auth_key { +public: + G2> minusI2; + r1cs_ppzkadsnark_vkTvkp; + + r1cs_ppzkadsnark_pub_auth_key() {}; + r1cs_ppzkadsnark_pub_auth_key& operator=(const r1cs_ppzkadsnark_pub_auth_key &other) = default; + r1cs_ppzkadsnark_pub_auth_key(const r1cs_ppzkadsnark_pub_auth_key &other) = default; + r1cs_ppzkadsnark_pub_auth_key(r1cs_ppzkadsnark_pub_auth_key &&other) = default; + r1cs_ppzkadsnark_pub_auth_key(G2> &&minusI2, r1cs_ppzkadsnark_vkT&&vkp) : + minusI2(std::move(minusI2)), + vkp(std::move(vkp)) {}; + + bool operator==(const r1cs_ppzkadsnark_pub_auth_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzkadsnark_pub_auth_key &key); + friend std::istream& operator>> (std::istream &in, r1cs_ppzkadsnark_pub_auth_key &key); +}; + +/******************************** Authentication key material ********************************/ + +template +class r1cs_ppzkadsnark_auth_keys { +public: + r1cs_ppzkadsnark_pub_auth_prms pap; + r1cs_ppzkadsnark_pub_auth_key pak; + r1cs_ppzkadsnark_sec_auth_key sak; + + r1cs_ppzkadsnark_auth_keys() {}; + r1cs_ppzkadsnark_auth_keys(r1cs_ppzkadsnark_auth_keys &&other) = default; + r1cs_ppzkadsnark_auth_keys(r1cs_ppzkadsnark_pub_auth_prms &&pap, + r1cs_ppzkadsnark_pub_auth_key &&pak, + r1cs_ppzkadsnark_sec_auth_key &&sak) : + pap(std::move(pap)), + pak(std::move(pak)), + sak(std::move(sak)) + {} +}; + +/******************************** Authenticated data ********************************/ + +template +class r1cs_ppzkadsnark_auth_data; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_auth_data &data); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_auth_data &data); + +/** + * Authenticated data for the R1CS ppzkADSNARK + */ +template +class r1cs_ppzkadsnark_auth_data { +public: + Fr> mu; + G2> Lambda; + r1cs_ppzkadsnark_sigTsigma; + + r1cs_ppzkadsnark_auth_data() {}; + r1cs_ppzkadsnark_auth_data& operator=(const r1cs_ppzkadsnark_auth_data &other) = default; + r1cs_ppzkadsnark_auth_data(const r1cs_ppzkadsnark_auth_data &other) = default; + r1cs_ppzkadsnark_auth_data(r1cs_ppzkadsnark_auth_data &&other) = default; + r1cs_ppzkadsnark_auth_data(Fr> &&mu, + G2> &&Lambda, + r1cs_ppzkadsnark_sigT&&sigma) : + mu(std::move(mu)), + Lambda(std::move(Lambda)), + sigma(std::move(sigma)) {}; + + bool operator==(const r1cs_ppzkadsnark_auth_data &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzkadsnark_auth_data &key); + friend std::istream& operator>> (std::istream &in, r1cs_ppzkadsnark_auth_data &key); +}; + +/******************************** Proving key ********************************/ + +template +class r1cs_ppzkadsnark_proving_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_proving_key &pk); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_proving_key &pk); + +/** + * A proving key for the R1CS ppzkADSNARK. + */ +template +class r1cs_ppzkadsnark_proving_key { +public: + knowledge_commitment_vector>, G1> > A_query; + knowledge_commitment_vector>, G1> > B_query; + knowledge_commitment_vector>, G1> > C_query; + G1_vector> H_query; // t powers + G1_vector> K_query; + /* Now come the additional elements for ad */ + G1> rA_i_Z_g1; + + r1cs_ppzkadsnark_constraint_system constraint_system; + + r1cs_ppzkadsnark_proving_key() {}; + r1cs_ppzkadsnark_proving_key& operator=(const r1cs_ppzkadsnark_proving_key &other) = default; + r1cs_ppzkadsnark_proving_key(const r1cs_ppzkadsnark_proving_key &other) = default; + r1cs_ppzkadsnark_proving_key(r1cs_ppzkadsnark_proving_key &&other) = default; + r1cs_ppzkadsnark_proving_key(knowledge_commitment_vector>, + G1> > &&A_query, + knowledge_commitment_vector>, + G1> > &&B_query, + knowledge_commitment_vector>, + G1> > &&C_query, + G1_vector> &&H_query, + G1_vector> &&K_query, + G1> &&rA_i_Z_g1, + r1cs_ppzkadsnark_constraint_system &&constraint_system) : + A_query(std::move(A_query)), + B_query(std::move(B_query)), + C_query(std::move(C_query)), + H_query(std::move(H_query)), + K_query(std::move(K_query)), + rA_i_Z_g1(std::move(rA_i_Z_g1)), + constraint_system(std::move(constraint_system)) + {}; + + size_t G1_size() const + { + return 2*(A_query.domain_size() + C_query.domain_size()) + B_query.domain_size() + H_query.size() + K_query.size() + 1; + } + + size_t G2_size() const + { + return B_query.domain_size(); + } + + size_t G1_sparse_size() const + { + return 2*(A_query.size() + C_query.size()) + B_query.size() + H_query.size() + K_query.size() + 1; + } + + size_t G2_sparse_size() const + { + return B_query.size(); + } + + size_t size_in_bits() const + { + return A_query.size_in_bits() + B_query.size_in_bits() + C_query.size_in_bits() + libsnark::size_in_bits(H_query) + libsnark::size_in_bits(K_query) + G1>::size_in_bits(); + } + + void print_size() const + { + print_indent(); printf("* G1 elements in PK: %zu\n", this->G1_size()); + print_indent(); printf("* Non-zero G1 elements in PK: %zu\n", this->G1_sparse_size()); + print_indent(); printf("* G2 elements in PK: %zu\n", this->G2_size()); + print_indent(); printf("* Non-zero G2 elements in PK: %zu\n", this->G2_sparse_size()); + print_indent(); printf("* PK size in bits: %zu\n", this->size_in_bits()); + } + + bool operator==(const r1cs_ppzkadsnark_proving_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzkadsnark_proving_key &pk); + friend std::istream& operator>> (std::istream &in, r1cs_ppzkadsnark_proving_key &pk); +}; + + +/******************************* Verification key ****************************/ + +template +class r1cs_ppzkadsnark_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_verification_key &vk); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_verification_key &vk); + +/** + * A verification key for the R1CS ppzkADSNARK. + */ +template +class r1cs_ppzkadsnark_verification_key { +public: + G2> alphaA_g2; + G1> alphaB_g1; + G2> alphaC_g2; + G2> gamma_g2; + G1> gamma_beta_g1; + G2> gamma_beta_g2; + G2> rC_Z_g2; + + G1> A0; + G1_vector> Ain; + + r1cs_ppzkadsnark_verification_key() = default; + r1cs_ppzkadsnark_verification_key(const G2> &alphaA_g2, + const G1> &alphaB_g1, + const G2> &alphaC_g2, + const G2> &gamma_g2, + const G1> &gamma_beta_g1, + const G2> &gamma_beta_g2, + const G2> &rC_Z_g2, + const G1> A0, + const G1_vector> Ain) : + alphaA_g2(alphaA_g2), + alphaB_g1(alphaB_g1), + alphaC_g2(alphaC_g2), + gamma_g2(gamma_g2), + gamma_beta_g1(gamma_beta_g1), + gamma_beta_g2(gamma_beta_g2), + rC_Z_g2(rC_Z_g2), + A0(A0), + Ain(Ain) + {}; + + size_t G1_size() const + { + return 3 + Ain.size(); + } + + size_t G2_size() const + { + return 5; + } + + size_t size_in_bits() const + { + return G1_size() * G1>::size_in_bits() + G2_size() * G2>::size_in_bits(); // possible zksnark bug + } + + void print_size() const + { + print_indent(); printf("* G1 elements in VK: %zu\n", this->G1_size()); + print_indent(); printf("* G2 elements in VK: %zu\n", this->G2_size()); + print_indent(); printf("* VK size in bits: %zu\n", this->size_in_bits()); + } + + bool operator==(const r1cs_ppzkadsnark_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzkadsnark_verification_key &vk); + friend std::istream& operator>> (std::istream &in, r1cs_ppzkadsnark_verification_key &vk); + + static r1cs_ppzkadsnark_verification_key dummy_verification_key(const size_t input_size); +}; + + +/************************ Processed verification key *************************/ + +template +class r1cs_ppzkadsnark_processed_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_processed_verification_key &pvk); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_processed_verification_key &pvk); + +/** + * A processed verification key for the R1CS ppzkADSNARK. + * + * Compared to a (non-processed) verification key, a processed verification key + * contains a small constant amount of additional pre-computed information that + * enables a faster verification time. + */ +template +class r1cs_ppzkadsnark_processed_verification_key { +public: + G2_precomp> pp_G2_one_precomp; + G2_precomp> vk_alphaA_g2_precomp; + G1_precomp> vk_alphaB_g1_precomp; + G2_precomp> vk_alphaC_g2_precomp; + G2_precomp> vk_rC_Z_g2_precomp; + G2_precomp> vk_gamma_g2_precomp; + G1_precomp> vk_gamma_beta_g1_precomp; + G2_precomp> vk_gamma_beta_g2_precomp; + G2_precomp> vk_rC_i_g2_precomp; + + G1> A0; + G1_vector> Ain; + + std::vector>> proof_g_vki_precomp; + + bool operator==(const r1cs_ppzkadsnark_processed_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzkadsnark_processed_verification_key &pvk); + friend std::istream& operator>> (std::istream &in, r1cs_ppzkadsnark_processed_verification_key &pvk); +}; + + +/********************************** Key pair *********************************/ + +/** + * A key pair for the R1CS ppzkADSNARK, which consists of a proving key and a verification key. + */ +template +class r1cs_ppzkadsnark_keypair { +public: + r1cs_ppzkadsnark_proving_key pk; + r1cs_ppzkadsnark_verification_key vk; + + r1cs_ppzkadsnark_keypair() = default; + r1cs_ppzkadsnark_keypair(const r1cs_ppzkadsnark_keypair &other) = default; + r1cs_ppzkadsnark_keypair(r1cs_ppzkadsnark_proving_key &&pk, + r1cs_ppzkadsnark_verification_key &&vk) : + pk(std::move(pk)), + vk(std::move(vk)) + {} + + r1cs_ppzkadsnark_keypair(r1cs_ppzkadsnark_keypair &&other) = default; +}; + + +/*********************************** Proof ***********************************/ + +template +class r1cs_ppzkadsnark_proof; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_proof &proof); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_proof &proof); + +/** + * A proof for the R1CS ppzkADSNARK. + * + * While the proof has a structure, externally one merely opaquely produces, + * seralizes/deserializes, and verifies proofs. We only expose some information + * about the structure for statistics purposes. + */ +template +class r1cs_ppzkadsnark_proof { +public: + knowledge_commitment>, G1> > g_A; + knowledge_commitment>, G1> > g_B; + knowledge_commitment>, G1> > g_C; + G1> g_H; + G1> g_K; + knowledge_commitment>, G1> > g_Aau; + G1> muA; + + r1cs_ppzkadsnark_proof() + { + // invalid proof with valid curve points + this->g_A.g = G1> ::one(); + this->g_A.h = G1>::one(); + this->g_B.g = G2> ::one(); + this->g_B.h = G1>::one(); + this->g_C.g = G1> ::one(); + this->g_C.h = G1>::one(); + this->g_H = G1>::one(); + this->g_K = G1>::one(); + g_Aau = knowledge_commitment>, G1> > + (G1>::one(),G1>::one()); + this->muA = G1>::one(); + } + r1cs_ppzkadsnark_proof(knowledge_commitment>, + G1> > &&g_A, + knowledge_commitment>, + G1> > &&g_B, + knowledge_commitment>, + G1> > &&g_C, + G1> &&g_H, + G1> &&g_K, + knowledge_commitment>, + G1> > &&g_Aau, + G1> &&muA) : + g_A(std::move(g_A)), + g_B(std::move(g_B)), + g_C(std::move(g_C)), + g_H(std::move(g_H)), + g_K(std::move(g_K)), + g_Aau(std::move(g_Aau)), + muA(std::move(muA)) + {}; + + size_t G1_size() const + { + return 10; + } + + size_t G2_size() const + { + return 1; + } + + size_t size_in_bits() const + { + return G1_size() * G1>::size_in_bits() + G2_size() * G2>::size_in_bits(); + } + + void print_size() const + { + print_indent(); printf("* G1 elements in proof: %zu\n", this->G1_size()); + print_indent(); printf("* G2 elements in proof: %zu\n", this->G2_size()); + print_indent(); printf("* Proof size in bits: %zu\n", this->size_in_bits()); + } + + bool is_well_formed() const + { + return (g_A.g.is_well_formed() && g_A.h.is_well_formed() && + g_B.g.is_well_formed() && g_B.h.is_well_formed() && + g_C.g.is_well_formed() && g_C.h.is_well_formed() && + g_H.is_well_formed() && + g_K.is_well_formed() && + g_Aau.g.is_well_formed() && g_Aau.h.is_well_formed() && + muA.is_well_formed()); + } + + bool operator==(const r1cs_ppzkadsnark_proof &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzkadsnark_proof &proof); + friend std::istream& operator>> (std::istream &in, r1cs_ppzkadsnark_proof &proof); +}; + + +/***************************** Main algorithms *******************************/ + +/** + * R1CS ppZKADSNARK authentication parameters generator algorithm. + */ +template +r1cs_ppzkadsnark_auth_keys r1cs_ppzkadsnark_auth_generator(void); + +/** + * R1CS ppZKADSNARK authentication algorithm. + */ +template +std::vector> r1cs_ppzkadsnark_auth_sign( + const std::vector>> &ins, + const r1cs_ppzkadsnark_sec_auth_key &sk, + const std::vector labels); + +/** + * R1CS ppZKADSNARK authentication verification algorithms. + */ +template +bool r1cs_ppzkadsnark_auth_verify(const std::vector>> &data, + const std::vector> & auth_data, + const r1cs_ppzkadsnark_sec_auth_key &sak, + const std::vector &labels); + +template +bool r1cs_ppzkadsnark_auth_verify(const std::vector>> &data, + const std::vector> & auth_data, + const r1cs_ppzkadsnark_pub_auth_key &pak, + const std::vector &labels); + +/** + * A generator algorithm for the R1CS ppzkADSNARK. + * + * Given a R1CS constraint system CS, this algorithm produces proving and verification keys for CS. + */ +template +r1cs_ppzkadsnark_keypair r1cs_ppzkadsnark_generator(const r1cs_ppzkadsnark_constraint_system &cs, + const r1cs_ppzkadsnark_pub_auth_prms &prms); + +/** + * A prover algorithm for the R1CS ppzkADSNARK. + * + * Given a R1CS primary input X and a R1CS auxiliary input Y, this algorithm + * produces a proof (of knowledge) that attests to the following statement: + * ``there exists Y such that CS(X,Y)=0''. + * Above, CS is the R1CS constraint system that was given as input to the generator algorithm. + */ +template +r1cs_ppzkadsnark_proof r1cs_ppzkadsnark_prover(const r1cs_ppzkadsnark_proving_key &pk, + const r1cs_ppzkadsnark_primary_input &primary_input, + const r1cs_ppzkadsnark_auxiliary_input &auxiliary_input, + const std::vector> &auth_data); + +/* + Below are two variants of verifier algorithm for the R1CS ppzkADSNARK. + + These are the four cases that arise from the following choices: + +1) The verifier accepts a (non-processed) verification key or, instead, a processed verification key. + In the latter case, we call the algorithm an "online verifier". + +2) The verifier uses the symmetric key or the public verification key. + In the former case we call the algorithm a "symmetric verifier". + +*/ + +/** + * Convert a (non-processed) verification key into a processed verification key. + */ +template +r1cs_ppzkadsnark_processed_verification_key r1cs_ppzkadsnark_verifier_process_vk( + const r1cs_ppzkadsnark_verification_key &vk); + +/** + * A symmetric verifier algorithm for the R1CS ppzkADSNARK that + * accepts a non-processed verification key + */ +template +bool r1cs_ppzkadsnark_verifier(const r1cs_ppzkadsnark_verification_key &vk, + const r1cs_ppzkadsnark_proof &proof, + const r1cs_ppzkadsnark_sec_auth_key & sak, + const std::vector &labels); + +/** + * A symmetric verifier algorithm for the R1CS ppzkADSNARK that + * accepts a processed verification key. + */ +template +bool r1cs_ppzkadsnark_online_verifier(const r1cs_ppzkadsnark_processed_verification_key &pvk, + const r1cs_ppzkadsnark_proof &proof, + const r1cs_ppzkadsnark_sec_auth_key & sak, + const std::vector &labels); + + +/** + * A verifier algorithm for the R1CS ppzkADSNARK that + * accepts a non-processed verification key + */ +template +bool r1cs_ppzkadsnark_verifier(const r1cs_ppzkadsnark_verification_key &vk, + const std::vector> &auth_data, + const r1cs_ppzkadsnark_proof &proof, + const r1cs_ppzkadsnark_pub_auth_key & pak, + const std::vector &labels); + +/** + * A verifier algorithm for the R1CS ppzkADSNARK that + * accepts a processed verification key. + */ +template +bool r1cs_ppzkadsnark_online_verifier(const r1cs_ppzkadsnark_processed_verification_key &pvk, + const std::vector> &auth_data, + const r1cs_ppzkadsnark_proof &proof, + const r1cs_ppzkadsnark_pub_auth_key & pak, + const std::vector &labels); + + +} // libsnark + +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark.tcc" + +#endif // R1CS_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark.tcc b/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark.tcc new file mode 100644 index 0000000..5468935 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark.tcc @@ -0,0 +1,1207 @@ +/** @file +***************************************************************************** + +Implementation of interfaces for a ppzkADSNARK for R1CS. + +See r1cs_ppzkadsnark.hpp . + +***************************************************************************** +* @author This file is part of libsnark, developed by SCIPR Lab +* and contributors (see AUTHORS). +* @copyright MIT license (see LICENSE file) +*****************************************************************************/ + +#ifndef R1CS_PPZKADSNARK_TCC_ +#define R1CS_PPZKADSNARK_TCC_ + +#include +#include +#include +#include +#include + +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "algebra/scalar_multiplication/multiexp.hpp" +#include "algebra/scalar_multiplication/kc_multiexp.hpp" +#include "reductions/r1cs_to_qap/r1cs_to_qap.hpp" + +namespace libsnark { + + +template +bool r1cs_ppzkadsnark_pub_auth_prms::operator==(const r1cs_ppzkadsnark_pub_auth_prms &other) const +{ + return (this->I1 == other.I1); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_pub_auth_prms &pap) +{ + out << pap.I1; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_pub_auth_prms &pap) +{ + in >> pap.I1; + + return in; +} + +template +bool r1cs_ppzkadsnark_sec_auth_key::operator==(const r1cs_ppzkadsnark_sec_auth_key &other) const +{ + return (this->i == other.i) && + (this->skp == other.skp) && + (this->S == other.S); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_sec_auth_key &key) +{ + out << key.i; + out << key.skp; + out << key.S; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_sec_auth_key &key) +{ + in >> key.i; + in >> key.skp; + in >> key.S; + + return in; +} + +template +bool r1cs_ppzkadsnark_pub_auth_key::operator==(const r1cs_ppzkadsnark_pub_auth_key &other) const +{ + return (this->minusI2 == other.minusI2) && + (this->vkp == other.vkp); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_pub_auth_key &key) +{ + out << key.minusI2; + out << key.vkp; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_pub_auth_key &key) +{ + in >> key.minusI2; + in >> key.vkp; + + return in; +} + +template +bool r1cs_ppzkadsnark_auth_data::operator==(const r1cs_ppzkadsnark_auth_data &other) const +{ + return (this->mu == other.mu) && + (this->Lambda == other.Lambda) && + (this->sigma == other.sigma); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_auth_data &data) +{ + out << data.mu; + out << data.Lambda; + out << data.sigma; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_auth_data &data) +{ + in >> data.mu; + in >> data.Lambda; + data.sigma; + + return in; +} + +template +bool r1cs_ppzkadsnark_proving_key::operator==(const r1cs_ppzkadsnark_proving_key &other) const +{ + return (this->A_query == other.A_query && + this->B_query == other.B_query && + this->C_query == other.C_query && + this->H_query == other.H_query && + this->K_query == other.K_query && + this->rA_i_Z_g1 == other.rA_i_Z_g1 && + this->constraint_system == other.constraint_system); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_proving_key &pk) +{ + out << pk.A_query; + out << pk.B_query; + out << pk.C_query; + out << pk.H_query; + out << pk.K_query; + out << pk.rA_i_Z_g1; + out << pk.constraint_system; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_proving_key &pk) +{ + in >> pk.A_query; + in >> pk.B_query; + in >> pk.C_query; + in >> pk.H_query; + in >> pk.K_query; + in >> pk.rA_i_Z_g1; + in >> pk.constraint_system; + + return in; +} + +template +bool r1cs_ppzkadsnark_verification_key::operator==(const r1cs_ppzkadsnark_verification_key &other) const +{ + return (this->alphaA_g2 == other.alphaA_g2 && + this->alphaB_g1 == other.alphaB_g1 && + this->alphaC_g2 == other.alphaC_g2 && + this->gamma_g2 == other.gamma_g2 && + this->gamma_beta_g1 == other.gamma_beta_g1 && + this->gamma_beta_g2 == other.gamma_beta_g2 && + this->rC_Z_g2 == other.rC_Z_g2 && + this->A0 == other.A0 && + this->Ain == other.Ain); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_verification_key &vk) +{ + out << vk.alphaA_g2 << OUTPUT_NEWLINE; + out << vk.alphaB_g1 << OUTPUT_NEWLINE; + out << vk.alphaC_g2 << OUTPUT_NEWLINE; + out << vk.gamma_g2 << OUTPUT_NEWLINE; + out << vk.gamma_beta_g1 << OUTPUT_NEWLINE; + out << vk.gamma_beta_g2 << OUTPUT_NEWLINE; + out << vk.rC_Z_g2 << OUTPUT_NEWLINE; + out << vk.A0 << OUTPUT_NEWLINE; + out << vk.Ain << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_verification_key &vk) +{ + in >> vk.alphaA_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.alphaB_g1; + consume_OUTPUT_NEWLINE(in); + in >> vk.alphaC_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.gamma_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.gamma_beta_g1; + consume_OUTPUT_NEWLINE(in); + in >> vk.gamma_beta_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.rC_Z_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.A0; + consume_OUTPUT_NEWLINE(in); + in >> vk.Ain; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +bool r1cs_ppzkadsnark_processed_verification_key::operator==( + const r1cs_ppzkadsnark_processed_verification_key &other) const +{ + bool result = (this->pp_G2_one_precomp == other.pp_G2_one_precomp && + this->vk_alphaA_g2_precomp == other.vk_alphaA_g2_precomp && + this->vk_alphaB_g1_precomp == other.vk_alphaB_g1_precomp && + this->vk_alphaC_g2_precomp == other.vk_alphaC_g2_precomp && + this->vk_rC_Z_g2_precomp == other.vk_rC_Z_g2_precomp && + this->vk_gamma_g2_precomp == other.vk_gamma_g2_precomp && + this->vk_gamma_beta_g1_precomp == other.vk_gamma_beta_g1_precomp && + this->vk_gamma_beta_g2_precomp == other.vk_gamma_beta_g2_precomp && + this->vk_rC_i_g2_precomp == other.vk_rC_i_g2_precomp && + this->A0 == other.A0 && + this->Ain == other.Ain && + this->proof_g_vki_precomp.size() == other.proof_g_vki_precomp.size()); + if (result) { + for(size_t i=0;iproof_g_vki_precomp.size();i++) + result &= this->proof_g_vki_precomp[i] == other.proof_g_vki_precomp[i]; + } + return result; +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_processed_verification_key &pvk) +{ + out << pvk.pp_G2_one_precomp << OUTPUT_NEWLINE; + out << pvk.vk_alphaA_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_alphaB_g1_precomp << OUTPUT_NEWLINE; + out << pvk.vk_alphaC_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_rC_Z_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_gamma_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_gamma_beta_g1_precomp << OUTPUT_NEWLINE; + out << pvk.vk_gamma_beta_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_rC_i_g2_precomp << OUTPUT_NEWLINE; + out << pvk.A0 << OUTPUT_NEWLINE; + out << pvk.Ain << OUTPUT_NEWLINE; + out << pvk.proof_g_vki_precomp << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_processed_verification_key &pvk) +{ + in >> pvk.pp_G2_one_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_alphaA_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_alphaB_g1_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_alphaC_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_rC_Z_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_gamma_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_gamma_beta_g1_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_gamma_beta_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_rC_i_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.A0; + consume_OUTPUT_NEWLINE(in); + in >> pvk.Ain; + consume_OUTPUT_NEWLINE(in); + in >> pvk.proof_g_vki_precomp; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +bool r1cs_ppzkadsnark_proof::operator==(const r1cs_ppzkadsnark_proof &other) const +{ + return (this->g_A == other.g_A && + this->g_B == other.g_B && + this->g_C == other.g_C && + this->g_H == other.g_H && + this->g_K == other.g_K && + this->g_Aau == other.g_Aau && + this->muA == other.muA); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_proof &proof) +{ + out << proof.g_A << OUTPUT_NEWLINE; + out << proof.g_B << OUTPUT_NEWLINE; + out << proof.g_C << OUTPUT_NEWLINE; + out << proof.g_H << OUTPUT_NEWLINE; + out << proof.g_K << OUTPUT_NEWLINE; + out << proof.g_Aau << OUTPUT_NEWLINE; + out << proof.muA << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_proof &proof) +{ + in >> proof.g_A; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_B; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_C; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_H; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_K; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_Aau; + consume_OUTPUT_NEWLINE(in); + in >> proof.muA; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +r1cs_ppzkadsnark_verification_key r1cs_ppzkadsnark_verification_key::dummy_verification_key(const size_t input_size) +{ + r1cs_ppzkadsnark_verification_key result; + result.alphaA_g2 = Fr>::random_element() * G2>::one(); + result.alphaB_g1 = Fr>::random_element() * G1>::one(); + result.alphaC_g2 = Fr>::random_element() * G2>::one(); + result.gamma_g2 = Fr>::random_element() * G2>::one(); + result.gamma_beta_g1 = Fr>::random_element() * G1>::one(); + result.gamma_beta_g2 = Fr>::random_element() * G2>::one(); + result.rC_Z_g2 = Fr>::random_element() * G2>::one(); + + result.A0 = Fr>::random_element() * G1>::one(); + for (size_t i = 0; i < input_size; ++i) + { + result.Ain.emplace_back(Fr>::random_element() * + G1>::one()); + } + + return result; +} + +template +r1cs_ppzkadsnark_auth_keys r1cs_ppzkadsnark_auth_generator(void) { + kpT sigkp = sigGen(); + r1cs_ppzkadsnark_prfKeyTprfseed = prfGen(); + Fr> i = Fr>::random_element(); + G1> I1 = i * G1>::one(); + G2> minusI2 = G2>::zero() - + i * G2>::one(); + return r1cs_ppzkadsnark_auth_keys( + r1cs_ppzkadsnark_pub_auth_prms(std::move(I1)), + r1cs_ppzkadsnark_pub_auth_key(std::move(minusI2),std::move(sigkp.vk)), + r1cs_ppzkadsnark_sec_auth_key(std::move(i),std::move(sigkp.sk),std::move(prfseed))); +} + +template +std::vector> r1cs_ppzkadsnark_auth_sign( + const std::vector>> &ins, + const r1cs_ppzkadsnark_sec_auth_key &sk, + const std::vector labels) { + enter_block("Call to r1cs_ppzkadsnark_auth_sign"); + assert (labels.size()==ins.size()); + std::vector> res; + res.reserve(ins.size()); + for (size_t i = 0; i < ins.size();i++) { + Fr> lambda = prfCompute(sk.S,labels[i]); + G2> Lambda = lambda * G2>::one(); + r1cs_ppzkadsnark_sigTsig = sigSign(sk.skp,labels[i],Lambda); + r1cs_ppzkadsnark_auth_data val(std::move(lambda + sk.i * ins[i]), + std::move(Lambda), + std::move(sig)); + res.emplace_back(val); + } + leave_block("Call to r1cs_ppzkadsnark_auth_sign"); + return std::move(res); +} + +// symmetric +template +bool r1cs_ppzkadsnark_auth_verify(const std::vector>> &data, + const std::vector> & auth_data, + const r1cs_ppzkadsnark_sec_auth_key &sak, + const std::vector &labels) { + enter_block("Call to r1cs_ppzkadsnark_auth_verify"); + assert ((data.size()==labels.size()) && (auth_data.size()==labels.size())); + bool res = true; + for (size_t i = 0; i < data.size();i++) { + Fr> lambda = prfCompute(sak.S,labels[i]); + Fr> mup = lambda + sak.i * data[i]; + res = res && (auth_data[i].mu == mup); + } + leave_block("Call to r1cs_ppzkadsnark_auth_verify"); + return res; +} + +// public +template +bool r1cs_ppzkadsnark_auth_verify(const std::vector>> &data, + const std::vector> & auth_data, + const r1cs_ppzkadsnark_pub_auth_key &pak, + const std::vector &labels) { + enter_block("Call to r1cs_ppzkadsnark_auth_verify"); + assert ((data.size()==labels.size()) && (data.size()==auth_data.size())); + bool res = true; + for (size_t i = 0; i < auth_data.size();i++) { + G2> Mup = auth_data[i].Lambda - data[i] * pak.minusI2; + res = res && (auth_data[i].mu * G2>::one() == Mup); + res = res && sigVerif(pak.vkp,labels[i],auth_data[i].Lambda,auth_data[i].sigma); + } + leave_block("Call to r1cs_ppzkadsnark_auth_verify"); + return res; +} + +template +r1cs_ppzkadsnark_keypair r1cs_ppzkadsnark_generator(const r1cs_ppzkadsnark_constraint_system &cs, + const r1cs_ppzkadsnark_pub_auth_prms &prms) +{ + enter_block("Call to r1cs_ppzkadsnark_generator"); + + /* make the B_query "lighter" if possible */ + r1cs_ppzkadsnark_constraint_system cs_copy(cs); + cs_copy.swap_AB_if_beneficial(); + + /* draw random element at which the QAP is evaluated */ + const Fr> t = Fr>::random_element(); + + qap_instance_evaluation> > qap_inst = + r1cs_to_qap_instance_map_with_evaluation(cs_copy, t); + + print_indent(); printf("* QAP number of variables: %zu\n", qap_inst.num_variables()); + print_indent(); printf("* QAP pre degree: %zu\n", cs_copy.constraints.size()); + print_indent(); printf("* QAP degree: %zu\n", qap_inst.degree()); + print_indent(); printf("* QAP number of input variables: %zu\n", qap_inst.num_inputs()); + + enter_block("Compute query densities"); + size_t non_zero_At = 0, non_zero_Bt = 0, non_zero_Ct = 0, non_zero_Ht = 0; + for (size_t i = 0; i < qap_inst.num_variables()+1; ++i) + { + if (!qap_inst.At[i].is_zero()) + { + ++non_zero_At; + } + if (!qap_inst.Bt[i].is_zero()) + { + ++non_zero_Bt; + } + if (!qap_inst.Ct[i].is_zero()) + { + ++non_zero_Ct; + } + } + for (size_t i = 0; i < qap_inst.degree()+1; ++i) + { + if (!qap_inst.Ht[i].is_zero()) + { + ++non_zero_Ht; + } + } + leave_block("Compute query densities"); + + Fr_vector> At = std::move(qap_inst.At); // qap_inst.At is now in unspecified state, but we do not use it later + Fr_vector> Bt = std::move(qap_inst.Bt); // qap_inst.Bt is now in unspecified state, but we do not use it later + Fr_vector> Ct = std::move(qap_inst.Ct); // qap_inst.Ct is now in unspecified state, but we do not use it later + Fr_vector> Ht = std::move(qap_inst.Ht); // qap_inst.Ht is now in unspecified state, but we do not use it later + + /* append Zt to At,Bt,Ct with */ + At.emplace_back(qap_inst.Zt); + Bt.emplace_back(qap_inst.Zt); + Ct.emplace_back(qap_inst.Zt); + + const Fr> alphaA = Fr>::random_element(), + alphaB = Fr>::random_element(), + alphaC = Fr>::random_element(), + rA = Fr>::random_element(), + rB = Fr>::random_element(), + beta = Fr>::random_element(), + gamma = Fr>::random_element(); + const Fr> rC = rA * rB; + + // consrtuct the same-coefficient-check query (must happen before zeroing out the prefix of At) + Fr_vector> Kt; + Kt.reserve(qap_inst.num_variables()+4); + for (size_t i = 0; i < qap_inst.num_variables()+1; ++i) + { + Kt.emplace_back( beta * (rA * At[i] + rB * Bt[i] + rC * Ct[i] ) ); + } + Kt.emplace_back(beta * rA * qap_inst.Zt); + Kt.emplace_back(beta * rB * qap_inst.Zt); + Kt.emplace_back(beta * rC * qap_inst.Zt); + + const size_t g1_exp_count = 2*(non_zero_At - qap_inst.num_inputs() + non_zero_Ct) + non_zero_Bt + non_zero_Ht + Kt.size(); + const size_t g2_exp_count = non_zero_Bt; + + size_t g1_window = get_exp_window_size> >(g1_exp_count); + size_t g2_window = get_exp_window_size> >(g2_exp_count); + print_indent(); printf("* G1 window: %zu\n", g1_window); + print_indent(); printf("* G2 window: %zu\n", g2_window); + +#ifdef MULTICORE + const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads() +#else + const size_t chunks = 1; +#endif + + enter_block("Generating G1 multiexp table"); + window_table> > g1_table = + get_window_table(Fr>::size_in_bits(), g1_window, + G1>::one()); + leave_block("Generating G1 multiexp table"); + + enter_block("Generating G2 multiexp table"); + window_table> > g2_table = + get_window_table(Fr>::size_in_bits(), + g2_window, G2>::one()); + leave_block("Generating G2 multiexp table"); + + enter_block("Generate R1CS proving key"); + + enter_block("Generate knowledge commitments"); + enter_block("Compute the A-query", false); + knowledge_commitment_vector>, G1> > A_query = + kc_batch_exp(Fr>::size_in_bits(), g1_window, g1_window, g1_table, + g1_table, rA, rA*alphaA, At, chunks); + leave_block("Compute the A-query", false); + + enter_block("Compute the B-query", false); + knowledge_commitment_vector>, G1> > B_query = + kc_batch_exp(Fr>::size_in_bits(), g2_window, g1_window, g2_table, + g1_table, rB, rB*alphaB, Bt, chunks); + leave_block("Compute the B-query", false); + + enter_block("Compute the C-query", false); + knowledge_commitment_vector>, G1> > C_query = + kc_batch_exp(Fr>::size_in_bits(), g1_window, g1_window, g1_table, + g1_table, rC, rC*alphaC, Ct, chunks); + leave_block("Compute the C-query", false); + + enter_block("Compute the H-query", false); + G1_vector> H_query = batch_exp(Fr>::size_in_bits(), g1_window, g1_table, Ht); + leave_block("Compute the H-query", false); + + enter_block("Compute the K-query", false); + G1_vector> K_query = batch_exp(Fr>::size_in_bits(), g1_window, g1_table, Kt); +#ifdef USE_MIXED_ADDITION + batch_to_special> >(K_query); +#endif + leave_block("Compute the K-query", false); + + leave_block("Generate knowledge commitments"); + + leave_block("Generate R1CS proving key"); + + enter_block("Generate R1CS verification key"); + G2> alphaA_g2 = alphaA * G2>::one(); + G1> alphaB_g1 = alphaB * G1>::one(); + G2> alphaC_g2 = alphaC * G2>::one(); + G2> gamma_g2 = gamma * G2>::one(); + G1> gamma_beta_g1 = (gamma * beta) * G1>::one(); + G2> gamma_beta_g2 = (gamma * beta) * G2>::one(); + G2> rC_Z_g2 = (rC * qap_inst.Zt) * G2>::one(); + + enter_block("Generate extra authentication elements"); + G1> rA_i_Z_g1 = (rA * qap_inst.Zt) * prms.I1; + leave_block("Generate extra authentication elements"); + + enter_block("Copy encoded input coefficients for R1CS verification key"); + G1> A0 = A_query[0].g; + G1_vector> Ain; + Ain.reserve(qap_inst.num_inputs()); + for (size_t i = 0; i < qap_inst.num_inputs(); ++i) + { + Ain.emplace_back(A_query[1+i].g); + } + + leave_block("Copy encoded input coefficients for R1CS verification key"); + + leave_block("Generate R1CS verification key"); + + leave_block("Call to r1cs_ppzkadsnark_generator"); + + r1cs_ppzkadsnark_verification_key vk = r1cs_ppzkadsnark_verification_key(alphaA_g2, + alphaB_g1, + alphaC_g2, + gamma_g2, + gamma_beta_g1, + gamma_beta_g2, + rC_Z_g2, + A0, + Ain); + r1cs_ppzkadsnark_proving_key pk = r1cs_ppzkadsnark_proving_key(std::move(A_query), + std::move(B_query), + std::move(C_query), + std::move(H_query), + std::move(K_query), + std::move(rA_i_Z_g1), + std::move(cs_copy)); + + pk.print_size(); + vk.print_size(); + + return r1cs_ppzkadsnark_keypair(std::move(pk), std::move(vk)); +} + +template +r1cs_ppzkadsnark_proof r1cs_ppzkadsnark_prover(const r1cs_ppzkadsnark_proving_key &pk, + const r1cs_ppzkadsnark_primary_input &primary_input, + const r1cs_ppzkadsnark_auxiliary_input &auxiliary_input, + const std::vector> &auth_data) +{ + enter_block("Call to r1cs_ppzkadsnark_prover"); + +#ifdef DEBUG + assert(pk.constraint_system.is_satisfied(primary_input, auxiliary_input)); +#endif + + const Fr> d1 = Fr>::random_element(), + d2 = Fr>::random_element(), + d3 = Fr>::random_element(), + dauth = Fr>::random_element(); + + enter_block("Compute the polynomial H"); + const qap_witness> > qap_wit = r1cs_to_qap_witness_map(pk.constraint_system, primary_input, + auxiliary_input, d1 + dauth, d2, d3); + leave_block("Compute the polynomial H"); + +#ifdef DEBUG + const Fr> t = Fr>::random_element(); + qap_instance_evaluation> > qap_inst = r1cs_to_qap_instance_map_with_evaluation(pk.constraint_system, t); + assert(qap_inst.is_satisfied(qap_wit)); +#endif + + knowledge_commitment>, G1> > g_A = + /* pk.A_query[0] + */ d1*pk.A_query[qap_wit.num_variables()+1]; + knowledge_commitment>, G1> > g_B = + pk.B_query[0] + qap_wit.d2*pk.B_query[qap_wit.num_variables()+1]; + knowledge_commitment>, G1> > g_C = + pk.C_query[0] + qap_wit.d3*pk.C_query[qap_wit.num_variables()+1]; + + knowledge_commitment>, G1> > g_Ain = dauth*pk.A_query[qap_wit.num_variables()+1]; + + G1> g_H = G1>::zero(); + G1> g_K = (pk.K_query[0] + + qap_wit.d1*pk.K_query[qap_wit.num_variables()+1] + + qap_wit.d2*pk.K_query[qap_wit.num_variables()+2] + + qap_wit.d3*pk.K_query[qap_wit.num_variables()+3]); + +#ifdef DEBUG + for (size_t i = 0; i < qap_wit.num_inputs() + 1; ++i) + { + assert(pk.A_query[i].g == G1>::zero()); + } + assert(pk.A_query.domain_size() == qap_wit.num_variables()+2); + assert(pk.B_query.domain_size() == qap_wit.num_variables()+2); + assert(pk.C_query.domain_size() == qap_wit.num_variables()+2); + assert(pk.H_query.size() == qap_wit.degree()+1); + assert(pk.K_query.size() == qap_wit.num_variables()+4); +#endif + +#ifdef MULTICORE + const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads() +#else + const size_t chunks = 1; +#endif + + enter_block("Compute the proof"); + + enter_block("Compute answer to A-query", false); + g_A = g_A + kc_multi_exp_with_mixed_addition>, G1>, Fr> >(pk.A_query, + 1+qap_wit.num_inputs(), 1+qap_wit.num_variables(), + qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_inputs(), + qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), + chunks, true); + leave_block("Compute answer to A-query", false); + + enter_block("Compute answer to Ain-query", false); + g_Ain = g_Ain + kc_multi_exp_with_mixed_addition>, G1>, Fr> >(pk.A_query, + 1, 1+qap_wit.num_inputs(), + qap_wit.coefficients_for_ABCs.begin(), + qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_inputs(), + chunks, true); + //std :: cout << "The input proof term: " << g_Ain << "\n"; + leave_block("Compute answer to Ain-query", false); + + enter_block("Compute answer to B-query", false); + g_B = g_B + kc_multi_exp_with_mixed_addition>, G1>, Fr> >(pk.B_query, + 1, 1+qap_wit.num_variables(), + qap_wit.coefficients_for_ABCs.begin(), + qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), + chunks, true); + leave_block("Compute answer to B-query", false); + + enter_block("Compute answer to C-query", false); + g_C = g_C + kc_multi_exp_with_mixed_addition>, G1>, Fr> >(pk.C_query, + 1, 1+qap_wit.num_variables(), + qap_wit.coefficients_for_ABCs.begin(), + qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), + chunks, true); + leave_block("Compute answer to C-query", false); + + enter_block("Compute answer to H-query", false); + g_H = g_H + multi_exp>, Fr> >(pk.H_query.begin(), + pk.H_query.begin()+qap_wit.degree()+1, + qap_wit.coefficients_for_H.begin(), + qap_wit.coefficients_for_H.begin()+qap_wit.degree()+1, + chunks, true); + leave_block("Compute answer to H-query", false); + + enter_block("Compute answer to K-query", false); + g_K = g_K + multi_exp_with_mixed_addition>, Fr> >(pk.K_query.begin()+1, + pk.K_query.begin()+1+qap_wit.num_variables(), + qap_wit.coefficients_for_ABCs.begin(), + qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), + chunks, true); + leave_block("Compute answer to K-query", false); + + enter_block("Compute extra auth terms", false); + std::vector>> mus; + std::vector>> Ains; + mus.reserve(qap_wit.num_inputs()); + Ains.reserve(qap_wit.num_inputs()); + for (size_t i=0;i> muA = dauth * pk.rA_i_Z_g1; + muA = muA + multi_exp>, Fr> >(Ains.begin(), Ains.begin()+qap_wit.num_inputs(), + mus.begin(), mus.begin()+qap_wit.num_inputs(), + chunks, true); + + // To Do: Decide whether to include relevant parts of auth_data in proof + leave_block("Compute extra auth terms", false); + + leave_block("Compute the proof"); + + leave_block("Call to r1cs_ppzkadsnark_prover"); + + r1cs_ppzkadsnark_proof proof = r1cs_ppzkadsnark_proof(std::move(g_A), + std::move(g_B), + std::move(g_C), + std::move(g_H), + std::move(g_K), + std::move(g_Ain), + std::move(muA)); + proof.print_size(); + + return proof; +} + +template +r1cs_ppzkadsnark_processed_verification_key r1cs_ppzkadsnark_verifier_process_vk( + const r1cs_ppzkadsnark_verification_key &vk) +{ + enter_block("Call to r1cs_ppzkadsnark_verifier_process_vk"); + + r1cs_ppzkadsnark_processed_verification_key pvk; + pvk.pp_G2_one_precomp = snark_pp::precompute_G2(G2>::one()); + pvk.vk_alphaA_g2_precomp = snark_pp::precompute_G2(vk.alphaA_g2); + pvk.vk_alphaB_g1_precomp = snark_pp::precompute_G1(vk.alphaB_g1); + pvk.vk_alphaC_g2_precomp = snark_pp::precompute_G2(vk.alphaC_g2); + pvk.vk_rC_Z_g2_precomp = snark_pp::precompute_G2(vk.rC_Z_g2); + pvk.vk_gamma_g2_precomp = snark_pp::precompute_G2(vk.gamma_g2); + pvk.vk_gamma_beta_g1_precomp = snark_pp::precompute_G1(vk.gamma_beta_g1); + pvk.vk_gamma_beta_g2_precomp = snark_pp::precompute_G2(vk.gamma_beta_g2); + + enter_block("Pre-processing for additional auth elements"); + G2_precomp> vk_rC_z_g2_precomp = snark_pp::precompute_G2(vk.rC_Z_g2); + + pvk.A0 = G1>(vk.A0); + pvk.Ain = G1_vector>(vk.Ain); + + pvk.proof_g_vki_precomp.reserve(pvk.Ain.size()); + for(size_t i = 0; i < pvk.Ain.size();i++) { + pvk.proof_g_vki_precomp.emplace_back(snark_pp::precompute_G1(pvk.Ain[i])); + } + + leave_block("Pre-processing for additional auth elements"); + + leave_block("Call to r1cs_ppzkadsnark_verifier_process_vk"); + + return pvk; +} + +// symmetric +template +bool r1cs_ppzkadsnark_online_verifier(const r1cs_ppzkadsnark_processed_verification_key &pvk, + const r1cs_ppzkadsnark_proof &proof, + const r1cs_ppzkadsnark_sec_auth_key & sak, + const std::vector &labels) +{ + bool result = true; + enter_block("Call to r1cs_ppzkadsnark_online_verifier"); + + enter_block("Check if the proof is well-formed"); + if (!proof.is_well_formed()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("At least one of the proof elements does not lie on the curve.\n"); + } + result = false; + } + leave_block("Check if the proof is well-formed"); + + enter_block("Checking auth-specific elements"); + + enter_block("Checking A1"); + + enter_block("Compute PRFs"); + std::vector>>lambdas; + lambdas.reserve(labels.size()); + for (size_t i = 0; i < labels.size();i++) { + lambdas.emplace_back(prfCompute(sak.S,labels[i])); + } + leave_block("Compute PRFs"); + G1> prodA = sak.i * proof.g_Aau.g; + prodA = prodA + multi_exp>, Fr> >(pvk.Ain.begin(), + pvk.Ain.begin() + labels.size(), + lambdas.begin(), + lambdas.begin() + labels.size(), 1, true); + + bool result_auth = true; + + if (!(prodA == proof.muA)) { + if (!inhibit_profiling_info) + { + print_indent(); printf("Authentication check failed.\n"); + } + result_auth = false; + } + + leave_block("Checking A1"); + + enter_block("Checking A2"); + G1_precomp> proof_g_Aau_g_precomp = snark_pp::precompute_G1(proof.g_Aau.g); + G1_precomp> proof_g_Aau_h_precomp = snark_pp::precompute_G1(proof.g_Aau.h); + Fqk> kc_Aau_1 = snark_pp::miller_loop(proof_g_Aau_g_precomp, pvk.vk_alphaA_g2_precomp); + Fqk> kc_Aau_2 = snark_pp::miller_loop(proof_g_Aau_h_precomp, pvk.pp_G2_one_precomp); + GT> kc_Aau = snark_pp::final_exponentiation(kc_Aau_1 * kc_Aau_2.unitary_inverse()); + if (kc_Aau != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Knowledge commitment for Aau query incorrect.\n"); + } + result_auth = false; + } + leave_block("Checking A2"); + + leave_block("Checking auth-specific elements"); + + result &= result_auth; + + enter_block("Online pairing computations"); + enter_block("Check knowledge commitment for A is valid"); + G1_precomp> proof_g_A_g_precomp = snark_pp::precompute_G1(proof.g_A.g); + G1_precomp> proof_g_A_h_precomp = snark_pp::precompute_G1(proof.g_A.h); + Fqk> kc_A_1 = snark_pp::miller_loop(proof_g_A_g_precomp, pvk.vk_alphaA_g2_precomp); + Fqk> kc_A_2 = snark_pp::miller_loop(proof_g_A_h_precomp, pvk.pp_G2_one_precomp); + GT> kc_A = snark_pp::final_exponentiation(kc_A_1 * kc_A_2.unitary_inverse()); + if (kc_A != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Knowledge commitment for A query incorrect.\n"); + } + result = false; + } + leave_block("Check knowledge commitment for A is valid"); + + enter_block("Check knowledge commitment for B is valid"); + G2_precomp> proof_g_B_g_precomp = snark_pp::precompute_G2(proof.g_B.g); + G1_precomp> proof_g_B_h_precomp = snark_pp::precompute_G1(proof.g_B.h); + Fqk> kc_B_1 = snark_pp::miller_loop(pvk.vk_alphaB_g1_precomp, proof_g_B_g_precomp); + Fqk> kc_B_2 = snark_pp::miller_loop(proof_g_B_h_precomp, pvk.pp_G2_one_precomp); + GT> kc_B = snark_pp::final_exponentiation(kc_B_1 * kc_B_2.unitary_inverse()); + if (kc_B != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Knowledge commitment for B query incorrect.\n"); + } + result = false; + } + leave_block("Check knowledge commitment for B is valid"); + + enter_block("Check knowledge commitment for C is valid"); + G1_precomp> proof_g_C_g_precomp = snark_pp::precompute_G1(proof.g_C.g); + G1_precomp> proof_g_C_h_precomp = snark_pp::precompute_G1(proof.g_C.h); + Fqk> kc_C_1 = snark_pp::miller_loop(proof_g_C_g_precomp, pvk.vk_alphaC_g2_precomp); + Fqk> kc_C_2 = snark_pp::miller_loop(proof_g_C_h_precomp, pvk.pp_G2_one_precomp); + GT> kc_C = snark_pp::final_exponentiation(kc_C_1 * kc_C_2.unitary_inverse()); + if (kc_C != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Knowledge commitment for C query incorrect.\n"); + } + result = false; + } + leave_block("Check knowledge commitment for C is valid"); + + G1> Aacc = pvk.A0 + proof.g_Aau.g + proof.g_A.g; + + enter_block("Check QAP divisibility"); + G1_precomp> proof_g_Aacc_precomp = snark_pp::precompute_G1(Aacc); + G1_precomp> proof_g_H_precomp = snark_pp::precompute_G1(proof.g_H); + Fqk> QAP_1 = snark_pp::miller_loop(proof_g_Aacc_precomp, proof_g_B_g_precomp); + Fqk> QAP_23 = snark_pp::double_miller_loop(proof_g_H_precomp, pvk.vk_rC_Z_g2_precomp, + proof_g_C_g_precomp, pvk.pp_G2_one_precomp); + GT> QAP = snark_pp::final_exponentiation(QAP_1 * QAP_23.unitary_inverse()); + if (QAP != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("QAP divisibility check failed.\n"); + } + result = false; + } + leave_block("Check QAP divisibility"); + + enter_block("Check same coefficients were used"); + G1_precomp> proof_g_K_precomp = snark_pp::precompute_G1(proof.g_K); + G1_precomp> proof_g_Aacc_C_precomp = snark_pp::precompute_G1(Aacc + proof.g_C.g); + Fqk> K_1 = snark_pp::miller_loop(proof_g_K_precomp, pvk.vk_gamma_g2_precomp); + Fqk> K_23 = snark_pp::double_miller_loop(proof_g_Aacc_C_precomp, pvk.vk_gamma_beta_g2_precomp, + pvk.vk_gamma_beta_g1_precomp, proof_g_B_g_precomp); + GT> K = snark_pp::final_exponentiation(K_1 * K_23.unitary_inverse()); + if (K != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Same-coefficient check failed.\n"); + } + result = false; + } + leave_block("Check same coefficients were used"); + leave_block("Online pairing computations"); + leave_block("Call to r1cs_ppzkadsnark_online_verifier"); + + return result; +} + +template +bool r1cs_ppzkadsnark_verifier(const r1cs_ppzkadsnark_verification_key &vk, + const r1cs_ppzkadsnark_proof &proof, + const r1cs_ppzkadsnark_sec_auth_key &sak, + const std::vector &labels) +{ + enter_block("Call to r1cs_ppzkadsnark_verifier"); + r1cs_ppzkadsnark_processed_verification_key pvk = r1cs_ppzkadsnark_verifier_process_vk(vk); + bool result = r1cs_ppzkadsnark_online_verifier(pvk, proof, sak, labels); + leave_block("Call to r1cs_ppzkadsnark_verifier"); + return result; +} + + +// public +template +bool r1cs_ppzkadsnark_online_verifier(const r1cs_ppzkadsnark_processed_verification_key &pvk, + const std::vector> &auth_data, + const r1cs_ppzkadsnark_proof &proof, + const r1cs_ppzkadsnark_pub_auth_key & pak, + const std::vector &labels) +{ + bool result = true; + enter_block("Call to r1cs_ppzkadsnark_online_verifier"); + + enter_block("Check if the proof is well-formed"); + if (!proof.is_well_formed()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("At least one of the proof elements does not lie on the curve.\n"); + } + result = false; + } + leave_block("Check if the proof is well-formed"); + + enter_block("Checking auth-specific elements"); + assert (labels.size()==auth_data.size()); + + enter_block("Checking A1"); + + enter_block("Checking signatures"); + std::vector>> Lambdas; + std::vector> sigs; + Lambdas.reserve(labels.size()); + sigs.reserve(labels.size()); + for (size_t i = 0; i < labels.size();i++) { + Lambdas.emplace_back(auth_data[i].Lambda); + sigs.emplace_back(auth_data[i].sigma); + } + bool result_auth = sigBatchVerif(pak.vkp,labels,Lambdas,sigs); + if (! result_auth) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Auth sig check failed.\n"); + } + } + + leave_block("Checking signatures"); + + enter_block("Checking pairings"); + // To Do: Decide whether to move pak and lambda preprocessing to offline + std::vector>> g_Lambdas_precomp; + g_Lambdas_precomp.reserve(auth_data.size()); + for(size_t i=0; i < auth_data.size(); i++) + g_Lambdas_precomp.emplace_back(snark_pp::precompute_G2(auth_data[i].Lambda)); + G2_precomp> g_minusi_precomp = snark_pp::precompute_G2(pak.minusI2); + + enter_block("Computation"); + Fqk> accum; + if(auth_data.size() % 2 == 1) { + accum = snark_pp::miller_loop(pvk.proof_g_vki_precomp[0] , g_Lambdas_precomp[0]); + } + else { + accum = Fqk>::one(); + } + for(size_t i = auth_data.size() % 2; i < labels.size();i=i+2) { + accum = accum * snark_pp::double_miller_loop(pvk.proof_g_vki_precomp[i] , g_Lambdas_precomp[i], + pvk.proof_g_vki_precomp[i+1], g_Lambdas_precomp[i+1]); + } + G1_precomp> proof_g_muA_precomp = snark_pp::precompute_G1(proof.muA); + G1_precomp> proof_g_Aau_precomp = snark_pp::precompute_G1(proof.g_Aau.g); + Fqk> accum2 = snark_pp::double_miller_loop(proof_g_muA_precomp, pvk.pp_G2_one_precomp, + proof_g_Aau_precomp, g_minusi_precomp); + GT> authPair = snark_pp::final_exponentiation(accum * accum2.unitary_inverse()); + if (authPair != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Auth pairing check failed.\n"); + } + result_auth = false; + } + leave_block("Computation"); + leave_block("Checking pairings"); + + + if (!(result_auth)) { + if (!inhibit_profiling_info) + { + print_indent(); printf("Authentication check failed.\n"); + } + } + + leave_block("Checking A1"); + + enter_block("Checking A2"); + G1_precomp> proof_g_Aau_g_precomp = snark_pp::precompute_G1(proof.g_Aau.g); + G1_precomp> proof_g_Aau_h_precomp = snark_pp::precompute_G1(proof.g_Aau.h); + Fqk> kc_Aau_1 = snark_pp::miller_loop(proof_g_Aau_g_precomp, pvk.vk_alphaA_g2_precomp); + Fqk> kc_Aau_2 = snark_pp::miller_loop(proof_g_Aau_h_precomp, pvk.pp_G2_one_precomp); + GT> kc_Aau = snark_pp::final_exponentiation(kc_Aau_1 * kc_Aau_2.unitary_inverse()); + if (kc_Aau != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Knowledge commitment for Aau query incorrect.\n"); + } + result_auth = false; + } + leave_block("Checking A2"); + + leave_block("Checking auth-specific elements"); + + result &= result_auth; + + enter_block("Online pairing computations"); + enter_block("Check knowledge commitment for A is valid"); + G1_precomp> proof_g_A_g_precomp = snark_pp::precompute_G1(proof.g_A.g); + G1_precomp> proof_g_A_h_precomp = snark_pp::precompute_G1(proof.g_A.h); + Fqk> kc_A_1 = snark_pp::miller_loop(proof_g_A_g_precomp, pvk.vk_alphaA_g2_precomp); + Fqk> kc_A_2 = snark_pp::miller_loop(proof_g_A_h_precomp, pvk.pp_G2_one_precomp); + GT> kc_A = snark_pp::final_exponentiation(kc_A_1 * kc_A_2.unitary_inverse()); + if (kc_A != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Knowledge commitment for A query incorrect.\n"); + } + result = false; + } + leave_block("Check knowledge commitment for A is valid"); + + enter_block("Check knowledge commitment for B is valid"); + G2_precomp> proof_g_B_g_precomp = snark_pp::precompute_G2(proof.g_B.g); + G1_precomp> proof_g_B_h_precomp = snark_pp::precompute_G1(proof.g_B.h); + Fqk> kc_B_1 = snark_pp::miller_loop(pvk.vk_alphaB_g1_precomp, proof_g_B_g_precomp); + Fqk> kc_B_2 = snark_pp::miller_loop(proof_g_B_h_precomp, pvk.pp_G2_one_precomp); + GT> kc_B = snark_pp::final_exponentiation(kc_B_1 * kc_B_2.unitary_inverse()); + if (kc_B != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Knowledge commitment for B query incorrect.\n"); + } + result = false; + } + leave_block("Check knowledge commitment for B is valid"); + + enter_block("Check knowledge commitment for C is valid"); + G1_precomp> proof_g_C_g_precomp = snark_pp::precompute_G1(proof.g_C.g); + G1_precomp> proof_g_C_h_precomp = snark_pp::precompute_G1(proof.g_C.h); + Fqk> kc_C_1 = snark_pp::miller_loop(proof_g_C_g_precomp, pvk.vk_alphaC_g2_precomp); + Fqk> kc_C_2 = snark_pp::miller_loop(proof_g_C_h_precomp, pvk.pp_G2_one_precomp); + GT> kc_C = snark_pp::final_exponentiation(kc_C_1 * kc_C_2.unitary_inverse()); + if (kc_C != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Knowledge commitment for C query incorrect.\n"); + } + result = false; + } + leave_block("Check knowledge commitment for C is valid"); + + G1> Aacc = pvk.A0 + proof.g_Aau.g + proof.g_A.g; + + enter_block("Check QAP divisibility"); + G1_precomp> proof_g_Aacc_precomp = snark_pp::precompute_G1(Aacc); + G1_precomp> proof_g_H_precomp = snark_pp::precompute_G1(proof.g_H); + Fqk> QAP_1 = snark_pp::miller_loop(proof_g_Aacc_precomp, proof_g_B_g_precomp); + Fqk> QAP_23 = snark_pp::double_miller_loop(proof_g_H_precomp, pvk.vk_rC_Z_g2_precomp, + proof_g_C_g_precomp, pvk.pp_G2_one_precomp); + GT> QAP = snark_pp::final_exponentiation(QAP_1 * QAP_23.unitary_inverse()); + if (QAP != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("QAP divisibility check failed.\n"); + } + result = false; + } + leave_block("Check QAP divisibility"); + + enter_block("Check same coefficients were used"); + G1_precomp> proof_g_K_precomp = snark_pp::precompute_G1(proof.g_K); + G1_precomp> proof_g_Aacc_C_precomp = snark_pp::precompute_G1(Aacc + proof.g_C.g); + Fqk> K_1 = snark_pp::miller_loop(proof_g_K_precomp, pvk.vk_gamma_g2_precomp); + Fqk> K_23 = snark_pp::double_miller_loop(proof_g_Aacc_C_precomp, pvk.vk_gamma_beta_g2_precomp, + pvk.vk_gamma_beta_g1_precomp, proof_g_B_g_precomp); + GT> K = snark_pp::final_exponentiation(K_1 * K_23.unitary_inverse()); + if (K != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Same-coefficient check failed.\n"); + } + result = false; + } + leave_block("Check same coefficients were used"); + leave_block("Online pairing computations"); + leave_block("Call to r1cs_ppzkadsnark_online_verifier"); + + return result; +} + +// public +template +bool r1cs_ppzkadsnark_verifier(const r1cs_ppzkadsnark_verification_key &vk, + const std::vector> &auth_data, + const r1cs_ppzkadsnark_proof &proof, + const r1cs_ppzkadsnark_pub_auth_key &pak, + const std::vector &labels) +{ + assert(labels.size() == auth_data.size()); + enter_block("Call to r1cs_ppzkadsnark_verifier"); + r1cs_ppzkadsnark_processed_verification_key pvk = r1cs_ppzkadsnark_verifier_process_vk(vk); + bool result = r1cs_ppzkadsnark_online_verifier(pvk, auth_data, proof, pak,labels); + leave_block("Call to r1cs_ppzkadsnark_verifier"); + return result; +} + +} // libsnark +#endif // R1CS_PPZKADSNARK_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_params.hpp b/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_params.hpp new file mode 100644 index 0000000..ebfefe7 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_params.hpp @@ -0,0 +1,57 @@ +/** @file + ***************************************************************************** + + Declaration of public-parameter selector for the R1CS ppzkADSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_PPZKADSNARK_PARAMS_HPP_ +#define R1CS_PPZKADSNARK_PARAMS_HPP_ + +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" + +namespace libsnark { + +class labelT { +public: + unsigned char label_bytes[16]; + labelT() {}; +}; + +/** + * Below are various template aliases (used for convenience). + */ + +template +using snark_pp = typename r1cs_ppzkadsnark_ppT::snark_pp; + +template +using r1cs_ppzkadsnark_constraint_system = r1cs_constraint_system>>; + +template +using r1cs_ppzkadsnark_primary_input = r1cs_primary_input> >; + +template +using r1cs_ppzkadsnark_auxiliary_input = r1cs_auxiliary_input> >; + +template +using r1cs_ppzkadsnark_skT = typename r1cs_ppzkadsnark_ppT::skT; + +template +using r1cs_ppzkadsnark_vkT = typename r1cs_ppzkadsnark_ppT::vkT; + +template +using r1cs_ppzkadsnark_sigT = typename r1cs_ppzkadsnark_ppT::sigT; + +template +using r1cs_ppzkadsnark_prfKeyT = typename r1cs_ppzkadsnark_ppT::prfKeyT; + + +} // libsnark + +#endif // R1CS_PPZKADSNARK_PARAMS_HPP_ + diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_prf.hpp b/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_prf.hpp new file mode 100644 index 0000000..188d755 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_prf.hpp @@ -0,0 +1,27 @@ +/** @file + ***************************************************************************** + + Generic PRF interface for ADSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PRF_HPP_ +#define PRF_HPP_ + +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_params.hpp" + +namespace libsnark { + +template +r1cs_ppzkadsnark_prfKeyT prfGen(); + +template +Fr> prfCompute(const r1cs_ppzkadsnark_prfKeyT &key, const labelT &label); + +} // libsnark + +#endif // PRF_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_signature.hpp b/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_signature.hpp new file mode 100644 index 0000000..3218a9b --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_signature.hpp @@ -0,0 +1,46 @@ +/** @file + ***************************************************************************** + + Generic signature interface for ADSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +/** @file + ***************************************************************************** + * @author This file was deed to libsnark by Manuel Barbosa. + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SIGNATURE_HPP_ +#define SIGNATURE_HPP_ + +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_params.hpp" + +namespace libsnark { + +template +class kpT { +public: + r1cs_ppzkadsnark_skT sk; + r1cs_ppzkadsnark_vkT vk; +}; + +template +kpT sigGen(void); + +template +r1cs_ppzkadsnark_sigT sigSign(const r1cs_ppzkadsnark_skT &sk, const labelT &label, const G2> &Lambda); + +template +bool sigVerif(const r1cs_ppzkadsnark_vkT &vk, const labelT &label, const G2> &Lambda, const r1cs_ppzkadsnark_sigT &sig); + +template +bool sigBatchVerif(const r1cs_ppzkadsnark_vkT &vk, const std::vector &labels, const std::vector>> &Lambdas, const std::vector> &sigs); + +} // libsnark + +#endif // SIGNATURE_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark.hpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark.hpp new file mode 100644 index 0000000..139c083 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark.hpp @@ -0,0 +1,258 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a ppzkSNARK for BACS. + + This includes: + - class for proving key + - class for verification key + - class for processed verification key + - class for key pair (proving key & verification key) + - class for proof + - generator algorithm + - prover algorithm + - verifier algorithm (with strong or weak input consistency) + - online verifier algorithm (with strong or weak input consistency) + + The implementation is a straightforward combination of: + (1) a BACS-to-R1CS reduction, and + (2) a ppzkSNARK for R1CS. + + + Acronyms: + + - BACS = "Bilinear Arithmetic Circuit Satisfiability" + - R1CS = "Rank-1 Constraint System" + - ppzkSNARK = "PreProcessing Zero-Knowledge Succinct Non-interactive ARgument of Knowledge" + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BACS_PPZKSNARK_HPP_ +#define BACS_PPZKSNARK_HPP_ + +#include "relations/circuit_satisfaction_problems/bacs/bacs.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" +#include "zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark_params.hpp" + +namespace libsnark { + +/******************************** Proving key ********************************/ + +template +class bacs_ppzksnark_proving_key; + +template +std::ostream& operator<<(std::ostream &out, const bacs_ppzksnark_proving_key &pk); + +template +std::istream& operator>>(std::istream &in, bacs_ppzksnark_proving_key &pk); + +/** + * A proving key for the BACS ppzkSNARK. + */ +template +class bacs_ppzksnark_proving_key { +public: + bacs_ppzksnark_circuit circuit; + r1cs_ppzksnark_proving_key r1cs_pk; + + bacs_ppzksnark_proving_key() {}; + bacs_ppzksnark_proving_key(const bacs_ppzksnark_proving_key &other) = default; + bacs_ppzksnark_proving_key(bacs_ppzksnark_proving_key &&other) = default; + bacs_ppzksnark_proving_key(const bacs_ppzksnark_circuit &circuit, + const r1cs_ppzksnark_proving_key &r1cs_pk) : + circuit(circuit), r1cs_pk(r1cs_pk) + {} + bacs_ppzksnark_proving_key(bacs_ppzksnark_circuit &&circuit, + r1cs_ppzksnark_proving_key &&r1cs_pk) : + circuit(std::move(circuit)), r1cs_pk(std::move(r1cs_pk)) + {} + + bacs_ppzksnark_proving_key& operator=(const bacs_ppzksnark_proving_key &other) = default; + + size_t G1_size() const + { + return r1cs_pk.G1_size(); + } + + size_t G2_size() const + { + return r1cs_pk.G2_size(); + } + + size_t G1_sparse_size() const + { + return r1cs_pk.G1_sparse_size(); + } + + size_t G2_sparse_size() const + { + return r1cs_pk.G2_sparse_size(); + } + + size_t size_in_bits() const + { + return r1cs_pk.size_in_bits(); + } + + void print_size() const + { + r1cs_pk.print_size(); + } + + bool operator==(const bacs_ppzksnark_proving_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const bacs_ppzksnark_proving_key &pk); + friend std::istream& operator>> (std::istream &in, bacs_ppzksnark_proving_key &pk); +}; + + +/******************************* Verification key ****************************/ + +/** + * A verification key for the BACS ppzkSNARK. + */ +template +using bacs_ppzksnark_verification_key = r1cs_ppzksnark_verification_key; + + +/************************ Processed verification key *************************/ + +/** + * A processed verification key for the BACS ppzkSNARK. + * + * Compared to a (non-processed) verification key, a processed verification key + * contains a small constant amount of additional pre-computed information that + * enables a faster verification time. + */ +template +using bacs_ppzksnark_processed_verification_key = r1cs_ppzksnark_processed_verification_key; + + +/********************************** Key pair *********************************/ + +/** + * A key pair for the BACS ppzkSNARK, which consists of a proving key and a verification key. + */ +template +class bacs_ppzksnark_keypair { +public: + bacs_ppzksnark_proving_key pk; + bacs_ppzksnark_verification_key vk; + + bacs_ppzksnark_keypair() {}; + bacs_ppzksnark_keypair(bacs_ppzksnark_keypair &&other) = default; + bacs_ppzksnark_keypair(const bacs_ppzksnark_proving_key &pk, + const bacs_ppzksnark_verification_key &vk) : + pk(pk), + vk(vk) + {} + + bacs_ppzksnark_keypair(bacs_ppzksnark_proving_key &&pk, + bacs_ppzksnark_verification_key &&vk) : + pk(std::move(pk)), + vk(std::move(vk)) + {} +}; + + +/*********************************** Proof ***********************************/ + +/** + * A proof for the BACS ppzkSNARK. + */ +template +using bacs_ppzksnark_proof = r1cs_ppzksnark_proof; + + +/***************************** Main algorithms *******************************/ + +/** + * A generator algorithm for the BACS ppzkSNARK. + * + * Given a BACS circuit C, this algorithm produces proving and verification keys for C. + */ +template +bacs_ppzksnark_keypair bacs_ppzksnark_generator(const bacs_ppzksnark_circuit &circuit); + +/** + * A prover algorithm for the BACS ppzkSNARK. + * + * Given a BACS primary input X and a BACS auxiliary input Y, this algorithm + * produces a proof (of knowledge) that attests to the following statement: + * ``there exists Y such that C(X,Y)=0''. + * Above, C is the BACS circuit that was given as input to the generator algorithm. + */ +template +bacs_ppzksnark_proof bacs_ppzksnark_prover(const bacs_ppzksnark_proving_key &pk, + const bacs_ppzksnark_primary_input &primary_input, + const bacs_ppzksnark_auxiliary_input &auxiliary_input); + +/* + Below are four variants of verifier algorithm for the BACS ppzkSNARK. + + These are the four cases that arise from the following two choices: + + (1) The verifier accepts a (non-processed) verification key or, instead, a processed verification key. + In the latter case, we call the algorithm an "online verifier". + + (2) The verifier checks for "weak" input consistency or, instead, "strong" input consistency. + Strong input consistency requires that |primary_input| = C.num_inputs, whereas + weak input consistency requires that |primary_input| <= C.num_inputs (and + the primary input is implicitly padded with zeros up to length C.num_inputs). + */ + +/** + * A verifier algorithm for the BACS ppzkSNARK that: + * (1) accepts a non-processed verification key, and + * (2) has weak input consistency. + */ +template +bool bacs_ppzksnark_verifier_weak_IC(const bacs_ppzksnark_verification_key &vk, + const bacs_ppzksnark_primary_input &primary_input, + const bacs_ppzksnark_proof &proof); + +/** + * A verifier algorithm for the BACS ppzkSNARK that: + * (1) accepts a non-processed verification key, and + * (2) has strong input consistency. + */ +template +bool bacs_ppzksnark_verifier_strong_IC(const bacs_ppzksnark_verification_key &vk, + const bacs_ppzksnark_primary_input &primary_input, + const bacs_ppzksnark_proof &proof); + +/** + * Convert a (non-processed) verification key into a processed verification key. + */ +template +bacs_ppzksnark_processed_verification_key bacs_ppzksnark_verifier_process_vk(const bacs_ppzksnark_verification_key &vk); + +/** + * A verifier algorithm for the BACS ppzkSNARK that: + * (1) accepts a processed verification key, and + * (2) has weak input consistency. + */ +template +bool bacs_ppzksnark_online_verifier_weak_IC(const bacs_ppzksnark_processed_verification_key &pvk, + const bacs_ppzksnark_primary_input &primary_input, + const bacs_ppzksnark_proof &proof); + +/** + * A verifier algorithm for the BACS ppzkSNARK that: + * (1) accepts a processed verification key, and + * (2) has strong input consistency. + */ +template +bool bacs_ppzksnark_online_verifier_strong_IC(const bacs_ppzksnark_processed_verification_key &pvk, + const bacs_ppzksnark_primary_input &primary_input, + const bacs_ppzksnark_proof &proof); + +} // libsnark + +#include "zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark.tcc" + +#endif // BACS_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark.tcc b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark.tcc new file mode 100644 index 0000000..b31b172 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark.tcc @@ -0,0 +1,142 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a ppzkSNARK for BACS. + + See bacs_ppzksnark.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BACS_PPZKSNARK_TCC_ +#define BACS_PPZKSNARK_TCC_ + +#include "reductions/bacs_to_r1cs/bacs_to_r1cs.hpp" + +namespace libsnark { + + +template +bool bacs_ppzksnark_proving_key::operator==(const bacs_ppzksnark_proving_key &other) const +{ + return (this->circuit == other.circuit && + this->r1cs_pk == other.r1cs_pk); +} + +template +std::ostream& operator<<(std::ostream &out, const bacs_ppzksnark_proving_key &pk) +{ + out << pk.circuit << OUTPUT_NEWLINE; + out << pk.r1cs_pk << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, bacs_ppzksnark_proving_key &pk) +{ + in >> pk.circuit; + consume_OUTPUT_NEWLINE(in); + in >> pk.r1cs_pk; + consume_OUTPUT_NEWLINE(in); + + return in; +} + + +template +bacs_ppzksnark_keypair bacs_ppzksnark_generator(const bacs_ppzksnark_circuit &circuit) +{ + typedef Fr FieldT; + + enter_block("Call to bacs_ppzksnark_generator"); + const r1cs_constraint_system r1cs_cs = bacs_to_r1cs_instance_map(circuit); + const r1cs_ppzksnark_keypair r1cs_keypair = r1cs_ppzksnark_generator(r1cs_cs); + leave_block("Call to bacs_ppzksnark_generator"); + + return bacs_ppzksnark_keypair(bacs_ppzksnark_proving_key(circuit, r1cs_keypair.pk), + r1cs_keypair.vk); +} + +template +bacs_ppzksnark_proof bacs_ppzksnark_prover(const bacs_ppzksnark_proving_key &pk, + const bacs_ppzksnark_primary_input &primary_input, + const bacs_ppzksnark_auxiliary_input &auxiliary_input) +{ + typedef Fr FieldT; + + enter_block("Call to bacs_ppzksnark_prover"); + const r1cs_variable_assignment r1cs_va = bacs_to_r1cs_witness_map(pk.circuit, primary_input, auxiliary_input); + const r1cs_auxiliary_input r1cs_ai(r1cs_va.begin() + primary_input.size(), r1cs_va.end()); // TODO: faster to just change bacs_to_r1cs_witness_map into two :( + const r1cs_ppzksnark_proof r1cs_proof = r1cs_ppzksnark_prover(pk.r1cs_pk, primary_input, r1cs_ai); + leave_block("Call to bacs_ppzksnark_prover"); + + return r1cs_proof; +} + +template +bacs_ppzksnark_processed_verification_key bacs_ppzksnark_verifier_process_vk(const bacs_ppzksnark_verification_key &vk) +{ + enter_block("Call to bacs_ppzksnark_verifier_process_vk"); + const bacs_ppzksnark_processed_verification_key pvk = r1cs_ppzksnark_verifier_process_vk(vk); + leave_block("Call to bacs_ppzksnark_verifier_process_vk"); + + return pvk; +} + +template +bool bacs_ppzksnark_verifier_weak_IC(const bacs_ppzksnark_verification_key &vk, + const bacs_ppzksnark_primary_input &primary_input, + const bacs_ppzksnark_proof &proof) +{ + enter_block("Call to bacs_ppzksnark_verifier_weak_IC"); + const bacs_ppzksnark_processed_verification_key pvk = bacs_ppzksnark_verifier_process_vk(vk); + const bool bit = r1cs_ppzksnark_online_verifier_weak_IC(pvk, primary_input, proof); + leave_block("Call to bacs_ppzksnark_verifier_weak_IC"); + + return bit; +} + +template +bool bacs_ppzksnark_verifier_strong_IC(const bacs_ppzksnark_verification_key &vk, + const bacs_ppzksnark_primary_input &primary_input, + const bacs_ppzksnark_proof &proof) +{ + enter_block("Call to bacs_ppzksnark_verifier_strong_IC"); + const bacs_ppzksnark_processed_verification_key pvk = bacs_ppzksnark_verifier_process_vk(vk); + const bool bit = r1cs_ppzksnark_online_verifier_strong_IC(pvk, primary_input, proof); + leave_block("Call to bacs_ppzksnark_verifier_strong_IC"); + + return bit; +} + +template +bool bacs_ppzksnark_online_verifier_weak_IC(const bacs_ppzksnark_processed_verification_key &pvk, + const bacs_ppzksnark_primary_input &primary_input, + const bacs_ppzksnark_proof &proof) +{ + enter_block("Call to bacs_ppzksnark_online_verifier_weak_IC"); + const bool bit = r1cs_ppzksnark_online_verifier_weak_IC(pvk, primary_input, proof); + leave_block("Call to bacs_ppzksnark_online_verifier_weak_IC"); + + return bit; +} + +template +bool bacs_ppzksnark_online_verifier_strong_IC(const bacs_ppzksnark_processed_verification_key &pvk, + const bacs_ppzksnark_primary_input &primary_input, + const bacs_ppzksnark_proof &proof) +{ + enter_block("Call to bacs_ppzksnark_online_verifier_strong_IC"); + const bool bit = r1cs_ppzksnark_online_verifier_strong_IC(pvk, primary_input, proof); + leave_block("Call to bacs_ppzksnark_online_verifier_strong_IC"); + + return bit; +} + +} // libsnark + +#endif // BACS_PPZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark_params.hpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark_params.hpp new file mode 100644 index 0000000..ca3538a --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark_params.hpp @@ -0,0 +1,34 @@ +/** @file + ***************************************************************************** + + Declaration of public-parameter selector for the BACS ppzkSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BACS_PPZKSNARK_PARAMS_HPP_ +#define BACS_PPZKSNARK_PARAMS_HPP_ + +#include "relations/circuit_satisfaction_problems/bacs/bacs.hpp" + +namespace libsnark { + +/** + * Below are various template aliases (used for convenience). + */ + +template +using bacs_ppzksnark_circuit = bacs_circuit >; + +template +using bacs_ppzksnark_primary_input = bacs_primary_input >; + +template +using bacs_ppzksnark_auxiliary_input = bacs_auxiliary_input >; + +} // libsnark + +#endif // BACS_PPZKSNARK_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/bacs_ppzksnark/examples/run_bacs_ppzksnark.hpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/bacs_ppzksnark/examples/run_bacs_ppzksnark.hpp new file mode 100644 index 0000000..1798493 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/bacs_ppzksnark/examples/run_bacs_ppzksnark.hpp @@ -0,0 +1,35 @@ +/** @file + ***************************************************************************** + + Declaration of functionality that runs the BACS ppzkSNARK for + a given BACS example. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_BACS_PPZKSNARK_HPP_ +#define RUN_BACS_PPZKSNARK_HPP_ + +#include "relations/circuit_satisfaction_problems/bacs/examples/bacs_examples.hpp" + +namespace libsnark { + +/** + * Runs the ppzkSNARK (generator, prover, and verifier) for a given + * BACS example (specified by a circuit, primary input, and auxiliary input). + * + * Optionally, also test the serialization routines for keys and proofs. + * (This takes additional time.) + */ +template +bool run_bacs_ppzksnark(const bacs_example > &example, + const bool test_serialization); + +} // libsnark + +#include "zk_proof_systems/ppzksnark/bacs_ppzksnark/examples/run_bacs_ppzksnark.tcc" + +#endif // RUN_BACS_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/bacs_ppzksnark/examples/run_bacs_ppzksnark.tcc b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/bacs_ppzksnark/examples/run_bacs_ppzksnark.tcc new file mode 100644 index 0000000..ecb1a24 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/bacs_ppzksnark/examples/run_bacs_ppzksnark.tcc @@ -0,0 +1,87 @@ +/** @file + ***************************************************************************** + + Implementation of functionality that runs the BACS ppzkSNARK for + a given BACS example. + + See run_bacs_ppzksnark.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_BACS_PPZKSNARK_TCC_ +#define RUN_BACS_PPZKSNARK_TCC_ + +#include "zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark.hpp" + +#include + +#include "common/profiling.hpp" + +namespace libsnark { + +/** + * The code below provides an example of all stages of running a BACS ppzkSNARK. + * + * Of course, in a real-life scenario, we would have three distinct entities, + * mangled into one in the demonstration below. The three entities are as follows. + * (1) The "generator", which runs the ppzkSNARK generator on input a given + * circuit C to create a proving and a verification key for C. + * (2) The "prover", which runs the ppzkSNARK prover on input the proving key, + * a primary input for C, and an auxiliary input for C. + * (3) The "verifier", which runs the ppzkSNARK verifier on input the verification key, + * a primary input for C, and a proof. + */ +template +bool run_bacs_ppzksnark(const bacs_example > &example, + const bool test_serialization) +{ + enter_block("Call to run_bacs_ppzksnark"); + + print_header("BACS ppzkSNARK Generator"); + bacs_ppzksnark_keypair keypair = bacs_ppzksnark_generator(example.circuit); + printf("\n"); print_indent(); print_mem("after generator"); + + print_header("Preprocess verification key"); + bacs_ppzksnark_processed_verification_key pvk = bacs_ppzksnark_verifier_process_vk(keypair.vk); + + if (test_serialization) + { + enter_block("Test serialization of keys"); + keypair.pk = reserialize >(keypair.pk); + keypair.vk = reserialize >(keypair.vk); + pvk = reserialize >(pvk); + leave_block("Test serialization of keys"); + } + + print_header("BACS ppzkSNARK Prover"); + bacs_ppzksnark_proof proof = bacs_ppzksnark_prover(keypair.pk, example.primary_input, example.auxiliary_input); + printf("\n"); print_indent(); print_mem("after prover"); + + if (test_serialization) + { + enter_block("Test serialization of proof"); + proof = reserialize >(proof); + leave_block("Test serialization of proof"); + } + + print_header("BACS ppzkSNARK Verifier"); + bool ans = bacs_ppzksnark_verifier_strong_IC(keypair.vk, example.primary_input, proof); + printf("\n"); print_indent(); print_mem("after verifier"); + printf("* The verification result is: %s\n", (ans ? "PASS" : "FAIL")); + + print_header("BACS ppzkSNARK Online Verifier"); + bool ans2 = bacs_ppzksnark_online_verifier_strong_IC(pvk, example.primary_input, proof); + assert(ans == ans2); + + leave_block("Call to run_bacs_ppzksnark"); + + return ans; +} + +} // libsnark + +#endif // RUN_BACS_PPZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/bacs_ppzksnark/profiling/profile_bacs_ppzksnark.cpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/bacs_ppzksnark/profiling/profile_bacs_ppzksnark.cpp new file mode 100644 index 0000000..585f759 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/bacs_ppzksnark/profiling/profile_bacs_ppzksnark.cpp @@ -0,0 +1,59 @@ +/** @file + ***************************************************************************** + Profiling program that exercises the ppzkSNARK (first generator, then prover, + then verifier) on a synthetic BACS instance. + + The command + + $ src/zk_proof_systems/bacs_ppzksnark/profiling/profile_bacs_ppzksnark 1000 10 + + exercises the ppzkSNARK (first generator, then prover, then verifier) on an BACS instance with 1000 gates and an input consisting of 10 Field elements + + (If you get the error `zmInit ERR:can't protect`, see the discussion [above](#elliptic-curve-choices).) + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include + +#include "common/default_types/bacs_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "relations/circuit_satisfaction_problems/bacs/examples/bacs_examples.hpp" +#include "zk_proof_systems/ppzksnark/bacs_ppzksnark/examples/run_bacs_ppzksnark.hpp" + +using namespace libsnark; + +int main(int argc, const char * argv[]) +{ + default_bacs_ppzksnark_pp::init_public_params(); + start_profiling(); + + if (argc == 2 && strcmp(argv[1], "-v") == 0) + { + print_compilation_info(); + return 0; + } + + if (argc != 3) + { + printf("usage: %s num_gates primary_input_size\n", argv[0]); + return 1; + } + const int num_gates = atoi(argv[1]); + int primary_input_size = atoi(argv[2]); + + const size_t auxiliary_input_size = 0; + const size_t num_outputs = num_gates / 2; + + enter_block("Generate BACS example"); + bacs_example > example = generate_bacs_example >(primary_input_size, auxiliary_input_size, num_gates, num_outputs); + leave_block("Generate BACS example"); + + print_header("(enter) Profile BACS ppzkSNARK"); + const bool test_serialization = true; + run_bacs_ppzksnark(example, test_serialization); + print_header("(leave) Profile BACS ppzkSNARK"); +} diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/bacs_ppzksnark/tests/test_bacs_ppzksnark.cpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/bacs_ppzksnark/tests/test_bacs_ppzksnark.cpp new file mode 100644 index 0000000..6dede05 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/bacs_ppzksnark/tests/test_bacs_ppzksnark.cpp @@ -0,0 +1,46 @@ +/** @file + ***************************************************************************** + Test program that exercises the ppzkSNARK (first generator, then + prover, then verifier) on a synthetic BACS instance. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include + +#include "common/default_types/bacs_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "relations/circuit_satisfaction_problems/bacs/examples/bacs_examples.hpp" +#include "zk_proof_systems/ppzksnark/bacs_ppzksnark/examples/run_bacs_ppzksnark.hpp" + +using namespace libsnark; + +template +void test_bacs_ppzksnark(const size_t primary_input_size, + const size_t auxiliary_input_size, + const size_t num_gates, + const size_t num_outputs) +{ + print_header("(enter) Test BACS ppzkSNARK"); + + const bool test_serialization = true; + const bacs_example > example = generate_bacs_example >(primary_input_size, auxiliary_input_size, num_gates, num_outputs); +#ifdef DEBUG + example.circuit.print(); +#endif + const bool bit = run_bacs_ppzksnark(example, test_serialization); + assert(bit); + + print_header("(leave) Test BACS ppzkSNARK"); +} + +int main() +{ + default_bacs_ppzksnark_pp::init_public_params(); + start_profiling(); + + test_bacs_ppzksnark(10, 10, 20, 5); +} diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/examples/run_r1cs_gg_ppzksnark.hpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/examples/run_r1cs_gg_ppzksnark.hpp new file mode 100644 index 0000000..1eef742 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/examples/run_r1cs_gg_ppzksnark.hpp @@ -0,0 +1,35 @@ +/** @file + ***************************************************************************** + + Declaration of functionality that runs the R1CS GG-ppzkSNARK for + a given R1CS example. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_R1CS_GG_PPZKSNARK_HPP_ +#define RUN_R1CS_GG_PPZKSNARK_HPP_ + +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" + +namespace libsnark { + +/** + * Runs the ppzkSNARK (generator, prover, and verifier) for a given + * R1CS example (specified by a constraint system, input, and witness). + * + * Optionally, also test the serialization routines for keys and proofs. + * (This takes additional time.) + */ +template +bool run_r1cs_gg_ppzksnark(const r1cs_example > &example, + const bool test_serialization); + +} // libsnark + +#include "zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/examples/run_r1cs_gg_ppzksnark.tcc" + +#endif // RUN_R1CS_GG_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/examples/run_r1cs_gg_ppzksnark.tcc b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/examples/run_r1cs_gg_ppzksnark.tcc new file mode 100644 index 0000000..032617e --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/examples/run_r1cs_gg_ppzksnark.tcc @@ -0,0 +1,114 @@ +/** @file + ***************************************************************************** + + Implementation of functionality that runs the R1CS GG-ppzkSNARK for + a given R1CS example. + + See run_r1cs_gg_ppzksnark.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_R1CS_GG_PPZKSNARK_TCC_ +#define RUN_R1CS_GG_PPZKSNARK_TCC_ + +#include "zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark.hpp" + +#include +#include + +#include "common/profiling.hpp" + +namespace libsnark { + +template +typename std::enable_if::type +test_affine_verifier(const r1cs_gg_ppzksnark_verification_key &vk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_proof &proof, + const bool expected_answer) +{ + print_header("R1CS GG-ppzkSNARK Affine Verifier"); + const bool answer = r1cs_gg_ppzksnark_affine_verifier_weak_IC(vk, primary_input, proof); + assert(answer == expected_answer); +} + +template +typename std::enable_if::type +test_affine_verifier(const r1cs_gg_ppzksnark_verification_key &vk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_proof &proof, + const bool expected_answer) +{ + print_header("R1CS GG-ppzkSNARK Affine Verifier"); + UNUSED(vk, primary_input, proof, expected_answer); + printf("Affine verifier is not supported; not testing anything.\n"); +} + +/** + * The code below provides an example of all stages of running a R1CS GG-ppzkSNARK. + * + * Of course, in a real-life scenario, we would have three distinct entities, + * mangled into one in the demonstration below. The three entities are as follows. + * (1) The "generator", which runs the ppzkSNARK generator on input a given + * constraint system CS to create a proving and a verification key for CS. + * (2) The "prover", which runs the ppzkSNARK prover on input the proving key, + * a primary input for CS, and an auxiliary input for CS. + * (3) The "verifier", which runs the ppzkSNARK verifier on input the verification key, + * a primary input for CS, and a proof. + */ +template +bool run_r1cs_gg_ppzksnark(const r1cs_example > &example, + const bool test_serialization) +{ + enter_block("Call to run_r1cs_gg_ppzksnark"); + + print_header("R1CS GG-ppzkSNARK Generator"); + r1cs_gg_ppzksnark_keypair keypair = r1cs_gg_ppzksnark_generator(example.constraint_system); + printf("\n"); print_indent(); print_mem("after generator"); + + print_header("Preprocess verification key"); + r1cs_gg_ppzksnark_processed_verification_key pvk = r1cs_gg_ppzksnark_verifier_process_vk(keypair.vk); + + if (test_serialization) + { + enter_block("Test serialization of keys"); + keypair.pk = reserialize >(keypair.pk); + keypair.vk = reserialize >(keypair.vk); + pvk = reserialize >(pvk); + leave_block("Test serialization of keys"); + } + + print_header("R1CS GG-ppzkSNARK Prover"); + r1cs_gg_ppzksnark_proof proof = r1cs_gg_ppzksnark_prover(keypair.pk, example.primary_input, example.auxiliary_input); + printf("\n"); print_indent(); print_mem("after prover"); + + if (test_serialization) + { + enter_block("Test serialization of proof"); + proof = reserialize >(proof); + leave_block("Test serialization of proof"); + } + + print_header("R1CS GG-ppzkSNARK Verifier"); + const bool ans = r1cs_gg_ppzksnark_verifier_strong_IC(keypair.vk, example.primary_input, proof); + printf("\n"); print_indent(); print_mem("after verifier"); + printf("* The verification result is: %s\n", (ans ? "PASS" : "FAIL")); + + print_header("R1CS GG-ppzkSNARK Online Verifier"); + const bool ans2 = r1cs_gg_ppzksnark_online_verifier_strong_IC(pvk, example.primary_input, proof); + assert(ans == ans2); + + test_affine_verifier(keypair.vk, example.primary_input, proof, ans); + + leave_block("Call to run_r1cs_gg_ppzksnark"); + + return ans; +} + +} // libsnark + +#endif // RUN_R1CS_GG_PPZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark.cpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark.cpp new file mode 100644 index 0000000..4d1dc6c --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark.cpp @@ -0,0 +1,71 @@ +/** @file + ***************************************************************************** + Profiling program that exercises the ppzkSNARK (first generator, then prover, + then verifier) on a synthetic R1CS instance. + + The command + + $ src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark 1000 10 Fr + + exercises the ppzkSNARK (first generator, then prover, then verifier) on an R1CS instance with 1000 equations and an input consisting of 10 field elements. + + (If you get the error `zmInit ERR:can't protect`, see the discussion [above](#elliptic-curve-choices).) + + The command + + $ src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark 1000 10 bytes + + does the same but now the input consists of 10 bytes. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include + +#include "common/default_types/r1cs_gg_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/examples/run_r1cs_gg_ppzksnark.hpp" + +using namespace libsnark; + +int main(int argc, const char * argv[]) +{ + default_r1cs_gg_ppzksnark_pp::init_public_params(); + start_profiling(); + + if (argc == 2 && strcmp(argv[1], "-v") == 0) + { + print_compilation_info(); + return 0; + } + + if (argc != 3 && argc != 4) + { + printf("usage: %s num_constraints input_size [Fr|bytes]\n", argv[0]); + return 1; + } + const int num_constraints = atoi(argv[1]); + int input_size = atoi(argv[2]); + if (argc == 4) + { + assert(strcmp(argv[3], "Fr") == 0 || strcmp(argv[3], "bytes") == 0); + if (strcmp(argv[3], "bytes") == 0) + { + input_size = div_ceil(8 * input_size, Fr::capacity()); + } + } + + enter_block("Generate R1CS example"); + r1cs_example > example = generate_r1cs_example_with_field_input >(num_constraints, input_size); + leave_block("Generate R1CS example"); + + print_header("(enter) Profile R1CS GG-ppzkSNARK"); + const bool test_serialization = true; + run_r1cs_gg_ppzksnark(example, test_serialization); + print_header("(leave) Profile R1CS GG-ppzkSNARK"); +} diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark.hpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark.hpp new file mode 100644 index 0000000..3e997f6 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark.hpp @@ -0,0 +1,448 @@ +/** @file +***************************************************************************** + +Declaration of interfaces for a ppzkSNARK for R1CS with a security proof +in the generic group (GG) model. + +This includes: +- class for proving key +- class for verification key +- class for processed verification key +- class for key pair (proving key & verification key) +- class for proof +- generator algorithm +- prover algorithm +- verifier algorithm (with strong or weak input consistency) +- online verifier algorithm (with strong or weak input consistency) + +The implementation instantiates the protocol of \[Gro16]. + + +Acronyms: + +- R1CS = "Rank-1 Constraint Systems" +- ppzkSNARK = "PreProcessing Zero-Knowledge Succinct Non-interactive ARgument of Knowledge" + +References: + +\[Gro16]: + "On the Size of Pairing-based Non-interactive Arguments", + Jens Groth, + EUROCRYPT 2016, + + + +***************************************************************************** +* @author This file is part of libsnark, developed by SCIPR Lab +* and contributors (see AUTHORS). +* @copyright MIT license (see LICENSE file) +*****************************************************************************/ + +#ifndef R1CS_GG_PPZKSNARK_HPP_ +#define R1CS_GG_PPZKSNARK_HPP_ + +#include + +#include "algebra/curves/public_params.hpp" +#include "common/data_structures/accumulation_vector.hpp" +#include "algebra/knowledge_commitment/knowledge_commitment.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark_params.hpp" + +namespace libsnark { + +/******************************** Proving key ********************************/ + +template +class r1cs_gg_ppzksnark_proving_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_gg_ppzksnark_proving_key &pk); + +template +std::istream& operator>>(std::istream &in, r1cs_gg_ppzksnark_proving_key &pk); + +/** + * A proving key for the R1CS GG-ppzkSNARK. + */ +template +class r1cs_gg_ppzksnark_proving_key { +public: + G1 delta_g1; + G2 delta_g2; + + G1_vector A_query; // this could be a sparse vector if we had multiexp for those + knowledge_commitment_vector, G1 > B_query; + G1_vector H_query; + G1_vector L_query; + + r1cs_gg_ppzksnark_constraint_system constraint_system; + + r1cs_gg_ppzksnark_proving_key() {}; + r1cs_gg_ppzksnark_proving_key& operator=(const r1cs_gg_ppzksnark_proving_key &other) = default; + r1cs_gg_ppzksnark_proving_key(const r1cs_gg_ppzksnark_proving_key &other) = default; + r1cs_gg_ppzksnark_proving_key(r1cs_gg_ppzksnark_proving_key &&other) = default; + r1cs_gg_ppzksnark_proving_key(G1 &&delta_g1, + G2 &&delta_g2, + G1_vector &&A_query, + knowledge_commitment_vector, G1 > &&B_query, + G1_vector &&H_query, + G1_vector &&L_query, + r1cs_gg_ppzksnark_constraint_system &&constraint_system) : + delta_g1(std::move(delta_g1)), + delta_g2(std::move(delta_g2)), + A_query(std::move(A_query)), + B_query(std::move(B_query)), + H_query(std::move(H_query)), + L_query(std::move(L_query)), + constraint_system(std::move(constraint_system)) + {}; + + size_t G1_size() const + { + return 1 + A_query.size() + B_query.domain_size() + H_query.size() + L_query.size(); + } + + size_t G2_size() const + { + return 1 + B_query.domain_size(); + } + + size_t G1_sparse_size() const + { + return 1 + A_query.size() + B_query.size() + H_query.size() + L_query.size(); + } + + size_t G2_sparse_size() const + { + return 1 + B_query.size(); + } + + size_t size_in_bits() const + { + return (libsnark::size_in_bits(A_query) + B_query.size_in_bits() + + libsnark::size_in_bits(H_query) + libsnark::size_in_bits(L_query) + + 1 * G1::size_in_bits() + 1 * G2::size_in_bits()); + } + + void print_size() const + { + print_indent(); printf("* G1 elements in PK: %zu\n", this->G1_size()); + print_indent(); printf("* Non-zero G1 elements in PK: %zu\n", this->G1_sparse_size()); + print_indent(); printf("* G2 elements in PK: %zu\n", this->G2_size()); + print_indent(); printf("* Non-zero G2 elements in PK: %zu\n", this->G2_sparse_size()); + print_indent(); printf("* PK size in bits: %zu\n", this->size_in_bits()); + } + + bool operator==(const r1cs_gg_ppzksnark_proving_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_gg_ppzksnark_proving_key &pk); + friend std::istream& operator>> (std::istream &in, r1cs_gg_ppzksnark_proving_key &pk); +}; + + +/******************************* Verification key ****************************/ + +template +class r1cs_gg_ppzksnark_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_gg_ppzksnark_verification_key &vk); + +template +std::istream& operator>>(std::istream &in, r1cs_gg_ppzksnark_verification_key &vk); + +/** + * A verification key for the R1CS GG-ppzkSNARK. + */ +template +class r1cs_gg_ppzksnark_verification_key { +public: + GT alpha_g1_beta_g2; + G2 gamma_g2; + G2 delta_g2; + + accumulation_vector > encoded_IC_query; + + r1cs_gg_ppzksnark_verification_key() = default; + r1cs_gg_ppzksnark_verification_key(const GT &alpha_g1_beta_g2, + const G2 &gamma_g2, + const G2 &delta_g2, + const accumulation_vector > &eIC) : + alpha_g1_beta_g2(alpha_g1_beta_g2), + gamma_g2(gamma_g2), + delta_g2(delta_g2), + encoded_IC_query(eIC) + {}; + + size_t G1_size() const + { + return encoded_IC_query.size(); + } + + size_t G2_size() const + { + return 2; + } + + size_t GT_size() const + { + return 1; + } + + size_t size_in_bits() const + { + // TODO: include GT size + return (encoded_IC_query.size_in_bits() + 2 * G2::size_in_bits()); + } + + void print_size() const + { + print_indent(); printf("* G1 elements in VK: %zu\n", this->G1_size()); + print_indent(); printf("* G2 elements in VK: %zu\n", this->G2_size()); + print_indent(); printf("* GT elements in VK: %zu\n", this->GT_size()); + print_indent(); printf("* VK size in bits: %zu\n", this->size_in_bits()); + } + + bool operator==(const r1cs_gg_ppzksnark_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_gg_ppzksnark_verification_key &vk); + friend std::istream& operator>> (std::istream &in, r1cs_gg_ppzksnark_verification_key &vk); + + static r1cs_gg_ppzksnark_verification_key dummy_verification_key(const size_t input_size); +}; + + +/************************ Processed verification key *************************/ + +template +class r1cs_gg_ppzksnark_processed_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_gg_ppzksnark_processed_verification_key &pvk); + +template +std::istream& operator>>(std::istream &in, r1cs_gg_ppzksnark_processed_verification_key &pvk); + +/** + * A processed verification key for the R1CS GG-ppzkSNARK. + * + * Compared to a (non-processed) verification key, a processed verification key + * contains a small constant amount of additional pre-computed information that + * enables a faster verification time. + */ +template +class r1cs_gg_ppzksnark_processed_verification_key { +public: + GT vk_alpha_g1_beta_g2; + G2_precomp vk_gamma_g2_precomp; + G2_precomp vk_delta_g2_precomp; + + accumulation_vector > encoded_IC_query; + + bool operator==(const r1cs_gg_ppzksnark_processed_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_gg_ppzksnark_processed_verification_key &pvk); + friend std::istream& operator>> (std::istream &in, r1cs_gg_ppzksnark_processed_verification_key &pvk); +}; + + +/********************************** Key pair *********************************/ + +/** + * A key pair for the R1CS GG-ppzkSNARK, which consists of a proving key and a verification key. + */ +template +class r1cs_gg_ppzksnark_keypair { +public: + r1cs_gg_ppzksnark_proving_key pk; + r1cs_gg_ppzksnark_verification_key vk; + + r1cs_gg_ppzksnark_keypair() = default; + r1cs_gg_ppzksnark_keypair(const r1cs_gg_ppzksnark_keypair &other) = default; + r1cs_gg_ppzksnark_keypair(r1cs_gg_ppzksnark_proving_key &&pk, + r1cs_gg_ppzksnark_verification_key &&vk) : + pk(std::move(pk)), + vk(std::move(vk)) + {} + + r1cs_gg_ppzksnark_keypair(r1cs_gg_ppzksnark_keypair &&other) = default; +}; + + +/*********************************** Proof ***********************************/ + +template +class r1cs_gg_ppzksnark_proof; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_gg_ppzksnark_proof &proof); + +template +std::istream& operator>>(std::istream &in, r1cs_gg_ppzksnark_proof &proof); + +/** + * A proof for the R1CS GG-ppzkSNARK. + * + * While the proof has a structure, externally one merely opaquely produces, + * seralizes/deserializes, and verifies proofs. We only expose some information + * about the structure for statistics purposes. + */ +template +class r1cs_gg_ppzksnark_proof { +public: + G1 g_A; + G2 g_B; + G1 g_C; + + r1cs_gg_ppzksnark_proof() + { + // invalid proof with valid curve points + this->g_A = G1::one(); + this->g_B = G2::one(); + this->g_C = G1::one(); + } + r1cs_gg_ppzksnark_proof(G1 &&g_A, + G2 &&g_B, + G1 &&g_C) : + g_A(std::move(g_A)), + g_B(std::move(g_B)), + g_C(std::move(g_C)) + {}; + + size_t G1_size() const + { + return 2; + } + + size_t G2_size() const + { + return 1; + } + + size_t size_in_bits() const + { + return G1_size() * G1::size_in_bits() + G2_size() * G2::size_in_bits(); + } + + void print_size() const + { + print_indent(); printf("* G1 elements in proof: %zu\n", this->G1_size()); + print_indent(); printf("* G2 elements in proof: %zu\n", this->G2_size()); + print_indent(); printf("* Proof size in bits: %zu\n", this->size_in_bits()); + } + + bool is_well_formed() const + { + return (g_A.is_well_formed() && + g_B.is_well_formed() && + g_C.is_well_formed()); + } + + bool operator==(const r1cs_gg_ppzksnark_proof &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_gg_ppzksnark_proof &proof); + friend std::istream& operator>> (std::istream &in, r1cs_gg_ppzksnark_proof &proof); +}; + + +/***************************** Main algorithms *******************************/ + +/** + * A generator algorithm for the R1CS GG-ppzkSNARK. + * + * Given a R1CS constraint system CS, this algorithm produces proving and verification keys for CS. + */ +template +r1cs_gg_ppzksnark_keypair r1cs_gg_ppzksnark_generator(const r1cs_gg_ppzksnark_constraint_system &cs); + +/** + * A prover algorithm for the R1CS GG-ppzkSNARK. + * + * Given a R1CS primary input X and a R1CS auxiliary input Y, this algorithm + * produces a proof (of knowledge) that attests to the following statement: + * ``there exists Y such that CS(X,Y)=0''. + * Above, CS is the R1CS constraint system that was given as input to the generator algorithm. + */ +template +r1cs_gg_ppzksnark_proof r1cs_gg_ppzksnark_prover(const r1cs_gg_ppzksnark_proving_key &pk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_auxiliary_input &auxiliary_input); + +/* + Below are four variants of verifier algorithm for the R1CS GG-ppzkSNARK. + + These are the four cases that arise from the following two choices: + + (1) The verifier accepts a (non-processed) verification key or, instead, a processed verification key. + In the latter case, we call the algorithm an "online verifier". + + (2) The verifier checks for "weak" input consistency or, instead, "strong" input consistency. + Strong input consistency requires that |primary_input| = CS.num_inputs, whereas + weak input consistency requires that |primary_input| <= CS.num_inputs (and + the primary input is implicitly padded with zeros up to length CS.num_inputs). +*/ + +/** + * A verifier algorithm for the R1CS GG-ppzkSNARK that: + * (1) accepts a non-processed verification key, and + * (2) has weak input consistency. + */ +template +bool r1cs_gg_ppzksnark_verifier_weak_IC(const r1cs_gg_ppzksnark_verification_key &vk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_proof &proof); + +/** + * A verifier algorithm for the R1CS GG-ppzkSNARK that: + * (1) accepts a non-processed verification key, and + * (2) has strong input consistency. + */ +template +bool r1cs_gg_ppzksnark_verifier_strong_IC(const r1cs_gg_ppzksnark_verification_key &vk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_proof &proof); + +/** + * Convert a (non-processed) verification key into a processed verification key. + */ +template +r1cs_gg_ppzksnark_processed_verification_key r1cs_gg_ppzksnark_verifier_process_vk(const r1cs_gg_ppzksnark_verification_key &vk); + +/** + * A verifier algorithm for the R1CS GG-ppzkSNARK that: + * (1) accepts a processed verification key, and + * (2) has weak input consistency. + */ +template +bool r1cs_gg_ppzksnark_online_verifier_weak_IC(const r1cs_gg_ppzksnark_processed_verification_key &pvk, + const r1cs_gg_ppzksnark_primary_input &input, + const r1cs_gg_ppzksnark_proof &proof); + +/** + * A verifier algorithm for the R1CS GG-ppzkSNARK that: + * (1) accepts a processed verification key, and + * (2) has strong input consistency. + */ +template +bool r1cs_gg_ppzksnark_online_verifier_strong_IC(const r1cs_gg_ppzksnark_processed_verification_key &pvk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_proof &proof); + +/****************************** Miscellaneous ********************************/ + +/** + * For debugging purposes (of r1cs_gg_ppzksnark_r1cs_gg_ppzksnark_verifier_gadget): + * + * A verifier algorithm for the R1CS GG-ppzkSNARK that: + * (1) accepts a non-processed verification key, + * (2) has weak input consistency, and + * (3) uses affine coordinates for elliptic-curve computations. + */ +template +bool r1cs_gg_ppzksnark_affine_verifier_weak_IC(const r1cs_gg_ppzksnark_verification_key &vk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_proof &proof); + + +} // libsnark + +#include "zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark.tcc" + +#endif // R1CS_GG_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark.tcc b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark.tcc new file mode 100644 index 0000000..48ad1fb --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark.tcc @@ -0,0 +1,626 @@ +/** @file +***************************************************************************** + +Implementation of interfaces for a ppzkSNARK for R1CS. + +See r1cs_gg_ppzksnark.hpp . + +***************************************************************************** +* @author This file is part of libsnark, developed by SCIPR Lab +* and contributors (see AUTHORS). +* @copyright MIT license (see LICENSE file) +*****************************************************************************/ + +#ifndef R1CS_GG_PPZKSNARK_TCC_ +#define R1CS_GG_PPZKSNARK_TCC_ + +#include +#include +#include +#include +#include + +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "algebra/scalar_multiplication/multiexp.hpp" +#include "algebra/scalar_multiplication/kc_multiexp.hpp" +#include "reductions/r1cs_to_qap/r1cs_to_qap.hpp" + +namespace libsnark { + +template +bool r1cs_gg_ppzksnark_proving_key::operator==(const r1cs_gg_ppzksnark_proving_key &other) const +{ + return (this->delta_g1 == other.delta_g1 && + this->delta_g2 == other.delta_g2 && + this->A_query == other.A_query && + this->B_query == other.B_query && + this->H_query == other.H_query && + this->L_query == other.L_query && + this->constraint_system == other.constraint_system); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_gg_ppzksnark_proving_key &pk) +{ + out << pk.delta_g1 << OUTPUT_NEWLINE; + out << pk.delta_g2 << OUTPUT_NEWLINE; + out << pk.A_query; + out << pk.B_query; + out << pk.H_query; + out << pk.L_query; + out << pk.constraint_system; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_gg_ppzksnark_proving_key &pk) +{ + in >> pk.delta_g1; + consume_OUTPUT_NEWLINE(in); + in >> pk.delta_g2; + consume_OUTPUT_NEWLINE(in); + in >> pk.A_query; + in >> pk.B_query; + in >> pk.H_query; + in >> pk.L_query; + in >> pk.constraint_system; + + return in; +} + +template +bool r1cs_gg_ppzksnark_verification_key::operator==(const r1cs_gg_ppzksnark_verification_key &other) const +{ + return (this->alpha_g1_beta_g2 == other.alpha_g1_beta_g2 && + this->gamma_g2 == other.gamma_g2 && + this->delta_g2 == other.delta_g2 && + this->encoded_IC_query == other.encoded_IC_query); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_gg_ppzksnark_verification_key &vk) +{ + out << vk.alpha_g1_beta_g2 << OUTPUT_NEWLINE; + out << vk.gamma_g2 << OUTPUT_NEWLINE; + out << vk.delta_g2 << OUTPUT_NEWLINE; + out << vk.encoded_IC_query << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_gg_ppzksnark_verification_key &vk) +{ + in >> vk.alpha_g1_beta_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.gamma_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.delta_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.encoded_IC_query; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +bool r1cs_gg_ppzksnark_processed_verification_key::operator==(const r1cs_gg_ppzksnark_processed_verification_key &other) const +{ + return (this->vk_alpha_g1_beta_g2 == other.vk_alpha_g1_beta_g2 && + this->vk_gamma_g2_precomp == other.vk_gamma_g2_precomp && + this->vk_delta_g2_precomp == other.vk_delta_g2_precomp && + this->encoded_IC_query == other.encoded_IC_query); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_gg_ppzksnark_processed_verification_key &pvk) +{ + out << pvk.vk_alpha_g1_beta_g2 << OUTPUT_NEWLINE; + out << pvk.vk_gamma_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_delta_g2_precomp << OUTPUT_NEWLINE; + out << pvk.encoded_IC_query << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_gg_ppzksnark_processed_verification_key &pvk) +{ + in >> pvk.vk_alpha_g1_beta_g2; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_gamma_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_delta_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.encoded_IC_query; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +bool r1cs_gg_ppzksnark_proof::operator==(const r1cs_gg_ppzksnark_proof &other) const +{ + return (this->g_A == other.g_A && + this->g_B == other.g_B && + this->g_C == other.g_C); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_gg_ppzksnark_proof &proof) +{ + out << proof.g_A << OUTPUT_NEWLINE; + out << proof.g_B << OUTPUT_NEWLINE; + out << proof.g_C << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_gg_ppzksnark_proof &proof) +{ + in >> proof.g_A; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_B; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_C; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +r1cs_gg_ppzksnark_verification_key r1cs_gg_ppzksnark_verification_key::dummy_verification_key(const size_t input_size) +{ + r1cs_gg_ppzksnark_verification_key result; + result.alpha_g1_beta_g2 = Fr::random_element() * GT::random_element(); + result.gamma_g2 = G2::random_element(); + result.delta_g2 = G2::random_element(); + + G1 base = G1::random_element(); + G1_vector v; + for (size_t i = 0; i < input_size; ++i) + { + v.emplace_back(G1::random_element()); + } + + result.encoded_IC_query = accumulation_vector >(std::move(base), std::move(v)); + + return result; +} + +template +r1cs_gg_ppzksnark_keypair r1cs_gg_ppzksnark_generator(const r1cs_gg_ppzksnark_constraint_system &cs) +{ + enter_block("Call to r1cs_gg_ppzksnark_generator"); + + /* make the B_query "lighter" if possible */ + r1cs_gg_ppzksnark_constraint_system cs_copy(cs); + cs_copy.swap_AB_if_beneficial(); + + /* draw random element at which the QAP is evaluated */ + const Fr t = Fr::random_element(); + + qap_instance_evaluation > qap_inst = r1cs_to_qap_instance_map_with_evaluation(cs_copy, t); + + print_indent(); printf("* QAP number of variables: %zu\n", qap_inst.num_variables()); + print_indent(); printf("* QAP pre degree: %zu\n", cs_copy.constraints.size()); + print_indent(); printf("* QAP degree: %zu\n", qap_inst.degree()); + print_indent(); printf("* QAP number of input variables: %zu\n", qap_inst.num_inputs()); + + enter_block("Compute query densities"); + size_t non_zero_At = 0, non_zero_Bt = 0; + for (size_t i = 0; i < qap_inst.num_variables()+1; ++i) + { + if (!qap_inst.At[i].is_zero()) + { + ++non_zero_At; + } + if (!qap_inst.Bt[i].is_zero()) + { + ++non_zero_Bt; + } + } + leave_block("Compute query densities"); + + /* qap_inst.{At,Bt,Ct,Ht} are now in unspecified state, but we do not use them later */ + Fr_vector At = std::move(qap_inst.At); + Fr_vector Bt = std::move(qap_inst.Bt); + Fr_vector Ct = std::move(qap_inst.Ct); + Fr_vector Ht = std::move(qap_inst.Ht); + + const Fr alpha = Fr::random_element(), + beta = Fr::random_element(), + gamma = Fr::random_element(), + delta = Fr::random_element(); + + /* append \alpha and \beta to At and Bt */ + At.emplace_back(alpha); ++non_zero_At; + Bt.emplace_back(beta); ++non_zero_Bt; + + /* construct IC coefficients */ + Fr_vector IC_input_coefficients; + IC_input_coefficients.reserve(qap_inst.num_inputs()); + const Fr gamma_inverse = gamma.inverse(); + + const Fr IC_constant_coefficient = (beta * At[0] + alpha * Bt[0] + Ct[0]) * gamma_inverse; + for (size_t i = 1; i < qap_inst.num_inputs() + 1; ++i) + { + IC_input_coefficients.emplace_back((beta * At[i] + alpha * Bt[i] + Ct[i]) * gamma_inverse); + } + + /* construct L query */ + Fr_vector Lt; + Lt.reserve(qap_inst.num_variables() - qap_inst.num_inputs()); + + const Fr delta_inverse = delta.inverse(); + const size_t Lt_offset = qap_inst.num_inputs() + 1; + for (size_t i = 0; i < qap_inst.num_variables() - qap_inst.num_inputs(); ++i) + { + Lt.emplace_back((beta * At[Lt_offset + i] + alpha * Bt[Lt_offset + i] + Ct[Lt_offset + i]) * delta_inverse); + } + + /* Note that H for Groth's proof system is degree d-2, but the QAP + reduction returns coefficients for degree d polynomial H (in + style of PGHR-type proof systems) */ + Ht.resize(Ht.size() - 2); + + const size_t g1_exp_count = non_zero_At + non_zero_Bt + qap_inst.num_variables(); + const size_t g2_exp_count = non_zero_Bt; + + size_t g1_window = get_exp_window_size >(g1_exp_count); + size_t g2_window = get_exp_window_size >(g2_exp_count); + print_indent(); printf("* G1 window: %zu\n", g1_window); + print_indent(); printf("* G2 window: %zu\n", g2_window); + +#ifdef MULTICORE + const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads() +#else + const size_t chunks = 1; +#endif + + const G1 G1_gen = G1::random_element(); + const G2 G2_gen = G2::random_element(); + + enter_block("Generating G1 multiexp table"); + window_table > g1_table = get_window_table(Fr::size_in_bits(), g1_window, G1_gen); + leave_block("Generating G1 multiexp table"); + + enter_block("Generating G2 multiexp table"); + window_table > g2_table = get_window_table(Fr::size_in_bits(), g2_window, G2_gen); + leave_block("Generating G2 multiexp table"); + + enter_block("Generate R1CS proving key"); + G1 delta_g1 = delta * G1_gen; + G2 delta_g2 = delta * G2_gen; + + enter_block("Generate queries"); + enter_block("Compute the A-query", false); + G1_vector A_query = batch_exp(Fr::size_in_bits(), g1_window, g1_table, At); +#ifdef USE_MIXED_ADDITION + batch_to_special >(A_query); +#endif + leave_block("Compute the A-query", false); + + enter_block("Compute the B-query", false); + knowledge_commitment_vector, G1 > B_query = kc_batch_exp(Fr::size_in_bits(), g2_window, g1_window, g2_table, g1_table, Fr::one(), Fr::one(), Bt, chunks); + leave_block("Compute the B-query", false); + + enter_block("Compute the H-query", false); + G1_vector H_query = batch_exp_with_coeff(Fr::size_in_bits(), g1_window, g1_table, qap_inst.Zt * delta_inverse, Ht); + leave_block("Compute the H-query", false); + + enter_block("Compute the L-query", false); + G1_vector L_query = batch_exp(Fr::size_in_bits(), g1_window, g1_table, Lt); +#ifdef USE_MIXED_ADDITION + batch_to_special >(L_query); +#endif + leave_block("Compute the L-query", false); + leave_block("Generate queries"); + + leave_block("Generate R1CS proving key"); + + enter_block("Generate R1CS verification key"); + GT alpha_g1_beta_g2 = ppT::reduced_pairing(alpha * G1_gen, beta * G2_gen); + G2 gamma_g2 = gamma * G2_gen; + + enter_block("Encode IC query for R1CS verification key"); + G1 encoded_IC_base = IC_constant_coefficient * G1_gen; + G1_vector encoded_IC_values = batch_exp(Fr::size_in_bits(), g1_window, g1_table, + IC_input_coefficients); + leave_block("Encode IC query for R1CS verification key"); + leave_block("Generate R1CS verification key"); + + leave_block("Call to r1cs_gg_ppzksnark_generator"); + + accumulation_vector > encoded_IC_query(std::move(encoded_IC_base), std::move(encoded_IC_values)); + + r1cs_gg_ppzksnark_verification_key vk = r1cs_gg_ppzksnark_verification_key(alpha_g1_beta_g2, + gamma_g2, + delta_g2, + encoded_IC_query); + + r1cs_gg_ppzksnark_proving_key pk = r1cs_gg_ppzksnark_proving_key(std::move(delta_g1), + std::move(delta_g2), + std::move(A_query), + std::move(B_query), + std::move(H_query), + std::move(L_query), + std::move(cs_copy)); + + pk.print_size(); + vk.print_size(); + + return r1cs_gg_ppzksnark_keypair(std::move(pk), std::move(vk)); +} + +template +r1cs_gg_ppzksnark_proof r1cs_gg_ppzksnark_prover(const r1cs_gg_ppzksnark_proving_key &pk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_auxiliary_input &auxiliary_input) +{ + enter_block("Call to r1cs_gg_ppzksnark_prover"); + +#ifdef DEBUG + assert(pk.constraint_system.is_satisfied(primary_input, auxiliary_input)); +#endif + + enter_block("Compute the polynomial H"); + const qap_witness > qap_wit = r1cs_to_qap_witness_map(pk.constraint_system, primary_input, auxiliary_input, Fr::zero(), Fr::zero(), Fr::zero()); + + /* We are dividing degree 2(d-1) polynomial by degree d polynomial + and not adding a PGHR-style ZK-patch, so our H is degree d-2 */ + assert(!qap_wit.coefficients_for_H[qap_wit.degree()-2].is_zero()); + assert(qap_wit.coefficients_for_H[qap_wit.degree()-1].is_zero()); + assert(qap_wit.coefficients_for_H[qap_wit.degree()].is_zero()); + leave_block("Compute the polynomial H"); + +#ifdef DEBUG + const Fr t = Fr::random_element(); + qap_instance_evaluation > qap_inst = r1cs_to_qap_instance_map_with_evaluation(pk.constraint_system, t); + assert(qap_inst.is_satisfied(qap_wit)); +#endif + + const Fr r = Fr::random_element(); + const Fr s = Fr::random_element(); + G1 g_A = r * pk.delta_g1 + pk.A_query[qap_wit.num_variables()+1]; + G2 g_B = s * pk.delta_g2 + pk.B_query[qap_wit.num_variables()+1].g; // TODO: swap g and h in knowledge commitment + G1 g_C = (r * s) * pk.delta_g1 + s * pk.A_query[qap_wit.num_variables()+1] + r * pk.B_query[qap_wit.num_variables()+1].h; + +#ifdef DEBUG + assert(qap_wit.coefficients_for_ABCs.size() == qap_wit.num_variables()); + assert(pk.A_query.size() == qap_wit.num_variables()+2); + assert(pk.B_query.domain_size() == qap_wit.num_variables()+2); + assert(pk.H_query.size() == qap_wit.degree() - 1); + assert(pk.L_query.size() == qap_wit.num_variables() - qap_wit.num_inputs()); +#endif + +#ifdef MULTICORE + const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads() +#else + const size_t chunks = 1; +#endif + + enter_block("Compute the proof"); + + enter_block("Compute answer to A-query", false); + // TODO: sort out indexing + Fr_vector const_padded_assignment(1, Fr::one()); + const_padded_assignment.insert(const_padded_assignment.end(), qap_wit.coefficients_for_ABCs.begin(), qap_wit.coefficients_for_ABCs.end()); + + G1 A_answer = multi_exp_with_mixed_addition, Fr >(pk.A_query.begin(), pk.A_query.begin() + qap_wit.num_variables() + 1, + const_padded_assignment.begin(), const_padded_assignment.begin() + qap_wit.num_variables() + 1, + chunks, true); + g_A = g_A + A_answer; + g_C = g_C + s * A_answer; + leave_block("Compute answer to A-query", false); + + enter_block("Compute answer to B-query", false); + knowledge_commitment, G1 > B_answer; + B_answer = kc_multi_exp_with_mixed_addition, G1, Fr >(pk.B_query, + 0, qap_wit.num_variables() + 1, + const_padded_assignment.begin(), const_padded_assignment.begin() + qap_wit.num_variables() + 1, + chunks, true); + g_B = g_B + B_answer.g; + g_C = g_C + r * B_answer.h; + leave_block("Compute answer to B-query", false); + + enter_block("Compute answer to H-query", false); + g_C = g_C + multi_exp, Fr >(pk.H_query.begin(), pk.H_query.begin() + (qap_wit.degree() - 1), + qap_wit.coefficients_for_H.begin(), qap_wit.coefficients_for_H.begin() + (qap_wit.degree() - 1), + chunks, true); + leave_block("Compute answer to H-query", false); + + enter_block("Compute answer to L-query", false); + g_C = g_C + multi_exp_with_mixed_addition, Fr >(pk.L_query.begin(), pk.L_query.end(), + const_padded_assignment.begin()+qap_wit.num_inputs()+1, const_padded_assignment.begin()+qap_wit.num_variables()+1, + chunks, true); + leave_block("Compute answer to L-query", false); + + leave_block("Compute the proof"); + + leave_block("Call to r1cs_gg_ppzksnark_prover"); + + r1cs_gg_ppzksnark_proof proof = r1cs_gg_ppzksnark_proof(std::move(g_A), std::move(g_B), std::move(g_C)); + proof.print_size(); + + return proof; +} + +template +r1cs_gg_ppzksnark_processed_verification_key r1cs_gg_ppzksnark_verifier_process_vk(const r1cs_gg_ppzksnark_verification_key &vk) +{ + enter_block("Call to r1cs_gg_ppzksnark_verifier_process_vk"); + + r1cs_gg_ppzksnark_processed_verification_key pvk; + pvk.vk_alpha_g1_beta_g2 = vk.alpha_g1_beta_g2; + pvk.vk_gamma_g2_precomp = ppT::precompute_G2(vk.gamma_g2); + pvk.vk_delta_g2_precomp = ppT::precompute_G2(vk.delta_g2); + pvk.encoded_IC_query = vk.encoded_IC_query; + + leave_block("Call to r1cs_gg_ppzksnark_verifier_process_vk"); + + return pvk; +} + +template +bool r1cs_gg_ppzksnark_online_verifier_weak_IC(const r1cs_gg_ppzksnark_processed_verification_key &pvk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_proof &proof) +{ + enter_block("Call to r1cs_gg_ppzksnark_online_verifier_weak_IC"); + assert(pvk.encoded_IC_query.domain_size() >= primary_input.size()); + + enter_block("Accumulate input"); + const accumulation_vector > accumulated_IC = pvk.encoded_IC_query.template accumulate_chunk >(primary_input.begin(), primary_input.end(), 0); + const G1 &acc = accumulated_IC.first; + leave_block("Accumulate input"); + + bool result = true; + + enter_block("Check if the proof is well-formed"); + if (!proof.is_well_formed()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("At least one of the proof elements does not lie on the curve.\n"); + } + result = false; + } + leave_block("Check if the proof is well-formed"); + + enter_block("Online pairing computations"); + enter_block("Check QAP divisibility"); + const G1_precomp proof_g_A_precomp = ppT::precompute_G1(proof.g_A); + const G2_precomp proof_g_B_precomp = ppT::precompute_G2(proof.g_B); + const G1_precomp proof_g_C_precomp = ppT::precompute_G1(proof.g_C); + const G1_precomp acc_precomp = ppT::precompute_G1(acc); + + const Fqk QAP1 = ppT::miller_loop(proof_g_A_precomp, proof_g_B_precomp); + const Fqk QAP2 = ppT::double_miller_loop( + acc_precomp, pvk.vk_gamma_g2_precomp, + proof_g_C_precomp, pvk.vk_delta_g2_precomp); + const GT QAP = ppT::final_exponentiation(QAP1 * QAP2.unitary_inverse()); + + if (QAP != pvk.vk_alpha_g1_beta_g2) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("QAP divisibility check failed.\n"); + } + result = false; + } + leave_block("Check QAP divisibility"); + leave_block("Online pairing computations"); + + leave_block("Call to r1cs_gg_ppzksnark_online_verifier_weak_IC"); + + return result; +} + +template +bool r1cs_gg_ppzksnark_verifier_weak_IC(const r1cs_gg_ppzksnark_verification_key &vk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_proof &proof) +{ + enter_block("Call to r1cs_gg_ppzksnark_verifier_weak_IC"); + r1cs_gg_ppzksnark_processed_verification_key pvk = r1cs_gg_ppzksnark_verifier_process_vk(vk); + bool result = r1cs_gg_ppzksnark_online_verifier_weak_IC(pvk, primary_input, proof); + leave_block("Call to r1cs_gg_ppzksnark_verifier_weak_IC"); + return result; +} + +template +bool r1cs_gg_ppzksnark_online_verifier_strong_IC(const r1cs_gg_ppzksnark_processed_verification_key &pvk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_proof &proof) +{ + bool result = true; + enter_block("Call to r1cs_gg_ppzksnark_online_verifier_strong_IC"); + + if (pvk.encoded_IC_query.domain_size() != primary_input.size()) + { + print_indent(); printf("Input length differs from expected (got %zu, expected %zu).\n", primary_input.size(), pvk.encoded_IC_query.domain_size()); + result = false; + } + else + { + result = r1cs_gg_ppzksnark_online_verifier_weak_IC(pvk, primary_input, proof); + } + + leave_block("Call to r1cs_gg_ppzksnark_online_verifier_strong_IC"); + return result; +} + +template +bool r1cs_gg_ppzksnark_verifier_strong_IC(const r1cs_gg_ppzksnark_verification_key &vk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_proof &proof) +{ + enter_block("Call to r1cs_gg_ppzksnark_verifier_strong_IC"); + r1cs_gg_ppzksnark_processed_verification_key pvk = r1cs_gg_ppzksnark_verifier_process_vk(vk); + bool result = r1cs_gg_ppzksnark_online_verifier_strong_IC(pvk, primary_input, proof); + leave_block("Call to r1cs_gg_ppzksnark_verifier_strong_IC"); + return result; +} + +template +bool r1cs_gg_ppzksnark_affine_verifier_weak_IC(const r1cs_gg_ppzksnark_verification_key &vk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_proof &proof) +{ + enter_block("Call to r1cs_gg_ppzksnark_affine_verifier_weak_IC"); + assert(vk.encoded_IC_query.domain_size() >= primary_input.size()); + + affine_ate_G2_precomp pvk_vk_gamma_g2_precomp = ppT::affine_ate_precompute_G2(vk.gamma_g2); + affine_ate_G2_precomp pvk_vk_delta_g2_precomp = ppT::affine_ate_precompute_G2(vk.delta_g2); + + enter_block("Accumulate input"); + const accumulation_vector > accumulated_IC = vk.encoded_IC_query.template accumulate_chunk >(primary_input.begin(), primary_input.end(), 0); + const G1 &acc = accumulated_IC.first; + leave_block("Accumulate input"); + + bool result = true; + + enter_block("Check if the proof is well-formed"); + if (!proof.is_well_formed()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("At least one of the proof elements does not lie on the curve.\n"); + } + result = false; + } + leave_block("Check if the proof is well-formed"); + + enter_block("Check QAP divisibility"); + const affine_ate_G1_precomp proof_g_A_precomp = ppT::affine_ate_precompute_G1(proof.g_A); + const affine_ate_G2_precomp proof_g_B_precomp = ppT::affine_ate_precompute_G2(proof.g_B); + const affine_ate_G1_precomp proof_g_C_precomp = ppT::affine_ate_precompute_G1(proof.g_C); + const affine_ate_G1_precomp acc_precomp = ppT::affine_ate_precompute_G1(acc); + + const Fqk QAP_miller = ppT::affine_ate_e_times_e_over_e_miller_loop( + acc_precomp, pvk_vk_gamma_g2_precomp, + proof_g_C_precomp, pvk_vk_delta_g2_precomp, + proof_g_A_precomp, proof_g_B_precomp); + const GT QAP = ppT::final_exponentiation(QAP_miller.unitary_inverse()); + + if (QAP != vk.alpha_g1_beta_g2) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("QAP divisibility check failed.\n"); + } + result = false; + } + leave_block("Check QAP divisibility"); + + leave_block("Call to r1cs_gg_ppzksnark_affine_verifier_weak_IC"); + + return result; +} + +} // libsnark +#endif // R1CS_GG_PPZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark_params.hpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark_params.hpp new file mode 100644 index 0000000..dd347cb --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark_params.hpp @@ -0,0 +1,34 @@ +/** @file + ***************************************************************************** + + Declaration of public-parameter selector for the R1CS GG-ppzkSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_GG_PPZKSNARK_PARAMS_HPP_ +#define R1CS_GG_PPZKSNARK_PARAMS_HPP_ + +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" + +namespace libsnark { + +/** + * Below are various template aliases (used for convenience). + */ + +template +using r1cs_gg_ppzksnark_constraint_system = r1cs_constraint_system >; + +template +using r1cs_gg_ppzksnark_primary_input = r1cs_primary_input >; + +template +using r1cs_gg_ppzksnark_auxiliary_input = r1cs_auxiliary_input >; + +} // libsnark + +#endif // R1CS_GG_PPZKSNARK_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/tests/test_r1cs_gg_ppzksnark.cpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/tests/test_r1cs_gg_ppzksnark.cpp new file mode 100644 index 0000000..c2e0906 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/tests/test_r1cs_gg_ppzksnark.cpp @@ -0,0 +1,42 @@ +/** @file + ***************************************************************************** + Test program that exercises the ppzkSNARK (first generator, then + prover, then verifier) on a synthetic R1CS instance. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include + +#include "common/default_types/r1cs_gg_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/examples/run_r1cs_gg_ppzksnark.hpp" + +using namespace libsnark; + +template +void test_r1cs_gg_ppzksnark(size_t num_constraints, + size_t input_size) +{ + print_header("(enter) Test R1CS GG-ppzkSNARK"); + + const bool test_serialization = true; + r1cs_example > example = generate_r1cs_example_with_binary_input >(num_constraints, input_size); + const bool bit = run_r1cs_gg_ppzksnark(example, test_serialization); + assert(bit); + + print_header("(leave) Test R1CS GG-ppzkSNARK"); +} + +int main() +{ + default_r1cs_gg_ppzksnark_pp::init_public_params(); + start_profiling(); + + test_r1cs_gg_ppzksnark(1000, 100); +} diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp new file mode 100644 index 0000000..d2a686c --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp @@ -0,0 +1,36 @@ +/** @file + ***************************************************************************** + + Declaration of functionality that runs the R1CS ppzkSNARK for + a given R1CS example. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_R1CS_PPZKSNARK_HPP_ +#define RUN_R1CS_PPZKSNARK_HPP_ + +#include "common/default_types/ec_pp.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" + +namespace libsnark { + +/** + * Runs the ppzkSNARK (generator, prover, and verifier) for a given + * R1CS example (specified by a constraint system, input, and witness). + * + * Optionally, also test the serialization routines for keys and proofs. + * (This takes additional time.) + */ +template +bool run_r1cs_ppzksnark(const r1cs_example > &example, + const bool test_serialization); + +} // libsnark + +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc" + +#endif // RUN_R1CS_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc new file mode 100644 index 0000000..9bc8758 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc @@ -0,0 +1,114 @@ +/** @file + ***************************************************************************** + + Implementation of functionality that runs the R1CS ppzkSNARK for + a given R1CS example. + + See run_r1cs_ppzksnark.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_R1CS_PPZKSNARK_TCC_ +#define RUN_R1CS_PPZKSNARK_TCC_ + +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" + +#include +#include + +#include "common/profiling.hpp" + +namespace libsnark { + +template +typename std::enable_if::type +test_affine_verifier(const r1cs_ppzksnark_verification_key &vk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof, + const bool expected_answer) +{ + print_header("R1CS ppzkSNARK Affine Verifier"); + const bool answer = r1cs_ppzksnark_affine_verifier_weak_IC(vk, primary_input, proof); + assert(answer == expected_answer); +} + +template +typename std::enable_if::type +test_affine_verifier(const r1cs_ppzksnark_verification_key &vk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof, + const bool expected_answer) +{ + UNUSED(vk, primary_input, proof, expected_answer); + print_header("R1CS ppzkSNARK Affine Verifier"); + printf("Affine verifier is not supported; not testing anything.\n"); +} + +/** + * The code below provides an example of all stages of running a R1CS ppzkSNARK. + * + * Of course, in a real-life scenario, we would have three distinct entities, + * mangled into one in the demonstration below. The three entities are as follows. + * (1) The "generator", which runs the ppzkSNARK generator on input a given + * constraint system CS to create a proving and a verification key for CS. + * (2) The "prover", which runs the ppzkSNARK prover on input the proving key, + * a primary input for CS, and an auxiliary input for CS. + * (3) The "verifier", which runs the ppzkSNARK verifier on input the verification key, + * a primary input for CS, and a proof. + */ +template +bool run_r1cs_ppzksnark(const r1cs_example > &example, + const bool test_serialization) +{ + enter_block("Call to run_r1cs_ppzksnark"); + + print_header("R1CS ppzkSNARK Generator"); + r1cs_ppzksnark_keypair keypair = r1cs_ppzksnark_generator(example.constraint_system); + printf("\n"); print_indent(); print_mem("after generator"); + + print_header("Preprocess verification key"); + r1cs_ppzksnark_processed_verification_key pvk = r1cs_ppzksnark_verifier_process_vk(keypair.vk); + + if (test_serialization) + { + enter_block("Test serialization of keys"); + keypair.pk = reserialize >(keypair.pk); + keypair.vk = reserialize >(keypair.vk); + pvk = reserialize >(pvk); + leave_block("Test serialization of keys"); + } + + print_header("R1CS ppzkSNARK Prover"); + r1cs_ppzksnark_proof proof = r1cs_ppzksnark_prover(keypair.pk, example.primary_input, example.auxiliary_input); + printf("\n"); print_indent(); print_mem("after prover"); + + if (test_serialization) + { + enter_block("Test serialization of proof"); + proof = reserialize >(proof); + leave_block("Test serialization of proof"); + } + + print_header("R1CS ppzkSNARK Verifier"); + const bool ans = r1cs_ppzksnark_verifier_strong_IC(keypair.vk, example.primary_input, proof); + printf("\n"); print_indent(); print_mem("after verifier"); + printf("* The verification result is: %s\n", (ans ? "PASS" : "FAIL")); + + print_header("R1CS ppzkSNARK Online Verifier"); + const bool ans2 = r1cs_ppzksnark_online_verifier_strong_IC(pvk, example.primary_input, proof); + assert(ans == ans2); + + test_affine_verifier(keypair.vk, example.primary_input, proof, ans); + + leave_block("Call to run_r1cs_ppzksnark"); + + return ans; +} + +} // libsnark + +#endif // RUN_R1CS_PPZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp new file mode 100644 index 0000000..5c54150 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp @@ -0,0 +1,71 @@ +/** @file + ***************************************************************************** + Profiling program that exercises the ppzkSNARK (first generator, then prover, + then verifier) on a synthetic R1CS instance. + + The command + + $ src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark 1000 10 Fr + + exercises the ppzkSNARK (first generator, then prover, then verifier) on an R1CS instance with 1000 equations and an input consisting of 10 field elements. + + (If you get the error `zmInit ERR:can't protect`, see the discussion [above](#elliptic-curve-choices).) + + The command + + $ src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark 1000 10 bytes + + does the same but now the input consists of 10 bytes. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include + +#include "common/default_types/r1cs_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp" + +using namespace libsnark; + +int main(int argc, const char * argv[]) +{ + default_r1cs_ppzksnark_pp::init_public_params(); + start_profiling(); + + if (argc == 2 && strcmp(argv[1], "-v") == 0) + { + print_compilation_info(); + return 0; + } + + if (argc != 3 && argc != 4) + { + printf("usage: %s num_constraints input_size [Fr|bytes]\n", argv[0]); + return 1; + } + const int num_constraints = atoi(argv[1]); + int input_size = atoi(argv[2]); + if (argc == 4) + { + assert(strcmp(argv[3], "Fr") == 0 || strcmp(argv[3], "bytes") == 0); + if (strcmp(argv[3], "bytes") == 0) + { + input_size = div_ceil(8 * input_size, Fr::capacity()); + } + } + + enter_block("Generate R1CS example"); + r1cs_example > example = generate_r1cs_example_with_field_input >(num_constraints, input_size); + leave_block("Generate R1CS example"); + + print_header("(enter) Profile R1CS ppzkSNARK"); + const bool test_serialization = true; + run_r1cs_ppzksnark(example, test_serialization); + print_header("(leave) Profile R1CS ppzkSNARK"); +} diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp new file mode 100644 index 0000000..6e74f07 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp @@ -0,0 +1,467 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a ppzkSNARK for R1CS. + + This includes: + - class for proving key + - class for verification key + - class for processed verification key + - class for key pair (proving key & verification key) + - class for proof + - generator algorithm + - prover algorithm + - verifier algorithm (with strong or weak input consistency) + - online verifier algorithm (with strong or weak input consistency) + + The implementation instantiates (a modification of) the protocol of \[PGHR13], + by following extending, and optimizing the approach described in \[BCTV14]. + + + Acronyms: + + - R1CS = "Rank-1 Constraint Systems" + - ppzkSNARK = "PreProcessing Zero-Knowledge Succinct Non-interactive ARgument of Knowledge" + + References: + + \[BCTV14]: + "Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture", + Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, + USENIX Security 2014, + + + \[PGHR13]: + "Pinocchio: Nearly practical verifiable computation", + Bryan Parno, Craig Gentry, Jon Howell, Mariana Raykova, + IEEE S&P 2013, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_PPZKSNARK_HPP_ +#define R1CS_PPZKSNARK_HPP_ + +#include + +#include "algebra/curves/public_params.hpp" +#include "common/data_structures/accumulation_vector.hpp" +#include "algebra/knowledge_commitment/knowledge_commitment.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp" + +namespace libsnark { + +/******************************** Proving key ********************************/ + +template +class r1cs_ppzksnark_proving_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_proving_key &pk); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzksnark_proving_key &pk); + +/** + * A proving key for the R1CS ppzkSNARK. + */ +template +class r1cs_ppzksnark_proving_key { +public: + knowledge_commitment_vector, G1 > A_query; + knowledge_commitment_vector, G1 > B_query; + knowledge_commitment_vector, G1 > C_query; + G1_vector H_query; + G1_vector K_query; + + r1cs_ppzksnark_proving_key() {}; + r1cs_ppzksnark_proving_key& operator=(const r1cs_ppzksnark_proving_key &other) = default; + r1cs_ppzksnark_proving_key(const r1cs_ppzksnark_proving_key &other) = default; + r1cs_ppzksnark_proving_key(r1cs_ppzksnark_proving_key &&other) = default; + r1cs_ppzksnark_proving_key(knowledge_commitment_vector, G1 > &&A_query, + knowledge_commitment_vector, G1 > &&B_query, + knowledge_commitment_vector, G1 > &&C_query, + G1_vector &&H_query, + G1_vector &&K_query) : + A_query(std::move(A_query)), + B_query(std::move(B_query)), + C_query(std::move(C_query)), + H_query(std::move(H_query)), + K_query(std::move(K_query)) + {}; + + size_t G1_size() const + { + return 2*(A_query.domain_size() + C_query.domain_size()) + B_query.domain_size() + H_query.size() + K_query.size(); + } + + size_t G2_size() const + { + return B_query.domain_size(); + } + + size_t G1_sparse_size() const + { + return 2*(A_query.size() + C_query.size()) + B_query.size() + H_query.size() + K_query.size(); + } + + size_t G2_sparse_size() const + { + return B_query.size(); + } + + size_t size_in_bits() const + { + return A_query.size_in_bits() + B_query.size_in_bits() + C_query.size_in_bits() + libsnark::size_in_bits(H_query) + libsnark::size_in_bits(K_query); + } + + void print_size() const + { + print_indent(); printf("* G1 elements in PK: %zu\n", this->G1_size()); + print_indent(); printf("* Non-zero G1 elements in PK: %zu\n", this->G1_sparse_size()); + print_indent(); printf("* G2 elements in PK: %zu\n", this->G2_size()); + print_indent(); printf("* Non-zero G2 elements in PK: %zu\n", this->G2_sparse_size()); + print_indent(); printf("* PK size in bits: %zu\n", this->size_in_bits()); + } + + bool operator==(const r1cs_ppzksnark_proving_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzksnark_proving_key &pk); + friend std::istream& operator>> (std::istream &in, r1cs_ppzksnark_proving_key &pk); +}; + + +/******************************* Verification key ****************************/ + +template +class r1cs_ppzksnark_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_verification_key &vk); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzksnark_verification_key &vk); + +/** + * A verification key for the R1CS ppzkSNARK. + */ +template +class r1cs_ppzksnark_verification_key { +public: + G2 alphaA_g2; + G1 alphaB_g1; + G2 alphaC_g2; + G2 gamma_g2; + G1 gamma_beta_g1; + G2 gamma_beta_g2; + G2 rC_Z_g2; + + accumulation_vector > encoded_IC_query; + + r1cs_ppzksnark_verification_key() = default; + r1cs_ppzksnark_verification_key(const G2 &alphaA_g2, + const G1 &alphaB_g1, + const G2 &alphaC_g2, + const G2 &gamma_g2, + const G1 &gamma_beta_g1, + const G2 &gamma_beta_g2, + const G2 &rC_Z_g2, + const accumulation_vector > &eIC) : + alphaA_g2(alphaA_g2), + alphaB_g1(alphaB_g1), + alphaC_g2(alphaC_g2), + gamma_g2(gamma_g2), + gamma_beta_g1(gamma_beta_g1), + gamma_beta_g2(gamma_beta_g2), + rC_Z_g2(rC_Z_g2), + encoded_IC_query(eIC) + {}; + + size_t G1_size() const + { + return 2 + encoded_IC_query.size(); + } + + size_t G2_size() const + { + return 5; + } + + size_t size_in_bits() const + { + return (2 * G1::size_in_bits() + encoded_IC_query.size_in_bits() + 5 * G2::size_in_bits()); + } + + void print_size() const + { + print_indent(); printf("* G1 elements in VK: %zu\n", this->G1_size()); + print_indent(); printf("* G2 elements in VK: %zu\n", this->G2_size()); + print_indent(); printf("* VK size in bits: %zu\n", this->size_in_bits()); + } + + bool operator==(const r1cs_ppzksnark_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzksnark_verification_key &vk); + friend std::istream& operator>> (std::istream &in, r1cs_ppzksnark_verification_key &vk); + + static r1cs_ppzksnark_verification_key dummy_verification_key(const size_t input_size); +}; + + +/************************ Processed verification key *************************/ + +template +class r1cs_ppzksnark_processed_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_processed_verification_key &pvk); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzksnark_processed_verification_key &pvk); + +/** + * A processed verification key for the R1CS ppzkSNARK. + * + * Compared to a (non-processed) verification key, a processed verification key + * contains a small constant amount of additional pre-computed information that + * enables a faster verification time. + */ +template +class r1cs_ppzksnark_processed_verification_key { +public: + G2_precomp pp_G2_one_precomp; + G2_precomp vk_alphaA_g2_precomp; + G1_precomp vk_alphaB_g1_precomp; + G2_precomp vk_alphaC_g2_precomp; + G2_precomp vk_rC_Z_g2_precomp; + G2_precomp vk_gamma_g2_precomp; + G1_precomp vk_gamma_beta_g1_precomp; + G2_precomp vk_gamma_beta_g2_precomp; + + accumulation_vector > encoded_IC_query; + + bool operator==(const r1cs_ppzksnark_processed_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzksnark_processed_verification_key &pvk); + friend std::istream& operator>> (std::istream &in, r1cs_ppzksnark_processed_verification_key &pvk); +}; + + +/********************************** Key pair *********************************/ + +/** + * A key pair for the R1CS ppzkSNARK, which consists of a proving key and a verification key. + */ +template +class r1cs_ppzksnark_keypair { +public: + r1cs_ppzksnark_proving_key pk; + r1cs_ppzksnark_verification_key vk; + + r1cs_ppzksnark_keypair() = default; + r1cs_ppzksnark_keypair(const r1cs_ppzksnark_keypair &other) = default; + r1cs_ppzksnark_keypair(r1cs_ppzksnark_proving_key &&pk, + r1cs_ppzksnark_verification_key &&vk) : + pk(std::move(pk)), + vk(std::move(vk)) + {} + + r1cs_ppzksnark_keypair(r1cs_ppzksnark_keypair &&other) = default; +}; + + +/*********************************** Proof ***********************************/ + +template +class r1cs_ppzksnark_proof; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_proof &proof); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzksnark_proof &proof); + +/** + * A proof for the R1CS ppzkSNARK. + * + * While the proof has a structure, externally one merely opaquely produces, + * seralizes/deserializes, and verifies proofs. We only expose some information + * about the structure for statistics purposes. + */ +template +class r1cs_ppzksnark_proof { +public: + knowledge_commitment, G1 > g_A; + knowledge_commitment, G1 > g_B; + knowledge_commitment, G1 > g_C; + G1 g_H; + G1 g_K; + + r1cs_ppzksnark_proof() + { + // invalid proof with valid curve points + this->g_A.g = G1 ::one(); + this->g_A.h = G1::one(); + this->g_B.g = G2 ::one(); + this->g_B.h = G1::one(); + this->g_C.g = G1 ::one(); + this->g_C.h = G1::one(); + this->g_H = G1::one(); + this->g_K = G1::one(); + } + r1cs_ppzksnark_proof(knowledge_commitment, G1 > &&g_A, + knowledge_commitment, G1 > &&g_B, + knowledge_commitment, G1 > &&g_C, + G1 &&g_H, + G1 &&g_K) : + g_A(std::move(g_A)), + g_B(std::move(g_B)), + g_C(std::move(g_C)), + g_H(std::move(g_H)), + g_K(std::move(g_K)) + {}; + + size_t G1_size() const + { + return 7; + } + + size_t G2_size() const + { + return 1; + } + + size_t size_in_bits() const + { + return G1_size() * G1::size_in_bits() + G2_size() * G2::size_in_bits(); + } + + void print_size() const + { + //print_indent(); printf("* G1 elements in proof: %zu\n", this->G1_size()); + //print_indent(); printf("* G2 elements in proof: %zu\n", this->G2_size()); + //print_indent(); printf("* Proof size in bits: %zu\n", this->size_in_bits()); + } + + bool is_well_formed() const + { + return (g_A.g.is_well_formed() && g_A.h.is_well_formed() && + g_B.g.is_well_formed() && g_B.h.is_well_formed() && + g_C.g.is_well_formed() && g_C.h.is_well_formed() && + g_H.is_well_formed() && + g_K.is_well_formed()); + } + + bool operator==(const r1cs_ppzksnark_proof &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzksnark_proof &proof); + friend std::istream& operator>> (std::istream &in, r1cs_ppzksnark_proof &proof); +}; + + +/***************************** Main algorithms *******************************/ + +/** + * A generator algorithm for the R1CS ppzkSNARK. + * + * Given a R1CS constraint system CS, this algorithm produces proving and verification keys for CS. + */ +template +r1cs_ppzksnark_keypair r1cs_ppzksnark_generator(const r1cs_ppzksnark_constraint_system &cs); + +/** + * A prover algorithm for the R1CS ppzkSNARK. + * + * Given a R1CS primary input X and a R1CS auxiliary input Y, this algorithm + * produces a proof (of knowledge) that attests to the following statement: + * ``there exists Y such that CS(X,Y)=0''. + * Above, CS is the R1CS constraint system that was given as input to the generator algorithm. + */ +template +r1cs_ppzksnark_proof r1cs_ppzksnark_prover(const r1cs_ppzksnark_proving_key &pk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_auxiliary_input &auxiliary_input, + const r1cs_ppzksnark_constraint_system &cs); + +/* + Below are four variants of verifier algorithm for the R1CS ppzkSNARK. + + These are the four cases that arise from the following two choices: + + (1) The verifier accepts a (non-processed) verification key or, instead, a processed verification key. + In the latter case, we call the algorithm an "online verifier". + + (2) The verifier checks for "weak" input consistency or, instead, "strong" input consistency. + Strong input consistency requires that |primary_input| = CS.num_inputs, whereas + weak input consistency requires that |primary_input| <= CS.num_inputs (and + the primary input is implicitly padded with zeros up to length CS.num_inputs). + */ + +/** + * A verifier algorithm for the R1CS ppzkSNARK that: + * (1) accepts a non-processed verification key, and + * (2) has weak input consistency. + */ +template +bool r1cs_ppzksnark_verifier_weak_IC(const r1cs_ppzksnark_verification_key &vk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof); + +/** + * A verifier algorithm for the R1CS ppzkSNARK that: + * (1) accepts a non-processed verification key, and + * (2) has strong input consistency. + */ +template +bool r1cs_ppzksnark_verifier_strong_IC(const r1cs_ppzksnark_verification_key &vk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof); + +/** + * Convert a (non-processed) verification key into a processed verification key. + */ +template +r1cs_ppzksnark_processed_verification_key r1cs_ppzksnark_verifier_process_vk(const r1cs_ppzksnark_verification_key &vk); + +/** + * A verifier algorithm for the R1CS ppzkSNARK that: + * (1) accepts a processed verification key, and + * (2) has weak input consistency. + */ +template +bool r1cs_ppzksnark_online_verifier_weak_IC(const r1cs_ppzksnark_processed_verification_key &pvk, + const r1cs_ppzksnark_primary_input &input, + const r1cs_ppzksnark_proof &proof); + +/** + * A verifier algorithm for the R1CS ppzkSNARK that: + * (1) accepts a processed verification key, and + * (2) has strong input consistency. + */ +template +bool r1cs_ppzksnark_online_verifier_strong_IC(const r1cs_ppzksnark_processed_verification_key &pvk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof); + +/****************************** Miscellaneous ********************************/ + +/** + * For debugging purposes (of r1cs_ppzksnark_r1cs_ppzksnark_verifier_gadget): + * + * A verifier algorithm for the R1CS ppzkSNARK that: + * (1) accepts a non-processed verification key, + * (2) has weak input consistency, and + * (3) uses affine coordinates for elliptic-curve computations. + */ +template +bool r1cs_ppzksnark_affine_verifier_weak_IC(const r1cs_ppzksnark_verification_key &vk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof); + + +} // libsnark + +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc" + +#endif // R1CS_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc new file mode 100644 index 0000000..008aa44 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc @@ -0,0 +1,789 @@ +/** @file +***************************************************************************** + +Implementation of interfaces for a ppzkSNARK for R1CS. + +See r1cs_ppzksnark.hpp . + +***************************************************************************** +* @author This file is part of libsnark, developed by SCIPR Lab +* and contributors (see AUTHORS). +* @copyright MIT license (see LICENSE file) +*****************************************************************************/ + +#ifndef R1CS_PPZKSNARK_TCC_ +#define R1CS_PPZKSNARK_TCC_ + +#include +#include +#include +#include +#include + +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "algebra/scalar_multiplication/multiexp.hpp" +#include "algebra/scalar_multiplication/kc_multiexp.hpp" +#include "reductions/r1cs_to_qap/r1cs_to_qap.hpp" + +namespace libsnark { + +template +bool r1cs_ppzksnark_proving_key::operator==(const r1cs_ppzksnark_proving_key &other) const +{ + return (this->A_query == other.A_query && + this->B_query == other.B_query && + this->C_query == other.C_query && + this->H_query == other.H_query && + this->K_query == other.K_query); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_proving_key &pk) +{ + out << pk.A_query; + out << pk.B_query; + out << pk.C_query; + out << pk.H_query; + out << pk.K_query; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzksnark_proving_key &pk) +{ + in >> pk.A_query; + in >> pk.B_query; + in >> pk.C_query; + in >> pk.H_query; + in >> pk.K_query; + + return in; +} + +template +bool r1cs_ppzksnark_verification_key::operator==(const r1cs_ppzksnark_verification_key &other) const +{ + return (this->alphaA_g2 == other.alphaA_g2 && + this->alphaB_g1 == other.alphaB_g1 && + this->alphaC_g2 == other.alphaC_g2 && + this->gamma_g2 == other.gamma_g2 && + this->gamma_beta_g1 == other.gamma_beta_g1 && + this->gamma_beta_g2 == other.gamma_beta_g2 && + this->rC_Z_g2 == other.rC_Z_g2 && + this->encoded_IC_query == other.encoded_IC_query); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_verification_key &vk) +{ + out << vk.alphaA_g2 << OUTPUT_NEWLINE; + out << vk.alphaB_g1 << OUTPUT_NEWLINE; + out << vk.alphaC_g2 << OUTPUT_NEWLINE; + out << vk.gamma_g2 << OUTPUT_NEWLINE; + out << vk.gamma_beta_g1 << OUTPUT_NEWLINE; + out << vk.gamma_beta_g2 << OUTPUT_NEWLINE; + out << vk.rC_Z_g2 << OUTPUT_NEWLINE; + out << vk.encoded_IC_query << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzksnark_verification_key &vk) +{ + in >> vk.alphaA_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.alphaB_g1; + consume_OUTPUT_NEWLINE(in); + in >> vk.alphaC_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.gamma_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.gamma_beta_g1; + consume_OUTPUT_NEWLINE(in); + in >> vk.gamma_beta_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.rC_Z_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.encoded_IC_query; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +bool r1cs_ppzksnark_processed_verification_key::operator==(const r1cs_ppzksnark_processed_verification_key &other) const +{ + return (this->pp_G2_one_precomp == other.pp_G2_one_precomp && + this->vk_alphaA_g2_precomp == other.vk_alphaA_g2_precomp && + this->vk_alphaB_g1_precomp == other.vk_alphaB_g1_precomp && + this->vk_alphaC_g2_precomp == other.vk_alphaC_g2_precomp && + this->vk_rC_Z_g2_precomp == other.vk_rC_Z_g2_precomp && + this->vk_gamma_g2_precomp == other.vk_gamma_g2_precomp && + this->vk_gamma_beta_g1_precomp == other.vk_gamma_beta_g1_precomp && + this->vk_gamma_beta_g2_precomp == other.vk_gamma_beta_g2_precomp && + this->encoded_IC_query == other.encoded_IC_query); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_processed_verification_key &pvk) +{ + out << pvk.pp_G2_one_precomp << OUTPUT_NEWLINE; + out << pvk.vk_alphaA_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_alphaB_g1_precomp << OUTPUT_NEWLINE; + out << pvk.vk_alphaC_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_rC_Z_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_gamma_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_gamma_beta_g1_precomp << OUTPUT_NEWLINE; + out << pvk.vk_gamma_beta_g2_precomp << OUTPUT_NEWLINE; + out << pvk.encoded_IC_query << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzksnark_processed_verification_key &pvk) +{ + in >> pvk.pp_G2_one_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_alphaA_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_alphaB_g1_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_alphaC_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_rC_Z_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_gamma_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_gamma_beta_g1_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_gamma_beta_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.encoded_IC_query; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +bool r1cs_ppzksnark_proof::operator==(const r1cs_ppzksnark_proof &other) const +{ + return (this->g_A == other.g_A && + this->g_B == other.g_B && + this->g_C == other.g_C && + this->g_H == other.g_H && + this->g_K == other.g_K); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_proof &proof) +{ + out << proof.g_A << OUTPUT_NEWLINE; + out << proof.g_B << OUTPUT_NEWLINE; + out << proof.g_C << OUTPUT_NEWLINE; + out << proof.g_H << OUTPUT_NEWLINE; + out << proof.g_K << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzksnark_proof &proof) +{ + in >> proof.g_A; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_B; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_C; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_H; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_K; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +r1cs_ppzksnark_verification_key r1cs_ppzksnark_verification_key::dummy_verification_key(const size_t input_size) +{ + r1cs_ppzksnark_verification_key result; + result.alphaA_g2 = Fr::random_element() * G2::one(); + result.alphaB_g1 = Fr::random_element() * G1::one(); + result.alphaC_g2 = Fr::random_element() * G2::one(); + result.gamma_g2 = Fr::random_element() * G2::one(); + result.gamma_beta_g1 = Fr::random_element() * G1::one(); + result.gamma_beta_g2 = Fr::random_element() * G2::one(); + result.rC_Z_g2 = Fr::random_element() * G2::one(); + + G1 base = Fr::random_element() * G1::one(); + G1_vector v; + for (size_t i = 0; i < input_size; ++i) + { + v.emplace_back(Fr::random_element() * G1::one()); + } + + result.encoded_IC_query = accumulation_vector >(std::move(base), std::move(v)); + + return result; +} + +template +r1cs_ppzksnark_keypair r1cs_ppzksnark_generator(const r1cs_ppzksnark_constraint_system &cs) +{ + enter_block("Call to r1cs_ppzksnark_generator"); + + /* make the B_query "lighter" if possible */ + r1cs_ppzksnark_constraint_system cs_copy(cs); + cs_copy.swap_AB_if_beneficial(); + + /* draw random element at which the QAP is evaluated */ + const Fr t = Fr::random_element(); + + qap_instance_evaluation > qap_inst = r1cs_to_qap_instance_map_with_evaluation(cs_copy, t); + + print_indent(); printf("* QAP number of variables: %zu\n", qap_inst.num_variables()); + print_indent(); printf("* QAP pre degree: %zu\n", cs_copy.constraints.size()); + print_indent(); printf("* QAP degree: %zu\n", qap_inst.degree()); + print_indent(); printf("* QAP number of input variables: %zu\n", qap_inst.num_inputs()); + + enter_block("Compute query densities"); + size_t non_zero_At = 0, non_zero_Bt = 0, non_zero_Ct = 0, non_zero_Ht = 0; + for (size_t i = 0; i < qap_inst.num_variables()+1; ++i) + { + if (!qap_inst.At[i].is_zero()) + { + ++non_zero_At; + } + if (!qap_inst.Bt[i].is_zero()) + { + ++non_zero_Bt; + } + if (!qap_inst.Ct[i].is_zero()) + { + ++non_zero_Ct; + } + } + for (size_t i = 0; i < qap_inst.degree()+1; ++i) + { + if (!qap_inst.Ht[i].is_zero()) + { + ++non_zero_Ht; + } + } + leave_block("Compute query densities"); + + Fr_vector At = std::move(qap_inst.At); // qap_inst.At is now in unspecified state, but we do not use it later + Fr_vector Bt = std::move(qap_inst.Bt); // qap_inst.Bt is now in unspecified state, but we do not use it later + Fr_vector Ct = std::move(qap_inst.Ct); // qap_inst.Ct is now in unspecified state, but we do not use it later + Fr_vector Ht = std::move(qap_inst.Ht); // qap_inst.Ht is now in unspecified state, but we do not use it later + + /* append Zt to At,Bt,Ct with */ + At.emplace_back(qap_inst.Zt); + Bt.emplace_back(qap_inst.Zt); + Ct.emplace_back(qap_inst.Zt); + + const Fr alphaA = Fr::random_element(), + alphaB = Fr::random_element(), + alphaC = Fr::random_element(), + rA = Fr::random_element(), + rB = Fr::random_element(), + beta = Fr::random_element(), + gamma = Fr::random_element(); + const Fr rC = rA * rB; + + // consrtuct the same-coefficient-check query (must happen before zeroing out the prefix of At) + Fr_vector Kt; + Kt.reserve(qap_inst.num_variables()+4); + for (size_t i = 0; i < qap_inst.num_variables()+1; ++i) + { + Kt.emplace_back( beta * (rA * At[i] + rB * Bt[i] + rC * Ct[i] ) ); + } + Kt.emplace_back(beta * rA * qap_inst.Zt); + Kt.emplace_back(beta * rB * qap_inst.Zt); + Kt.emplace_back(beta * rC * qap_inst.Zt); + + /* zero out prefix of At and stick it into IC coefficients */ + Fr_vector IC_coefficients; + IC_coefficients.reserve(qap_inst.num_inputs() + 1); + for (size_t i = 0; i < qap_inst.num_inputs() + 1; ++i) + { + IC_coefficients.emplace_back(At[i]); + assert(!IC_coefficients[i].is_zero()); + At[i] = Fr::zero(); + } + + const size_t g1_exp_count = 2*(non_zero_At - qap_inst.num_inputs() + non_zero_Ct) + non_zero_Bt + non_zero_Ht + Kt.size(); + const size_t g2_exp_count = non_zero_Bt; + + size_t g1_window = get_exp_window_size >(g1_exp_count); + size_t g2_window = get_exp_window_size >(g2_exp_count); + print_indent(); printf("* G1 window: %zu\n", g1_window); + print_indent(); printf("* G2 window: %zu\n", g2_window); + +#ifdef MULTICORE + const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads() +#else + const size_t chunks = 1; +#endif + + enter_block("Generating G1 multiexp table"); + window_table > g1_table = get_window_table(Fr::size_in_bits(), g1_window, G1::one()); + leave_block("Generating G1 multiexp table"); + + enter_block("Generating G2 multiexp table"); + window_table > g2_table = get_window_table(Fr::size_in_bits(), g2_window, G2::one()); + leave_block("Generating G2 multiexp table"); + + enter_block("Generate R1CS proving key"); + + enter_block("Generate knowledge commitments"); + enter_block("Compute the A-query", false); + knowledge_commitment_vector, G1 > A_query = kc_batch_exp(Fr::size_in_bits(), g1_window, g1_window, g1_table, g1_table, rA, rA*alphaA, At, chunks); + leave_block("Compute the A-query", false); + + enter_block("Compute the B-query", false); + knowledge_commitment_vector, G1 > B_query = kc_batch_exp(Fr::size_in_bits(), g2_window, g1_window, g2_table, g1_table, rB, rB*alphaB, Bt, chunks); + leave_block("Compute the B-query", false); + + enter_block("Compute the C-query", false); + knowledge_commitment_vector, G1 > C_query = kc_batch_exp(Fr::size_in_bits(), g1_window, g1_window, g1_table, g1_table, rC, rC*alphaC, Ct, chunks); + leave_block("Compute the C-query", false); + + enter_block("Compute the H-query", false); + G1_vector H_query = batch_exp(Fr::size_in_bits(), g1_window, g1_table, Ht); + leave_block("Compute the H-query", false); + + enter_block("Compute the K-query", false); + G1_vector K_query = batch_exp(Fr::size_in_bits(), g1_window, g1_table, Kt); +#ifdef USE_MIXED_ADDITION + batch_to_special >(K_query); +#endif + leave_block("Compute the K-query", false); + + leave_block("Generate knowledge commitments"); + + leave_block("Generate R1CS proving key"); + + enter_block("Generate R1CS verification key"); + G2 alphaA_g2 = alphaA * G2::one(); + G1 alphaB_g1 = alphaB * G1::one(); + G2 alphaC_g2 = alphaC * G2::one(); + G2 gamma_g2 = gamma * G2::one(); + G1 gamma_beta_g1 = (gamma * beta) * G1::one(); + G2 gamma_beta_g2 = (gamma * beta) * G2::one(); + G2 rC_Z_g2 = (rC * qap_inst.Zt) * G2::one(); + + enter_block("Encode IC query for R1CS verification key"); + G1 encoded_IC_base = (rA * IC_coefficients[0]) * G1::one(); + Fr_vector multiplied_IC_coefficients; + multiplied_IC_coefficients.reserve(qap_inst.num_inputs()); + for (size_t i = 1; i < qap_inst.num_inputs() + 1; ++i) + { + multiplied_IC_coefficients.emplace_back(rA * IC_coefficients[i]); + } + G1_vector encoded_IC_values = batch_exp(Fr::size_in_bits(), g1_window, g1_table, multiplied_IC_coefficients); + + leave_block("Encode IC query for R1CS verification key"); + leave_block("Generate R1CS verification key"); + + leave_block("Call to r1cs_ppzksnark_generator"); + + accumulation_vector > encoded_IC_query(std::move(encoded_IC_base), std::move(encoded_IC_values)); + + r1cs_ppzksnark_verification_key vk = r1cs_ppzksnark_verification_key(alphaA_g2, + alphaB_g1, + alphaC_g2, + gamma_g2, + gamma_beta_g1, + gamma_beta_g2, + rC_Z_g2, + encoded_IC_query); + r1cs_ppzksnark_proving_key pk = r1cs_ppzksnark_proving_key(std::move(A_query), + std::move(B_query), + std::move(C_query), + std::move(H_query), + std::move(K_query)); + + pk.print_size(); + vk.print_size(); + + return r1cs_ppzksnark_keypair(std::move(pk), std::move(vk)); +} + +template +r1cs_ppzksnark_proof r1cs_ppzksnark_prover(const r1cs_ppzksnark_proving_key &pk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_auxiliary_input &auxiliary_input, + const r1cs_ppzksnark_constraint_system &cs) +{ + enter_block("Call to r1cs_ppzksnark_prover"); + +#ifdef DEBUG + assert(pk.constraint_system.is_satisfied(primary_input, auxiliary_input)); +#endif + + const Fr d1 = Fr::random_element(), + d2 = Fr::random_element(), + d3 = Fr::random_element(); + + enter_block("Compute the polynomial H"); + const qap_witness > qap_wit = r1cs_to_qap_witness_map(cs, primary_input, auxiliary_input, d1, d2, d3); + leave_block("Compute the polynomial H"); + +#ifdef DEBUG + const Fr t = Fr::random_element(); + qap_instance_evaluation > qap_inst = r1cs_to_qap_instance_map_with_evaluation(pk.constraint_system, t); + assert(qap_inst.is_satisfied(qap_wit)); +#endif + + knowledge_commitment, G1 > g_A = pk.A_query[0] + qap_wit.d1*pk.A_query[qap_wit.num_variables()+1]; + knowledge_commitment, G1 > g_B = pk.B_query[0] + qap_wit.d2*pk.B_query[qap_wit.num_variables()+1]; + knowledge_commitment, G1 > g_C = pk.C_query[0] + qap_wit.d3*pk.C_query[qap_wit.num_variables()+1]; + + G1 g_H = G1::zero(); + G1 g_K = (pk.K_query[0] + + qap_wit.d1*pk.K_query[qap_wit.num_variables()+1] + + qap_wit.d2*pk.K_query[qap_wit.num_variables()+2] + + qap_wit.d3*pk.K_query[qap_wit.num_variables()+3]); + +#ifdef DEBUG + for (size_t i = 0; i < qap_wit.num_inputs() + 1; ++i) + { + assert(pk.A_query[i].g == G1::zero()); + } + assert(pk.A_query.domain_size() == qap_wit.num_variables()+2); + assert(pk.B_query.domain_size() == qap_wit.num_variables()+2); + assert(pk.C_query.domain_size() == qap_wit.num_variables()+2); + assert(pk.H_query.size() == qap_wit.degree()+1); + assert(pk.K_query.size() == qap_wit.num_variables()+4); +#endif + +#ifdef MULTICORE + const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads() +#else + const size_t chunks = 1; +#endif + + enter_block("Compute the proof"); + + enter_block("Compute answer to A-query", false); + g_A = g_A + kc_multi_exp_with_mixed_addition, G1, Fr >(pk.A_query, + 1, 1+qap_wit.num_variables(), + qap_wit.coefficients_for_ABCs.begin(), qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), + chunks, true); + leave_block("Compute answer to A-query", false); + + enter_block("Compute answer to B-query", false); + g_B = g_B + kc_multi_exp_with_mixed_addition, G1, Fr >(pk.B_query, + 1, 1+qap_wit.num_variables(), + qap_wit.coefficients_for_ABCs.begin(), qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), + chunks, true); + leave_block("Compute answer to B-query", false); + + enter_block("Compute answer to C-query", false); + g_C = g_C + kc_multi_exp_with_mixed_addition, G1, Fr >(pk.C_query, + 1, 1+qap_wit.num_variables(), + qap_wit.coefficients_for_ABCs.begin(), qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), + chunks, true); + leave_block("Compute answer to C-query", false); + + enter_block("Compute answer to H-query", false); + g_H = g_H + multi_exp, Fr >(pk.H_query.begin(), pk.H_query.begin()+qap_wit.degree()+1, + qap_wit.coefficients_for_H.begin(), qap_wit.coefficients_for_H.begin()+qap_wit.degree()+1, + chunks, true); + leave_block("Compute answer to H-query", false); + + enter_block("Compute answer to K-query", false); + g_K = g_K + multi_exp_with_mixed_addition, Fr >(pk.K_query.begin()+1, pk.K_query.begin()+1+qap_wit.num_variables(), + qap_wit.coefficients_for_ABCs.begin(), qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), + chunks, true); + leave_block("Compute answer to K-query", false); + + leave_block("Compute the proof"); + + leave_block("Call to r1cs_ppzksnark_prover"); + + r1cs_ppzksnark_proof proof = r1cs_ppzksnark_proof(std::move(g_A), std::move(g_B), std::move(g_C), std::move(g_H), std::move(g_K)); + proof.print_size(); + + return proof; +} + +template +r1cs_ppzksnark_processed_verification_key r1cs_ppzksnark_verifier_process_vk(const r1cs_ppzksnark_verification_key &vk) +{ + enter_block("Call to r1cs_ppzksnark_verifier_process_vk"); + + r1cs_ppzksnark_processed_verification_key pvk; + pvk.pp_G2_one_precomp = ppT::precompute_G2(G2::one()); + pvk.vk_alphaA_g2_precomp = ppT::precompute_G2(vk.alphaA_g2); + pvk.vk_alphaB_g1_precomp = ppT::precompute_G1(vk.alphaB_g1); + pvk.vk_alphaC_g2_precomp = ppT::precompute_G2(vk.alphaC_g2); + pvk.vk_rC_Z_g2_precomp = ppT::precompute_G2(vk.rC_Z_g2); + pvk.vk_gamma_g2_precomp = ppT::precompute_G2(vk.gamma_g2); + pvk.vk_gamma_beta_g1_precomp = ppT::precompute_G1(vk.gamma_beta_g1); + pvk.vk_gamma_beta_g2_precomp = ppT::precompute_G2(vk.gamma_beta_g2); + + pvk.encoded_IC_query = vk.encoded_IC_query; + + leave_block("Call to r1cs_ppzksnark_verifier_process_vk"); + + return pvk; +} + +template +bool r1cs_ppzksnark_online_verifier_weak_IC(const r1cs_ppzksnark_processed_verification_key &pvk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof) +{ + enter_block("Call to r1cs_ppzksnark_online_verifier_weak_IC"); + assert(pvk.encoded_IC_query.domain_size() >= primary_input.size()); + + enter_block("Compute input-dependent part of A"); + const accumulation_vector > accumulated_IC = pvk.encoded_IC_query.template accumulate_chunk >(primary_input.begin(), primary_input.end(), 0); + const G1 &acc = accumulated_IC.first; + leave_block("Compute input-dependent part of A"); + + bool result = true; + + enter_block("Check if the proof is well-formed"); + if (!proof.is_well_formed()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("At least one of the proof elements does not lie on the curve.\n"); + } + result = false; + } + leave_block("Check if the proof is well-formed"); + + enter_block("Online pairing computations"); + enter_block("Check knowledge commitment for A is valid"); + G1_precomp proof_g_A_g_precomp = ppT::precompute_G1(proof.g_A.g); + G1_precomp proof_g_A_h_precomp = ppT::precompute_G1(proof.g_A.h); + Fqk kc_A_1 = ppT::miller_loop(proof_g_A_g_precomp, pvk.vk_alphaA_g2_precomp); + Fqk kc_A_2 = ppT::miller_loop(proof_g_A_h_precomp, pvk.pp_G2_one_precomp); + GT kc_A = ppT::final_exponentiation(kc_A_1 * kc_A_2.unitary_inverse()); + if (kc_A != GT::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Knowledge commitment for A query incorrect.\n"); + } + result = false; + } + leave_block("Check knowledge commitment for A is valid"); + + enter_block("Check knowledge commitment for B is valid"); + G2_precomp proof_g_B_g_precomp = ppT::precompute_G2(proof.g_B.g); + G1_precomp proof_g_B_h_precomp = ppT::precompute_G1(proof.g_B.h); + Fqk kc_B_1 = ppT::miller_loop(pvk.vk_alphaB_g1_precomp, proof_g_B_g_precomp); + Fqk kc_B_2 = ppT::miller_loop(proof_g_B_h_precomp, pvk.pp_G2_one_precomp); + GT kc_B = ppT::final_exponentiation(kc_B_1 * kc_B_2.unitary_inverse()); + if (kc_B != GT::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Knowledge commitment for B query incorrect.\n"); + } + result = false; + } + leave_block("Check knowledge commitment for B is valid"); + + enter_block("Check knowledge commitment for C is valid"); + G1_precomp proof_g_C_g_precomp = ppT::precompute_G1(proof.g_C.g); + G1_precomp proof_g_C_h_precomp = ppT::precompute_G1(proof.g_C.h); + Fqk kc_C_1 = ppT::miller_loop(proof_g_C_g_precomp, pvk.vk_alphaC_g2_precomp); + Fqk kc_C_2 = ppT::miller_loop(proof_g_C_h_precomp, pvk.pp_G2_one_precomp); + GT kc_C = ppT::final_exponentiation(kc_C_1 * kc_C_2.unitary_inverse()); + if (kc_C != GT::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Knowledge commitment for C query incorrect.\n"); + } + result = false; + } + leave_block("Check knowledge commitment for C is valid"); + + enter_block("Check QAP divisibility"); + // check that g^((A+acc)*B)=g^(H*\Prod(t-\sigma)+C) + // equivalently, via pairings, that e(g^(A+acc), g^B) = e(g^H, g^Z) + e(g^C, g^1) + G1_precomp proof_g_A_g_acc_precomp = ppT::precompute_G1(proof.g_A.g + acc); + G1_precomp proof_g_H_precomp = ppT::precompute_G1(proof.g_H); + Fqk QAP_1 = ppT::miller_loop(proof_g_A_g_acc_precomp, proof_g_B_g_precomp); + Fqk QAP_23 = ppT::double_miller_loop(proof_g_H_precomp, pvk.vk_rC_Z_g2_precomp, proof_g_C_g_precomp, pvk.pp_G2_one_precomp); + GT QAP = ppT::final_exponentiation(QAP_1 * QAP_23.unitary_inverse()); + if (QAP != GT::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("QAP divisibility check failed.\n"); + } + result = false; + } + leave_block("Check QAP divisibility"); + + enter_block("Check same coefficients were used"); + G1_precomp proof_g_K_precomp = ppT::precompute_G1(proof.g_K); + G1_precomp proof_g_A_g_acc_C_precomp = ppT::precompute_G1((proof.g_A.g + acc) + proof.g_C.g); + Fqk K_1 = ppT::miller_loop(proof_g_K_precomp, pvk.vk_gamma_g2_precomp); + Fqk K_23 = ppT::double_miller_loop(proof_g_A_g_acc_C_precomp, pvk.vk_gamma_beta_g2_precomp, pvk.vk_gamma_beta_g1_precomp, proof_g_B_g_precomp); + GT K = ppT::final_exponentiation(K_1 * K_23.unitary_inverse()); + if (K != GT::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Same-coefficient check failed.\n"); + } + result = false; + } + leave_block("Check same coefficients were used"); + leave_block("Online pairing computations"); + leave_block("Call to r1cs_ppzksnark_online_verifier_weak_IC"); + + return result; +} + +template +bool r1cs_ppzksnark_verifier_weak_IC(const r1cs_ppzksnark_verification_key &vk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof) +{ + enter_block("Call to r1cs_ppzksnark_verifier_weak_IC"); + r1cs_ppzksnark_processed_verification_key pvk = r1cs_ppzksnark_verifier_process_vk(vk); + bool result = r1cs_ppzksnark_online_verifier_weak_IC(pvk, primary_input, proof); + leave_block("Call to r1cs_ppzksnark_verifier_weak_IC"); + return result; +} + +template +bool r1cs_ppzksnark_online_verifier_strong_IC(const r1cs_ppzksnark_processed_verification_key &pvk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof) +{ + bool result = true; + enter_block("Call to r1cs_ppzksnark_online_verifier_strong_IC"); + + if (pvk.encoded_IC_query.domain_size() != primary_input.size()) + { + print_indent(); printf("Input length differs from expected (got %zu, expected %zu).\n", primary_input.size(), pvk.encoded_IC_query.domain_size()); + result = false; + } + else + { + result = r1cs_ppzksnark_online_verifier_weak_IC(pvk, primary_input, proof); + } + + leave_block("Call to r1cs_ppzksnark_online_verifier_strong_IC"); + return result; +} + +template +bool r1cs_ppzksnark_verifier_strong_IC(const r1cs_ppzksnark_verification_key &vk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof) +{ + enter_block("Call to r1cs_ppzksnark_verifier_strong_IC"); + r1cs_ppzksnark_processed_verification_key pvk = r1cs_ppzksnark_verifier_process_vk(vk); + bool result = r1cs_ppzksnark_online_verifier_strong_IC(pvk, primary_input, proof); + leave_block("Call to r1cs_ppzksnark_verifier_strong_IC"); + return result; +} + +template +bool r1cs_ppzksnark_affine_verifier_weak_IC(const r1cs_ppzksnark_verification_key &vk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof) +{ + enter_block("Call to r1cs_ppzksnark_affine_verifier_weak_IC"); + assert(vk.encoded_IC_query.domain_size() >= primary_input.size()); + + affine_ate_G2_precomp pvk_pp_G2_one_precomp = ppT::affine_ate_precompute_G2(G2::one()); + affine_ate_G2_precomp pvk_vk_alphaA_g2_precomp = ppT::affine_ate_precompute_G2(vk.alphaA_g2); + affine_ate_G1_precomp pvk_vk_alphaB_g1_precomp = ppT::affine_ate_precompute_G1(vk.alphaB_g1); + affine_ate_G2_precomp pvk_vk_alphaC_g2_precomp = ppT::affine_ate_precompute_G2(vk.alphaC_g2); + affine_ate_G2_precomp pvk_vk_rC_Z_g2_precomp = ppT::affine_ate_precompute_G2(vk.rC_Z_g2); + affine_ate_G2_precomp pvk_vk_gamma_g2_precomp = ppT::affine_ate_precompute_G2(vk.gamma_g2); + affine_ate_G1_precomp pvk_vk_gamma_beta_g1_precomp = ppT::affine_ate_precompute_G1(vk.gamma_beta_g1); + affine_ate_G2_precomp pvk_vk_gamma_beta_g2_precomp = ppT::affine_ate_precompute_G2(vk.gamma_beta_g2); + + enter_block("Compute input-dependent part of A"); + const accumulation_vector > accumulated_IC = vk.encoded_IC_query.template accumulate_chunk >(primary_input.begin(), primary_input.end(), 0); + assert(accumulated_IC.is_fully_accumulated()); + const G1 &acc = accumulated_IC.first; + leave_block("Compute input-dependent part of A"); + + bool result = true; + enter_block("Check knowledge commitment for A is valid"); + affine_ate_G1_precomp proof_g_A_g_precomp = ppT::affine_ate_precompute_G1(proof.g_A.g); + affine_ate_G1_precomp proof_g_A_h_precomp = ppT::affine_ate_precompute_G1(proof.g_A.h); + Fqk kc_A_miller = ppT::affine_ate_e_over_e_miller_loop(proof_g_A_g_precomp, pvk_vk_alphaA_g2_precomp, proof_g_A_h_precomp, pvk_pp_G2_one_precomp); + GT kc_A = ppT::final_exponentiation(kc_A_miller); + + if (kc_A != GT::one()) + { + print_indent(); printf("Knowledge commitment for A query incorrect.\n"); + result = false; + } + leave_block("Check knowledge commitment for A is valid"); + + enter_block("Check knowledge commitment for B is valid"); + affine_ate_G2_precomp proof_g_B_g_precomp = ppT::affine_ate_precompute_G2(proof.g_B.g); + affine_ate_G1_precomp proof_g_B_h_precomp = ppT::affine_ate_precompute_G1(proof.g_B.h); + Fqk kc_B_miller = ppT::affine_ate_e_over_e_miller_loop(pvk_vk_alphaB_g1_precomp, proof_g_B_g_precomp, proof_g_B_h_precomp, pvk_pp_G2_one_precomp); + GT kc_B = ppT::final_exponentiation(kc_B_miller); + if (kc_B != GT::one()) + { + print_indent(); printf("Knowledge commitment for B query incorrect.\n"); + result = false; + } + leave_block("Check knowledge commitment for B is valid"); + + enter_block("Check knowledge commitment for C is valid"); + affine_ate_G1_precomp proof_g_C_g_precomp = ppT::affine_ate_precompute_G1(proof.g_C.g); + affine_ate_G1_precomp proof_g_C_h_precomp = ppT::affine_ate_precompute_G1(proof.g_C.h); + Fqk kc_C_miller = ppT::affine_ate_e_over_e_miller_loop(proof_g_C_g_precomp, pvk_vk_alphaC_g2_precomp, proof_g_C_h_precomp, pvk_pp_G2_one_precomp); + GT kc_C = ppT::final_exponentiation(kc_C_miller); + if (kc_C != GT::one()) + { + print_indent(); printf("Knowledge commitment for C query incorrect.\n"); + result = false; + } + leave_block("Check knowledge commitment for C is valid"); + + enter_block("Check QAP divisibility"); + affine_ate_G1_precomp proof_g_A_g_acc_precomp = ppT::affine_ate_precompute_G1(proof.g_A.g + acc); + affine_ate_G1_precomp proof_g_H_precomp = ppT::affine_ate_precompute_G1(proof.g_H); + Fqk QAP_miller = ppT::affine_ate_e_times_e_over_e_miller_loop(proof_g_H_precomp, pvk_vk_rC_Z_g2_precomp, proof_g_C_g_precomp, pvk_pp_G2_one_precomp, proof_g_A_g_acc_precomp, proof_g_B_g_precomp); + GT QAP = ppT::final_exponentiation(QAP_miller); + if (QAP != GT::one()) + { + print_indent(); printf("QAP divisibility check failed.\n"); + result = false; + } + leave_block("Check QAP divisibility"); + + enter_block("Check same coefficients were used"); + affine_ate_G1_precomp proof_g_K_precomp = ppT::affine_ate_precompute_G1(proof.g_K); + affine_ate_G1_precomp proof_g_A_g_acc_C_precomp = ppT::affine_ate_precompute_G1((proof.g_A.g + acc) + proof.g_C.g); + Fqk K_miller = ppT::affine_ate_e_times_e_over_e_miller_loop(proof_g_A_g_acc_C_precomp, pvk_vk_gamma_beta_g2_precomp, pvk_vk_gamma_beta_g1_precomp, proof_g_B_g_precomp, proof_g_K_precomp, pvk_vk_gamma_g2_precomp); + GT K = ppT::final_exponentiation(K_miller); + if (K != GT::one()) + { + print_indent(); printf("Same-coefficient check failed.\n"); + result = false; + } + leave_block("Check same coefficients were used"); + + leave_block("Call to r1cs_ppzksnark_affine_verifier_weak_IC"); + + return result; +} + +} // libsnark +#endif // R1CS_PPZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp new file mode 100644 index 0000000..4054b8e --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp @@ -0,0 +1,34 @@ +/** @file + ***************************************************************************** + + Declaration of public-parameter selector for the R1CS ppzkSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_PPZKSNARK_PARAMS_HPP_ +#define R1CS_PPZKSNARK_PARAMS_HPP_ + +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" + +namespace libsnark { + +/** + * Below are various template aliases (used for convenience). + */ + +template +using r1cs_ppzksnark_constraint_system = r1cs_constraint_system >; + +template +using r1cs_ppzksnark_primary_input = r1cs_primary_input >; + +template +using r1cs_ppzksnark_auxiliary_input = r1cs_auxiliary_input >; + +} // libsnark + +#endif // R1CS_PPZKSNARK_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp new file mode 100644 index 0000000..6f8b575 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp @@ -0,0 +1,42 @@ +/** @file + ***************************************************************************** + Test program that exercises the ppzkSNARK (first generator, then + prover, then verifier) on a synthetic R1CS instance. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include + +#include "common/default_types/r1cs_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp" + +using namespace libsnark; + +template +void test_r1cs_ppzksnark(size_t num_constraints, + size_t input_size) +{ + print_header("(enter) Test R1CS ppzkSNARK"); + + const bool test_serialization = true; + r1cs_example > example = generate_r1cs_example_with_binary_input >(num_constraints, input_size); + const bool bit = run_r1cs_ppzksnark(example, test_serialization); + assert(bit); + + print_header("(leave) Test R1CS ppzkSNARK"); +} + +int main() +{ + default_r1cs_ppzksnark_pp::init_public_params(); + start_profiling(); + + test_r1cs_ppzksnark(1000, 100); +} diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark.cpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark.cpp new file mode 100644 index 0000000..127737f --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark.cpp @@ -0,0 +1,179 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include +#include +#include +#include +#ifndef MINDEPS +#include +#endif + +#include "common/default_types/tinyram_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "reductions/ram_to_r1cs/ram_to_r1cs.hpp" +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_params.hpp" + +#ifndef MINDEPS +namespace po = boost::program_options; + +bool process_demo_command_line(const int argc, const char** argv, + std::string &assembly_fn, + std::string &processed_assembly_fn, + std::string &architecture_params_fn, + std::string &computation_bounds_fn, + std::string &primary_input_fn, + std::string &auxiliary_input_fn) +{ + try + { + po::options_description desc("Usage"); + desc.add_options() + ("help", "print this help message") + ("assembly", po::value(&assembly_fn)->required()) + ("processed_assembly", po::value(&processed_assembly_fn)->required()) + ("architecture_params", po::value(&architecture_params_fn)->required()) + ("computation_bounds", po::value(&computation_bounds_fn)->required()) + ("primary_input", po::value(&primary_input_fn)->required()) + ("auxiliary_input", po::value(&auxiliary_input_fn)->required()); + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + + if (vm.count("help")) + { + std::cout << desc << "\n"; + return false; + } + + po::notify(vm); + } + catch(std::exception& e) + { + std::cerr << "Error: " << e.what() << "\n"; + return false; + } + + return true; +} +#endif + +using namespace libsnark; + +int main(int argc, const char * argv[]) +{ + default_tinyram_ppzksnark_pp::init_public_params(); +#ifdef MINDEPS + std::string assembly_fn = "assembly.s"; + std::string processed_assembly_fn = "processed.txt"; + std::string architecture_params_fn = "architecture_params.txt"; + std::string computation_bounds_fn = "computation_bounds.txt"; + std::string primary_input_fn = "primary_input.txt"; + std::string auxiliary_input_fn = "auxiliary_input.txt"; +#else + std::string assembly_fn; + std::string processed_assembly_fn; + std::string architecture_params_fn; + std::string computation_bounds_fn; + std::string primary_input_fn; + std::string auxiliary_input_fn; + + if (!process_demo_command_line(argc, argv, assembly_fn, processed_assembly_fn, architecture_params_fn, + computation_bounds_fn, primary_input_fn, auxiliary_input_fn)) + { + return 1; + } +#endif + start_profiling(); + + printf("================================================================================\n"); + printf("TinyRAM example loader\n"); + printf("================================================================================\n\n"); + + /* load everything */ + ram_ppzksnark_architecture_params ap; + std::ifstream f_ap(architecture_params_fn); + f_ap >> ap; + + printf("Will run on %zu register machine (word size = %zu)\n", ap.k, ap.w); + + std::ifstream f_rp(computation_bounds_fn); + size_t tinyram_input_size_bound, tinyram_program_size_bound, time_bound; + f_rp >> tinyram_input_size_bound >> tinyram_program_size_bound >> time_bound; + + std::ifstream processed(processed_assembly_fn); + std::ifstream raw(assembly_fn); + tinyram_program program = load_preprocessed_program(ap, processed); + + printf("Program:\n%s\n", std::string((std::istreambuf_iterator(raw)), + std::istreambuf_iterator()).c_str()); + + std::ifstream f_primary_input(primary_input_fn); + std::ifstream f_auxiliary_input(auxiliary_input_fn); + + enter_block("Loading primary input"); + tinyram_input_tape primary_input = load_tape(f_primary_input); + leave_block("Loading primary input"); + + enter_block("Loading auxiliary input"); + tinyram_input_tape auxiliary_input = load_tape(f_auxiliary_input); + leave_block("Loading auxiliary input"); + + printf("\nPress enter to continue.\n"); + std::cin.get(); + + const size_t boot_trace_size_bound = tinyram_program_size_bound + tinyram_input_size_bound; + const ram_boot_trace boot_trace = tinyram_boot_trace_from_program_and_input(ap, boot_trace_size_bound, program, primary_input); + + printf("================================================================================\n"); + printf("TinyRAM arithmetization test for T = %zu time steps\n", time_bound); + printf("================================================================================\n\n"); + + typedef ram_ppzksnark_machine_pp default_ram; + typedef ram_base_field FieldT; + + ram_to_r1cs r(ap, boot_trace_size_bound, time_bound); + r.instance_map(); + + const r1cs_primary_input r1cs_primary_input = ram_to_r1cs::primary_input_map(ap, boot_trace_size_bound, boot_trace); + const r1cs_auxiliary_input r1cs_auxiliary_input = r.auxiliary_input_map(boot_trace, auxiliary_input); + const r1cs_constraint_system constraint_system = r.get_constraint_system(); + + r.print_execution_trace(); + assert(constraint_system.is_satisfied(r1cs_primary_input, r1cs_auxiliary_input)); + + printf("\nPress enter to continue.\n"); + std::cin.get(); + + printf("================================================================================\n"); + printf("TinyRAM ppzkSNARK Key Pair Generator\n"); + printf("================================================================================\n\n"); + const ram_ppzksnark_keypair keypair = ram_ppzksnark_generator(ap, boot_trace_size_bound, time_bound); + + printf("\nPress enter to continue.\n"); + std::cin.get(); + + printf("================================================================================\n"); + printf("TinyRAM ppzkSNARK Prover\n"); + printf("================================================================================\n\n"); + const ram_ppzksnark_proof proof = ram_ppzksnark_prover(keypair.pk, boot_trace, auxiliary_input); + + printf("\nPress enter to continue.\n"); + std::cin.get(); + + printf("================================================================================\n"); + printf("TinyRAM ppzkSNARK Verifier\n"); + printf("================================================================================\n\n"); + bool bit = ram_ppzksnark_verifier(keypair.vk, boot_trace, proof); + + printf("================================================================================\n"); + printf("The verification result is: %s\n", (bit ? "PASS" : "FAIL")); + printf("================================================================================\n"); + print_mem(); + printf("================================================================================\n"); +} diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_generator.cpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_generator.cpp new file mode 100644 index 0000000..c684981 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_generator.cpp @@ -0,0 +1,101 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include +#ifndef MINDEPS +#include +#endif + +#include "common/default_types/ram_ppzksnark_pp.hpp" +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_params.hpp" + +#ifndef MINDEPS +namespace po = boost::program_options; + +bool process_generator_command_line(const int argc, const char** argv, + std::string &architecture_params_fn, + std::string &computation_bounds_fn, + std::string &proving_key_fn, + std::string &verification_key_fn) +{ + try + { + po::options_description desc("Usage"); + desc.add_options() + ("help", "print this help message") + ("architecture_params", po::value(&architecture_params_fn)->required()) + ("computation_bounds", po::value(&computation_bounds_fn)->required()) + ("proving_key", po::value(&proving_key_fn)->required()) + ("verification_key", po::value(&verification_key_fn)->required()); + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + + if (vm.count("help")) + { + std::cout << desc << "\n"; + return false; + } + + po::notify(vm); + } + catch(std::exception& e) + { + std::cerr << "Error: " << e.what() << "\n"; + return false; + } + + return true; +} +#endif + +using namespace libsnark; + +int main(int argc, const char * argv[]) +{ + ram_ppzksnark_snark_pp::init_public_params(); +#ifdef MINDEPS + std::string architecture_params_fn = "architecture_params.txt"; + std::string computation_bounds_fn = "computation_bounds.txt"; + std::string proving_key_fn = "proving_key.txt"; + std::string verification_key_fn = "verification_key.txt"; +#else + std::string architecture_params_fn; + std::string computation_bounds_fn; + std::string proving_key_fn; + std::string verification_key_fn; + + if (!process_generator_command_line(argc, argv, architecture_params_fn, computation_bounds_fn, + proving_key_fn, verification_key_fn)) + { + return 1; + } +#endif + start_profiling(); + + /* load everything */ + ram_ppzksnark_architecture_params ap; + std::ifstream f_ap(architecture_params_fn); + f_ap >> ap; + + std::ifstream f_rp(computation_bounds_fn); + size_t tinyram_input_size_bound, tinyram_program_size_bound, time_bound; + f_rp >> tinyram_input_size_bound >> tinyram_program_size_bound >> time_bound; + + const size_t boot_trace_size_bound = tinyram_program_size_bound + tinyram_input_size_bound; + + const ram_ppzksnark_keypair keypair = ram_ppzksnark_generator(ap, boot_trace_size_bound, time_bound); + + std::ofstream pk(proving_key_fn); + pk << keypair.pk; + pk.close(); + + std::ofstream vk(verification_key_fn); + vk << keypair.vk; + vk.close(); +} diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_prover.cpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_prover.cpp new file mode 100644 index 0000000..9e54755 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_prover.cpp @@ -0,0 +1,106 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include +#ifndef MINDEPS +#include +#endif + +#include "common/default_types/tinyram_ppzksnark_pp.hpp" +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_params.hpp" + +#ifndef MINDEPS +namespace po = boost::program_options; + +bool process_prover_command_line(const int argc, const char** argv, + std::string &processed_assembly_fn, + std::string &proving_key_fn, + std::string &primary_input_fn, + std::string &auxiliary_input_fn, + std::string &proof_fn) +{ + try + { + po::options_description desc("Usage"); + desc.add_options() + ("help", "print this help message") + ("processed_assembly", po::value(&processed_assembly_fn)->required()) + ("proving_key", po::value(&proving_key_fn)->required()) + ("primary_input", po::value(&primary_input_fn)->required()) + ("auxiliary_input", po::value(&auxiliary_input_fn)->required()) + ("proof", po::value(&proof_fn)->required()); + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + + if (vm.count("help")) + { + std::cout << desc << "\n"; + return false; + } + + po::notify(vm); + } + catch(std::exception& e) + { + std::cerr << "Error: " << e.what() << "\n"; + return false; + } + + return true; +} +#endif + +using namespace libsnark; + +int main(int argc, const char * argv[]) +{ + default_tinyram_ppzksnark_pp::init_public_params(); + +#ifdef MINDEPS + std::string processed_assembly_fn = "processed.txt"; + std::string proving_key_fn = "proving_key.txt"; + std::string primary_input_fn = "primary_input.txt"; + std::string auxiliary_input_fn = "auxiliary_input.txt"; + std::string proof_fn = "proof.txt"; +#else + std::string processed_assembly_fn; + std::string proving_key_fn; + std::string primary_input_fn; + std::string auxiliary_input_fn; + std::string proof_fn; + + if (!process_prover_command_line(argc, argv, processed_assembly_fn, + proving_key_fn, primary_input_fn, auxiliary_input_fn, proof_fn)) + { + return 1; + } +#endif + start_profiling(); + + /* load everything */ + ram_ppzksnark_proving_key pk; + std::ifstream pk_file(proving_key_fn); + pk_file >> pk; + pk_file.close(); + + std::ifstream processed(processed_assembly_fn); + tinyram_program program = load_preprocessed_program(pk.ap, processed); + + std::ifstream f_primary_input(primary_input_fn); + std::ifstream f_auxiliary_input(auxiliary_input_fn); + tinyram_input_tape primary_input = load_tape(f_primary_input); + tinyram_input_tape auxiliary_input = load_tape(f_auxiliary_input); + + const ram_boot_trace boot_trace = tinyram_boot_trace_from_program_and_input(pk.ap, pk.primary_input_size_bound, program, primary_input); + const ram_ppzksnark_proof proof = ram_ppzksnark_prover(pk, boot_trace, auxiliary_input); + + std::ofstream proof_file(proof_fn); + proof_file << proof; + proof_file.close(); +} diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_verifier.cpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_verifier.cpp new file mode 100644 index 0000000..33e411c --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_verifier.cpp @@ -0,0 +1,110 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include +#ifndef MINDEPS +#include +#endif + +#include "common/default_types/tinyram_ppzksnark_pp.hpp" +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_params.hpp" + +#ifndef MINDEPS +namespace po = boost::program_options; + +bool process_verifier_command_line(const int argc, const char** argv, + std::string &processed_assembly_fn, + std::string &verification_key_fn, + std::string &primary_input_fn, + std::string &proof_fn, + std::string &verification_result_fn) +{ + try + { + po::options_description desc("Usage"); + desc.add_options() + ("help", "print this help message") + ("processed_assembly", po::value(&processed_assembly_fn)->required()) + ("verification_key", po::value(&verification_key_fn)->required()) + ("primary_input", po::value(&primary_input_fn)->required()) + ("proof", po::value(&proof_fn)->required()) + ("verification_result", po::value(&verification_result_fn)->required()); + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + + if (vm.count("help")) + { + std::cout << desc << "\n"; + return false; + } + + po::notify(vm); + } + catch(std::exception& e) + { + std::cerr << "Error: " << e.what() << "\n"; + return false; + } + + return true; +} +#endif + +using namespace libsnark; + +int main(int argc, const char * argv[]) +{ + default_tinyram_ppzksnark_pp::init_public_params(); + +#ifdef MINDEPS + std::string processed_assembly_fn = "processed.txt"; + std::string verification_key_fn = "verification_key.txt"; + std::string proof_fn = "proof.txt"; + std::string primary_input_fn = "primary_input.txt"; + std::string verification_result_fn = "verification_result.txt"; +#else + std::string processed_assembly_fn; + std::string verification_key_fn; + std::string proof_fn; + std::string primary_input_fn; + std::string verification_result_fn; + + if (!process_verifier_command_line(argc, argv, processed_assembly_fn, verification_key_fn, primary_input_fn, proof_fn, verification_result_fn)) + { + return 1; + } +#endif + start_profiling(); + + ram_ppzksnark_verification_key vk; + std::ifstream vk_file(verification_key_fn); + vk_file >> vk; + vk_file.close(); + + std::ifstream processed(processed_assembly_fn); + tinyram_program program = load_preprocessed_program(vk.ap, processed); + + std::ifstream f_primary_input(primary_input_fn); + tinyram_input_tape primary_input = load_tape(f_primary_input); + + std::ifstream proof_file(proof_fn); + ram_ppzksnark_proof pi; + proof_file >> pi; + proof_file.close(); + + const ram_boot_trace boot_trace = tinyram_boot_trace_from_program_and_input(vk.ap, vk.primary_input_size_bound, program, primary_input); + const bool bit = ram_ppzksnark_verifier(vk, boot_trace, pi); + + printf("================================================================================\n"); + printf("The verification result is: %s\n", (bit ? "PASS" : "FAIL")); + printf("================================================================================\n"); + std::ofstream vr_file(verification_result_fn); + vr_file << bit << "\n"; + vr_file.close(); +} diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/run_ram_ppzksnark.hpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/run_ram_ppzksnark.hpp new file mode 100644 index 0000000..5bb4747 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/run_ram_ppzksnark.hpp @@ -0,0 +1,36 @@ +/** @file + ***************************************************************************** + + Declaration of functionality that runs the RAM ppzkSNARK for + a given RAM example. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_RAM_PPZKSNARK_HPP_ +#define RUN_RAM_PPZKSNARK_HPP_ + +#include "relations/ram_computations/rams/examples/ram_examples.hpp" +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark_params.hpp" + +namespace libsnark { + +/** + * Runs the ppzkSNARK (generator, prover, and verifier) for a given + * RAM example (specified by an architecture, boot trace, auxiliary input, and time bound). + * + * Optionally, also test the serialization routines for keys and proofs. + * (This takes additional time.) + */ +template +bool run_ram_ppzksnark(const ram_example > &example, + const bool test_serialization); + +} // libsnark + +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/examples/run_ram_ppzksnark.tcc" + +#endif // RUN_RAM_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/run_ram_ppzksnark.tcc b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/run_ram_ppzksnark.tcc new file mode 100644 index 0000000..b1cf2b8 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/run_ram_ppzksnark.tcc @@ -0,0 +1,85 @@ +/** @file + ***************************************************************************** + + Implementation of functionality that runs the RAM ppzkSNARK for + a given RAM example. + + See run_ram_ppzksnark.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_RAM_PPZKSNARK_TCC_ +#define RUN_RAM_PPZKSNARK_TCC_ + +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.hpp" + +#include + +#include "common/profiling.hpp" + +namespace libsnark { + +/** + * The code below provides an example of all stages of running a RAM ppzkSNARK. + * + * Of course, in a real-life scenario, we would have three distinct entities, + * mangled into one in the demonstration below. The three entities are as follows. + * (1) The "generator", which runs the ppzkSNARK generator on input a given + * architecture and bounds on the computation. + * (2) The "prover", which runs the ppzkSNARK prover on input the proving key, + * a boot trace, and an auxiliary input. + * (3) The "verifier", which runs the ppzkSNARK verifier on input the verification key, + * a boot trace, and a proof. + */ +template +bool run_ram_ppzksnark(const ram_example > &example, + const bool test_serialization) +{ + enter_block("Call to run_ram_ppzksnark"); + + printf("This run uses an example with the following parameters:\n"); + example.ap.print(); + printf("* Primary input size bound (L): %zu\n", example.boot_trace_size_bound); + printf("* Time bound (T): %zu\n", example.time_bound); + printf("Hence, log2(L+2*T) equals %zu\n", log2(example.boot_trace_size_bound+2*example.time_bound)); + + print_header("RAM ppzkSNARK Generator"); + ram_ppzksnark_keypair keypair = ram_ppzksnark_generator(example.ap, example.boot_trace_size_bound, example.time_bound); + printf("\n"); print_indent(); print_mem("after generator"); + + if (test_serialization) + { + enter_block("Test serialization of keys"); + keypair.pk = reserialize >(keypair.pk); + keypair.vk = reserialize >(keypair.vk); + leave_block("Test serialization of keys"); + } + + print_header("RAM ppzkSNARK Prover"); + ram_ppzksnark_proof proof = ram_ppzksnark_prover(keypair.pk, example.boot_trace, example.auxiliary_input); + printf("\n"); print_indent(); print_mem("after prover"); + + if (test_serialization) + { + enter_block("Test serialization of proof"); + proof = reserialize >(proof); + leave_block("Test serialization of proof"); + } + + print_header("RAM ppzkSNARK Verifier"); + bool ans = ram_ppzksnark_verifier(keypair.vk, example.boot_trace, proof); + printf("\n"); print_indent(); print_mem("after verifier"); + printf("* The verification result is: %s\n", (ans ? "PASS" : "FAIL")); + + leave_block("Call to run_ram_ppzksnark"); + + return ans; +} + +} // libsnark + +#endif // RUN_RAM_PPZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/profiling/profile_ram_ppzksnark.cpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/profiling/profile_ram_ppzksnark.cpp new file mode 100644 index 0000000..856f9ab --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/profiling/profile_ram_ppzksnark.cpp @@ -0,0 +1,59 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include +#include +#include +#include +#include + +#include "common/default_types/ram_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "relations/ram_computations/rams/examples/ram_examples.hpp" +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/examples/run_ram_ppzksnark.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_params.hpp" + +using namespace libsnark; + +int main(int argc, const char * argv[]) +{ + ram_ppzksnark_snark_pp::init_public_params(); + start_profiling(); + + if (argc == 2 && strcmp(argv[1], "-v") == 0) + { + print_compilation_info(); + return 0; + } + + if (argc != 6) + { + printf("usage: %s word_size reg_count program_size input_size time_bound\n", argv[0]); + return 1; + } + + const size_t w = atoi(argv[1]), + k = atoi(argv[2]), + program_size = atoi(argv[3]), + input_size = atoi(argv[4]), + time_bound = atoi(argv[5]); + + typedef ram_ppzksnark_machine_pp machine_ppT; + + const ram_ppzksnark_architecture_params ap(w, k); + + enter_block("Generate RAM example"); + const size_t boot_trace_size_bound = program_size + input_size; + const bool satisfiable = true; + ram_example example = gen_ram_example_complex(ap, boot_trace_size_bound, time_bound, satisfiable); + enter_block("Generate RAM example"); + + print_header("(enter) Profile RAM ppzkSNARK"); + const bool test_serialization = true; + run_ram_ppzksnark(example, test_serialization); + print_header("(leave) Profile RAM ppzkSNARK"); +} diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.hpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.hpp new file mode 100644 index 0000000..7950277 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.hpp @@ -0,0 +1,227 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a ppzkSNARK for RAM. + + This includes: + - the class for a proving key; + - the class for a verification key; + - the class for a key pair (proving key & verification key); + - the class for a proof; + - the generator algorithm; + - the prover algorithm; + - the verifier algorithm. + + The implementation follows, extends, and optimizes the approach described + in \[BCTV14] (itself building on \[BCGTV13]). In particular, the ppzkSNARK + for RAM is constructed from a ppzkSNARK for R1CS. + + + Acronyms: + + "R1CS" = "Rank-1 Constraint Systems" + "RAM" = "Random-Access Machines" + "ppzkSNARK" = "Pre-Processing Zero-Knowledge Succinct Non-interactive ARgument of Knowledge" + + References: + + \[BCGTV13]: + "SNARKs for C: verifying program executions succinctly and in zero knowledge", + Eli Ben-Sasson, Alessandro Chiesa, Daniel Genkin, Eran Tromer, Madars Virza, + CRYPTO 2014, + + + \[BCTV14]: + "Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture", + Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, + USENIX Security 2014, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_PPZKSNARK_HPP_ +#define RAM_PPZKSNARK_HPP_ + +#include + +#include "reductions/ram_to_r1cs/ram_to_r1cs.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark_params.hpp" + +namespace libsnark { + +/******************************** Proving key ********************************/ + +template +class ram_ppzksnark_proving_key; + +template +std::ostream& operator<<(std::ostream &out, const ram_ppzksnark_proving_key &pk); + +template +std::istream& operator>>(std::istream &in, ram_ppzksnark_proving_key &pk); + +/** + * A proving key for the RAM ppzkSNARK. + */ +template +class ram_ppzksnark_proving_key { +public: + typedef ram_ppzksnark_snark_pp snark_ppT; + + r1cs_ppzksnark_proving_key r1cs_pk; + ram_ppzksnark_architecture_params ap; + size_t primary_input_size_bound; + size_t time_bound; + + ram_ppzksnark_proving_key() {} + ram_ppzksnark_proving_key(const ram_ppzksnark_proving_key &other) = default; + ram_ppzksnark_proving_key(ram_ppzksnark_proving_key &&other) = default; + ram_ppzksnark_proving_key(r1cs_ppzksnark_proving_key &&r1cs_pk, + const ram_ppzksnark_architecture_params &ap, + const size_t primary_input_size_bound, + const size_t time_bound) : + r1cs_pk(std::move(r1cs_pk)), + ap(ap), + primary_input_size_bound(primary_input_size_bound), + time_bound(time_bound) + {} + + ram_ppzksnark_proving_key& operator=(const ram_ppzksnark_proving_key &other) = default; + + bool operator==(const ram_ppzksnark_proving_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const ram_ppzksnark_proving_key &pk); + friend std::istream& operator>> (std::istream &in, ram_ppzksnark_proving_key &pk); +}; + + +/******************************* Verification key ****************************/ + +template +class ram_ppzksnark_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const ram_ppzksnark_verification_key &vk); + +template +std::istream& operator>>(std::istream &in, ram_ppzksnark_verification_key &vk); + +/** + * A verification key for the RAM ppzkSNARK. + */ +template +class ram_ppzksnark_verification_key { +public: + typedef ram_ppzksnark_snark_pp snark_ppT; + + r1cs_ppzksnark_verification_key r1cs_vk; + ram_ppzksnark_architecture_params ap; + size_t primary_input_size_bound; + size_t time_bound; + + std::set bound_primary_input_locations; + + ram_ppzksnark_verification_key() = default; + ram_ppzksnark_verification_key(const ram_ppzksnark_verification_key &other) = default; + ram_ppzksnark_verification_key(ram_ppzksnark_verification_key &&other) = default; + ram_ppzksnark_verification_key(const r1cs_ppzksnark_verification_key &r1cs_vk, + const ram_ppzksnark_architecture_params &ap, + const size_t primary_input_size_bound, + const size_t time_bound) : + r1cs_vk(r1cs_vk), + ap(ap), + primary_input_size_bound(primary_input_size_bound), + time_bound(time_bound) + {} + + ram_ppzksnark_verification_key& operator=(const ram_ppzksnark_verification_key &other) = default; + + ram_ppzksnark_verification_key bind_primary_input(const ram_ppzksnark_primary_input &primary_input) const; + + bool operator==(const ram_ppzksnark_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const ram_ppzksnark_verification_key &vk); + friend std::istream& operator>> (std::istream &in, ram_ppzksnark_verification_key &vk); +}; + + +/********************************** Key pair *********************************/ + +/** + * A key pair for the RAM ppzkSNARK, which consists of a proving key and a verification key. + */ +template +struct ram_ppzksnark_keypair { +public: + ram_ppzksnark_proving_key pk; + ram_ppzksnark_verification_key vk; + + ram_ppzksnark_keypair() = default; + ram_ppzksnark_keypair(ram_ppzksnark_keypair &&other) = default; + ram_ppzksnark_keypair(const ram_ppzksnark_keypair &other) = default; + ram_ppzksnark_keypair(ram_ppzksnark_proving_key &&pk, + ram_ppzksnark_verification_key &&vk) : + pk(std::move(pk)), + vk(std::move(vk)) + {} +}; + + +/*********************************** Proof ***********************************/ + +/** + * A proof for the RAM ppzkSNARK. + */ +template +using ram_ppzksnark_proof = r1cs_ppzksnark_proof >; + + +/***************************** Main algorithms *******************************/ + +/** + * A generator algorithm for the RAM ppzkSNARK. + * + * Given a choice of architecture parameters and computation bounds, this algorithm + * produces proving and verification keys for all computations that respect these choices. + */ +template +ram_ppzksnark_keypair ram_ppzksnark_generator(const ram_ppzksnark_architecture_params &ap, + const size_t primary_input_size_bound, + const size_t time_bound); + +/** + * A prover algorithm for the RAM ppzkSNARK. + * + * Given a proving key, primary input X, and auxiliary input Y, this algorithm + * produces a proof (of knowledge) that attests to the following statement: + * ``there exists Y such that X(Y) accepts''. + * + * Above, it has to be the case that the computation respects the bounds: + * - the size of X is at most primary_input_size_bound, and + * - the time to compute X(Y) is at most time_bound. + */ +template +ram_ppzksnark_proof ram_ppzksnark_prover(const ram_ppzksnark_proving_key &pk, + const ram_ppzksnark_primary_input &primary_input, + const ram_ppzksnark_auxiliary_input &auxiliary_input); + +/** + * A verifier algorithm for the RAM ppzkSNARK. + * + * This algorithm is universal in the sense that the verification key + * supports proof verification for any choice of primary input + * provided that the computation respects the bounds. + */ +template +bool ram_ppzksnark_verifier(const ram_ppzksnark_verification_key &vk, + const ram_ppzksnark_primary_input &primary_input, + const ram_ppzksnark_proof &proof); + +} // libsnark + +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.tcc" + +#endif // RAM_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.tcc b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.tcc new file mode 100644 index 0000000..e46a805 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.tcc @@ -0,0 +1,178 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a ppzkSNARK for RAM. + + See ram_ppzksnark.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_PPZKSNARK_TCC_ +#define RAM_PPZKSNARK_TCC_ + +#include "common/profiling.hpp" +#include "reductions/ram_to_r1cs/ram_to_r1cs.hpp" + +namespace libsnark { + +template +bool ram_ppzksnark_proving_key::operator==(const ram_ppzksnark_proving_key &other) const +{ + return (this->r1cs_pk == other.r1cs_pk && + this->ap == other.ap && + this->primary_input_size_bound == other.primary_input_size_bound && + this->time_bound == other.time_bound); +} + +template +std::ostream& operator<<(std::ostream &out, const ram_ppzksnark_proving_key &pk) +{ + out << pk.r1cs_pk; + out << pk.ap; + out << pk.primary_input_size_bound << "\n"; + out << pk.time_bound << "\n"; + + return out; +} + +template +std::istream& operator>>(std::istream &in, ram_ppzksnark_proving_key &pk) +{ + in >> pk.r1cs_pk; + in >> pk.ap; + in >> pk.primary_input_size_bound; + consume_newline(in); + in >> pk.time_bound; + consume_newline(in); + + return in; +} + +template +ram_ppzksnark_verification_key ram_ppzksnark_verification_key::bind_primary_input(const ram_ppzksnark_primary_input &primary_input) const +{ + typedef ram_ppzksnark_machine_pp ram_ppT; + typedef ram_base_field FieldT; + + enter_block("Call to ram_ppzksnark_verification_key::bind_primary_input"); + ram_ppzksnark_verification_key result(*this); + + const size_t packed_input_element_size = ram_universal_gadget::packed_input_element_size(ap); + + for (auto it : primary_input.get_all_trace_entries()) + { + const size_t input_pos = it.first; + const address_and_value av = it.second; + + assert(input_pos < primary_input_size_bound); + assert(result.bound_primary_input_locations.find(input_pos) == result.bound_primary_input_locations.end()); + + const std::vector packed_input_element = ram_to_r1cs::pack_primary_input_address_and_value(ap, av); + result.r1cs_vk.encoded_IC_query = result.r1cs_vk.encoded_IC_query.template accumulate_chunk(packed_input_element.begin(), packed_input_element.end(), packed_input_element_size * (primary_input_size_bound - 1 - input_pos)); + + result.bound_primary_input_locations.insert(input_pos); + } + + leave_block("Call to ram_ppzksnark_verification_key::bind_primary_input"); + return result; +} + +template +bool ram_ppzksnark_verification_key::operator==(const ram_ppzksnark_verification_key &other) const +{ + return (this->r1cs_vk == other.r1cs_vk && + this->ap == other.ap && + this->primary_input_size_bound == other.primary_input_size_bound && + this->time_bound == other.time_bound); +} + +template +std::ostream& operator<<(std::ostream &out, const ram_ppzksnark_verification_key &vk) +{ + out << vk.r1cs_vk; + out << vk.ap; + out << vk.primary_input_size_bound << "\n"; + out << vk.time_bound << "\n"; + + return out; +} + +template +std::istream& operator>>(std::istream &in, ram_ppzksnark_verification_key &vk) +{ + in >> vk.r1cs_vk; + in >> vk.ap; + in >> vk.primary_input_size_bound; + consume_newline(in); + in >> vk.time_bound; + consume_newline(in); + + return in; +} + +template +ram_ppzksnark_keypair ram_ppzksnark_generator(const ram_ppzksnark_architecture_params &ap, + const size_t primary_input_size_bound, + const size_t time_bound) +{ + typedef ram_ppzksnark_machine_pp ram_ppT; + typedef ram_ppzksnark_snark_pp snark_ppT; + + enter_block("Call to ram_ppzksnark_generator"); + ram_to_r1cs universal_r1cs(ap, primary_input_size_bound, time_bound); + universal_r1cs.instance_map(); + r1cs_ppzksnark_keypair ppzksnark_keypair = r1cs_ppzksnark_generator(universal_r1cs.get_constraint_system()); + leave_block("Call to ram_ppzksnark_generator"); + + ram_ppzksnark_proving_key pk = ram_ppzksnark_proving_key(std::move(ppzksnark_keypair.pk), ap, primary_input_size_bound, time_bound); + ram_ppzksnark_verification_key vk = ram_ppzksnark_verification_key(std::move(ppzksnark_keypair.vk), ap, primary_input_size_bound, time_bound); + + return ram_ppzksnark_keypair(std::move(pk), std::move(vk)); +} + +template +ram_ppzksnark_proof ram_ppzksnark_prover(const ram_ppzksnark_proving_key &pk, + const ram_ppzksnark_primary_input &primary_input, + const ram_ppzksnark_auxiliary_input &auxiliary_input) +{ + typedef ram_ppzksnark_machine_pp ram_ppT; + typedef ram_ppzksnark_snark_pp snark_ppT; + typedef Fr FieldT; + + enter_block("Call to ram_ppzksnark_prover"); + ram_to_r1cs universal_r1cs(pk.ap, pk.primary_input_size_bound, pk.time_bound); + const r1cs_primary_input r1cs_primary_input = ram_to_r1cs::primary_input_map(pk.ap, pk.primary_input_size_bound, primary_input); + + const r1cs_auxiliary_input r1cs_auxiliary_input = universal_r1cs.auxiliary_input_map(primary_input, auxiliary_input); +#if DEBUG + universal_r1cs.print_execution_trace(); + universal_r1cs.print_memory_trace(); +#endif + const r1cs_ppzksnark_proof proof = r1cs_ppzksnark_prover(pk.r1cs_pk, r1cs_primary_input, r1cs_auxiliary_input); + leave_block("Call to ram_ppzksnark_prover"); + + return proof; +} + +template +bool ram_ppzksnark_verifier(const ram_ppzksnark_verification_key &vk, + const ram_ppzksnark_primary_input &primary_input, + const ram_ppzksnark_proof &proof) +{ + typedef ram_ppzksnark_snark_pp snark_ppT; + + enter_block("Call to ram_ppzksnark_verifier"); + const ram_ppzksnark_verification_key input_specific_vk = vk.bind_primary_input(primary_input); + const bool ans = r1cs_ppzksnark_verifier_weak_IC(input_specific_vk.r1cs_vk, r1cs_primary_input >(), proof); + leave_block("Call to ram_ppzksnark_verifier"); + + return ans; +} + +} // libsnark + +#endif // RAM_PPZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark_params.hpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark_params.hpp new file mode 100644 index 0000000..5a1d04e --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark_params.hpp @@ -0,0 +1,72 @@ +/** @file + ***************************************************************************** + + Declaration of public-parameter selector for the RAM ppzkSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_PPZKSNARK_PARAMS_HPP_ +#define RAM_PPZKSNARK_PARAMS_HPP_ + +namespace libsnark { + +/** + * The interfaces of the RAM ppzkSNARK are templatized via the parameter + * ram_ppzksnark_ppT. When used, the interfaces must be invoked with + * a particular parameter choice; let 'my_ram_ppzksnark_pp' denote this choice. + * + * my_ram_ppzksnark_pp needs to contain typedefs for the typenames + * - snark_pp, and + * - machine_pp. + * as well as a method with the following signature: + * - static void init_public_params(); + * + * For example, if you want to use the types my_snark_pp and my_machine_pp, + * then you could declare my_ram_ppzksnark_pp as follows: + * + * class my_ram_ppzksnark_pp { + * public: + * typedef my_snark_pp snark_pp; + * typedef my_machine_pp machine_pp; + * static void init_public params() + * { + * snark_pp::init_public_params(); // and additional initialization if needed + * } + * }; + * + * Having done the above, my_ram_ppzksnark_pp can be used as a template parameter. + * + * Look for for default_tinyram_ppzksnark_pp in the file + * + * common/default_types/ram_ppzksnark_pp.hpp + * + * for an example of the above steps for the case of "RAM=TinyRAM". + * + */ + +/** + * Below are various template aliases (used for convenience). + */ + +template +using ram_ppzksnark_snark_pp = typename ram_ppzksnark_ppT::snark_pp; + +template +using ram_ppzksnark_machine_pp = typename ram_ppzksnark_ppT::machine_pp; + +template +using ram_ppzksnark_architecture_params = ram_architecture_params >; + +template +using ram_ppzksnark_primary_input = ram_boot_trace >; + +template +using ram_ppzksnark_auxiliary_input = ram_input_tape >; + +} // libsnark + +#endif // RAM_PPZKSNARK_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/tests/test_ram_ppzksnark.cpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/tests/test_ram_ppzksnark.cpp new file mode 100644 index 0000000..93211d4 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/ram_ppzksnark/tests/test_ram_ppzksnark.cpp @@ -0,0 +1,57 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include +#include +#include +#include + +#include "common/default_types/ram_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "relations/ram_computations/rams/examples/ram_examples.hpp" +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/examples/run_ram_ppzksnark.hpp" + +using namespace libsnark; + +template +void test_ram_ppzksnark(const size_t w, + const size_t k, + const size_t program_size, + const size_t input_size, + const size_t time_bound) +{ + print_header("(enter) Test RAM ppzkSNARK"); + + typedef ram_ppzksnark_machine_pp machine_ppT; + const size_t boot_trace_size_bound = program_size + input_size; + const bool satisfiable = true; + + const ram_ppzksnark_architecture_params ap(w, k); + const ram_example example = gen_ram_example_complex(ap, boot_trace_size_bound, time_bound, satisfiable); + + const bool test_serialization = true; + const bool bit = run_ram_ppzksnark(example, test_serialization); + assert(bit); + + print_header("(leave) Test RAM ppzkSNARK"); +} + +int main() +{ + ram_ppzksnark_snark_pp::init_public_params(); + start_profiling(); + + const size_t program_size = 100; + const size_t input_size = 2; + const size_t time_bound = 20; + + // 16-bit TinyRAM with 16 registers + test_ram_ppzksnark(16, 16, program_size, input_size, time_bound); + + // 32-bit TinyRAM with 16 registers + test_ram_ppzksnark(32, 16, program_size, input_size, time_bound); +} diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/tbcs_ppzksnark/examples/run_tbcs_ppzksnark.hpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/tbcs_ppzksnark/examples/run_tbcs_ppzksnark.hpp new file mode 100644 index 0000000..ff4b062 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/tbcs_ppzksnark/examples/run_tbcs_ppzksnark.hpp @@ -0,0 +1,35 @@ +/** @file + ***************************************************************************** + + Declaration of functionality that runs the TBCS ppzkSNARK for + a given TBCS example. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_TBCS_PPZKSNARK_HPP_ +#define RUN_TBCS_PPZKSNARK_HPP_ + +#include "relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.hpp" + +namespace libsnark { + +/** + * Runs the ppzkSNARK (generator, prover, and verifier) for a given + * TBCS example (specified by a circuit, primary input, and auxiliary input). + * + * Optionally, also test the serialization routines for keys and proofs. + * (This takes additional time.) + */ +template +bool run_tbcs_ppzksnark(const tbcs_example &example, + const bool test_serialization); + +} // libsnark + +#include "zk_proof_systems/ppzksnark/tbcs_ppzksnark/examples/run_tbcs_ppzksnark.tcc" + +#endif // RUN_TBCS_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/tbcs_ppzksnark/examples/run_tbcs_ppzksnark.tcc b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/tbcs_ppzksnark/examples/run_tbcs_ppzksnark.tcc new file mode 100644 index 0000000..c67e40b --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/tbcs_ppzksnark/examples/run_tbcs_ppzksnark.tcc @@ -0,0 +1,87 @@ +/** @file + ***************************************************************************** + + Implementation of functionality that runs the TBCS ppzkSNARK for + a given TBCS example. + + See run_tbcs_ppzksnark.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_TBCS_PPZKSNARK_TCC_ +#define RUN_TBCS_PPZKSNARK_TCC_ + +#include "zk_proof_systems/ppzksnark/tbcs_ppzksnark/tbcs_ppzksnark.hpp" + +#include + +#include "common/profiling.hpp" + +namespace libsnark { + +/** + * The code below provides an example of all stages of running a TBCS ppzkSNARK. + * + * Of course, in a real-life scenario, we would have three distinct entities, + * mangled into one in the demonstration below. The three entities are as follows. + * (1) The "generator", which runs the ppzkSNARK generator on input a given + * circuit C to create a proving and a verification key for C. + * (2) The "prover", which runs the ppzkSNARK prover on input the proving key, + * a primary input for C, and an auxiliary input for C. + * (3) The "verifier", which runs the ppzkSNARK verifier on input the verification key, + * a primary input for C, and a proof. + */ +template +bool run_tbcs_ppzksnark(const tbcs_example &example, + const bool test_serialization) +{ + enter_block("Call to run_tbcs_ppzksnark"); + + print_header("TBCS ppzkSNARK Generator"); + tbcs_ppzksnark_keypair keypair = tbcs_ppzksnark_generator(example.circuit); + printf("\n"); print_indent(); print_mem("after generator"); + + print_header("Preprocess verification key"); + tbcs_ppzksnark_processed_verification_key pvk = tbcs_ppzksnark_verifier_process_vk(keypair.vk); + + if (test_serialization) + { + enter_block("Test serialization of keys"); + keypair.pk = reserialize >(keypair.pk); + keypair.vk = reserialize >(keypair.vk); + pvk = reserialize >(pvk); + leave_block("Test serialization of keys"); + } + + print_header("TBCS ppzkSNARK Prover"); + tbcs_ppzksnark_proof proof = tbcs_ppzksnark_prover(keypair.pk, example.primary_input, example.auxiliary_input); + printf("\n"); print_indent(); print_mem("after prover"); + + if (test_serialization) + { + enter_block("Test serialization of proof"); + proof = reserialize >(proof); + leave_block("Test serialization of proof"); + } + + print_header("TBCS ppzkSNARK Verifier"); + bool ans = tbcs_ppzksnark_verifier_strong_IC(keypair.vk, example.primary_input, proof); + printf("\n"); print_indent(); print_mem("after verifier"); + printf("* The verification result is: %s\n", (ans ? "PASS" : "FAIL")); + + print_header("TBCS ppzkSNARK Online Verifier"); + bool ans2 = tbcs_ppzksnark_online_verifier_strong_IC(pvk, example.primary_input, proof); + assert(ans == ans2); + + leave_block("Call to run_tbcs_ppzksnark"); + + return ans; +} + +} // libsnark + +#endif // RUN_TBCS_PPZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/tbcs_ppzksnark/profiling/profile_tbcs_ppzksnark.cpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/tbcs_ppzksnark/profiling/profile_tbcs_ppzksnark.cpp new file mode 100644 index 0000000..a27cabf --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/tbcs_ppzksnark/profiling/profile_tbcs_ppzksnark.cpp @@ -0,0 +1,58 @@ +/** @file + ***************************************************************************** + Profiling program that exercises the ppzkSNARK (first generator, then prover, + then verifier) on a synthetic TBCS instance. + + The command + + $ src/tbcs_ppzksnark/examples/profile_tbcs_ppzksnark 1000 10 + + exercises the ppzkSNARK (first generator, then prover, then verifier) on an TBCS instance with 1000 gates and an input consisting of 10 bits. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include + +#include "common/default_types/tbcs_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.hpp" +#include "zk_proof_systems/ppzksnark/tbcs_ppzksnark/examples/run_tbcs_ppzksnark.hpp" + +using namespace libsnark; + +int main(int argc, const char * argv[]) +{ + default_tbcs_ppzksnark_pp::init_public_params(); + start_profiling(); + + if (argc == 2 && strcmp(argv[1], "-v") == 0) + { + print_compilation_info(); + return 0; + } + + if (argc != 3) + { + printf("usage: %s num_gates primary_input_size\n", argv[0]); + return 1; + } + const int num_gates = atoi(argv[1]); + int primary_input_size = atoi(argv[2]); + + const size_t auxiliary_input_size = 0; + const size_t num_outputs = num_gates / 2; + + enter_block("Generate TBCS example"); + tbcs_example example = generate_tbcs_example(primary_input_size, auxiliary_input_size, num_gates, num_outputs); + leave_block("Generate TBCS example"); + + print_header("(enter) Profile TBCS ppzkSNARK"); + const bool test_serialization = true; + run_tbcs_ppzksnark(example, test_serialization); + print_header("(leave) Profile TBCS ppzkSNARK"); +} diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tbcs_ppzksnark.hpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tbcs_ppzksnark.hpp new file mode 100644 index 0000000..656a427 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tbcs_ppzksnark.hpp @@ -0,0 +1,260 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a ppzkSNARK for TBCS. + + This includes: + - class for proving key + - class for verification key + - class for processed verification key + - class for key pair (proving key & verification key) + - class for proof + - generator algorithm + - prover algorithm + - verifier algorithm (with strong or weak input consistency) + - online verifier algorithm (with strong or weak input consistency) + + The implementation is a straightforward combination of: + (1) a TBCS-to-USCS reduction, and + (2) a ppzkSNARK for USCS. + + + Acronyms: + + - TBCS = "Two-input Boolean Circuit Satisfiability" + - USCS = "Unitary-Square Constraint System" + - ppzkSNARK = "PreProcessing Zero-Knowledge Succinct Non-interactive ARgument of Knowledge" + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TBCS_PPZKSNARK_HPP_ +#define TBCS_PPZKSNARK_HPP_ + +#include "relations/circuit_satisfaction_problems/tbcs/tbcs.hpp" +#include "zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark.hpp" +#include "zk_proof_systems/ppzksnark/tbcs_ppzksnark/tbcs_ppzksnark_params.hpp" + +namespace libsnark { + +/******************************** Proving key ********************************/ + +template +class tbcs_ppzksnark_proving_key; + +template +std::ostream& operator<<(std::ostream &out, const tbcs_ppzksnark_proving_key &pk); + +template +std::istream& operator>>(std::istream &in, tbcs_ppzksnark_proving_key &pk); + +/** + * A proving key for the TBCS ppzkSNARK. + */ +template +class tbcs_ppzksnark_proving_key { +public: + typedef Fr FieldT; + + tbcs_ppzksnark_circuit circuit; + uscs_ppzksnark_proving_key uscs_pk; + + tbcs_ppzksnark_proving_key() {}; + tbcs_ppzksnark_proving_key(const tbcs_ppzksnark_proving_key &other) = default; + tbcs_ppzksnark_proving_key(tbcs_ppzksnark_proving_key &&other) = default; + tbcs_ppzksnark_proving_key(const tbcs_ppzksnark_circuit &circuit, + const uscs_ppzksnark_proving_key &uscs_pk) : + circuit(circuit), uscs_pk(uscs_pk) + {} + tbcs_ppzksnark_proving_key(tbcs_ppzksnark_circuit &&circuit, + uscs_ppzksnark_proving_key &&uscs_pk) : + circuit(std::move(circuit)), uscs_pk(std::move(uscs_pk)) + {} + + tbcs_ppzksnark_proving_key& operator=(const tbcs_ppzksnark_proving_key &other) = default; + + size_t G1_size() const + { + return uscs_pk.G1_size(); + } + + size_t G2_size() const + { + return uscs_pk.G2_size(); + } + + size_t G1_sparse_size() const + { + return uscs_pk.G1_sparse_size(); + } + + size_t G2_sparse_size() const + { + return uscs_pk.G2_sparse_size(); + } + + size_t size_in_bits() const + { + return uscs_pk.size_in_bits(); + } + + void print_size() const + { + uscs_pk.print_size(); + } + + bool operator==(const tbcs_ppzksnark_proving_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const tbcs_ppzksnark_proving_key &pk); + friend std::istream& operator>> (std::istream &in, tbcs_ppzksnark_proving_key &pk); +}; + + +/******************************* Verification key ****************************/ + +/** + * A verification key for the TBCS ppzkSNARK. + */ +template +using tbcs_ppzksnark_verification_key = uscs_ppzksnark_verification_key; + + +/************************ Processed verification key *************************/ + +/** + * A processed verification key for the TBCS ppzkSNARK. + * + * Compared to a (non-processed) verification key, a processed verification key + * contains a small constant amount of additional pre-computed information that + * enables a faster verification time. + */ +template +using tbcs_ppzksnark_processed_verification_key = uscs_ppzksnark_processed_verification_key; + + +/********************************** Key pair *********************************/ + +/** + * A key pair for the TBCS ppzkSNARK, which consists of a proving key and a verification key. + */ +template +class tbcs_ppzksnark_keypair { +public: + tbcs_ppzksnark_proving_key pk; + tbcs_ppzksnark_verification_key vk; + + tbcs_ppzksnark_keypair() {}; + tbcs_ppzksnark_keypair(tbcs_ppzksnark_keypair &&other) = default; + tbcs_ppzksnark_keypair(const tbcs_ppzksnark_proving_key &pk, + const tbcs_ppzksnark_verification_key &vk) : + pk(pk), + vk(vk) + {} + + tbcs_ppzksnark_keypair(tbcs_ppzksnark_proving_key &&pk, + tbcs_ppzksnark_verification_key &&vk) : + pk(std::move(pk)), + vk(std::move(vk)) + {} +}; + + +/*********************************** Proof ***********************************/ + +/** + * A proof for the TBCS ppzkSNARK. + */ +template +using tbcs_ppzksnark_proof = uscs_ppzksnark_proof; + + +/***************************** Main algorithms *******************************/ + +/** + * A generator algorithm for the TBCS ppzkSNARK. + * + * Given a TBCS circuit C, this algorithm produces proving and verification keys for C. + */ +template +tbcs_ppzksnark_keypair tbcs_ppzksnark_generator(const tbcs_ppzksnark_circuit &circuit); + +/** + * A prover algorithm for the TBCS ppzkSNARK. + * + * Given a TBCS primary input X and a TBCS auxiliary input Y, this algorithm + * produces a proof (of knowledge) that attests to the following statement: + * ``there exists Y such that C(X,Y)=0''. + * Above, C is the TBCS circuit that was given as input to the generator algorithm. + */ +template +tbcs_ppzksnark_proof tbcs_ppzksnark_prover(const tbcs_ppzksnark_proving_key &pk, + const tbcs_ppzksnark_primary_input &primary_input, + const tbcs_ppzksnark_auxiliary_input &auxiliary_input); + +/* + Below are four variants of verifier algorithm for the TBCS ppzkSNARK. + + These are the four cases that arise from the following two choices: + + (1) The verifier accepts a (non-processed) verification key or, instead, a processed verification key. + In the latter case, we call the algorithm an "online verifier". + + (2) The verifier checks for "weak" input consistency or, instead, "strong" input consistency. + Strong input consistency requires that |primary_input| = C.num_inputs, whereas + weak input consistency requires that |primary_input| <= C.num_inputs (and + the primary input is implicitly padded with zeros up to length C.num_inputs). + */ + +/** + * A verifier algorithm for the TBCS ppzkSNARK that: + * (1) accepts a non-processed verification key, and + * (2) has weak input consistency. + */ +template +bool tbcs_ppzksnark_verifier_weak_IC(const tbcs_ppzksnark_verification_key &vk, + const tbcs_ppzksnark_primary_input &primary_input, + const tbcs_ppzksnark_proof &proof); + +/** + * A verifier algorithm for the TBCS ppzkSNARK that: + * (1) accepts a non-processed verification key, and + * (2) has strong input consistency. + */ +template +bool tbcs_ppzksnark_verifier_strong_IC(const tbcs_ppzksnark_verification_key &vk, + const tbcs_ppzksnark_primary_input &primary_input, + const tbcs_ppzksnark_proof &proof); + +/** + * Convert a (non-processed) verification key into a processed verification key. + */ +template +tbcs_ppzksnark_processed_verification_key tbcs_ppzksnark_verifier_process_vk(const tbcs_ppzksnark_verification_key &vk); + +/** + * A verifier algorithm for the TBCS ppzkSNARK that: + * (1) accepts a processed verification key, and + * (2) has weak input consistency. + */ +template +bool tbcs_ppzksnark_online_verifier_weak_IC(const tbcs_ppzksnark_processed_verification_key &pvk, + const tbcs_ppzksnark_primary_input &primary_input, + const tbcs_ppzksnark_proof &proof); + +/** + * A verifier algorithm for the TBCS ppzkSNARK that: + * (1) accepts a processed verification key, and + * (2) has strong input consistency. + */ +template +bool tbcs_ppzksnark_online_verifier_strong_IC(const tbcs_ppzksnark_processed_verification_key &pvk, + const tbcs_ppzksnark_primary_input &primary_input, + const tbcs_ppzksnark_proof &proof); + +} // libsnark + +#include "zk_proof_systems/ppzksnark/tbcs_ppzksnark/tbcs_ppzksnark.tcc" + +#endif // TBCS_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tbcs_ppzksnark.tcc b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tbcs_ppzksnark.tcc new file mode 100644 index 0000000..bb8030f --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tbcs_ppzksnark.tcc @@ -0,0 +1,151 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a ppzkSNARK for TBCS. + + See tbcs_ppzksnark.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TBCS_PPZKSNARK_TCC_ +#define TBCS_PPZKSNARK_TCC_ + +#include "reductions/tbcs_to_uscs/tbcs_to_uscs.hpp" + +namespace libsnark { + + +template +bool tbcs_ppzksnark_proving_key::operator==(const tbcs_ppzksnark_proving_key &other) const +{ + return (this->circuit == other.circuit && + this->uscs_pk == other.uscs_pk); +} + +template +std::ostream& operator<<(std::ostream &out, const tbcs_ppzksnark_proving_key &pk) +{ + out << pk.circuit << OUTPUT_NEWLINE; + out << pk.uscs_pk << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, tbcs_ppzksnark_proving_key &pk) +{ + in >> pk.circuit; + consume_OUTPUT_NEWLINE(in); + in >> pk.uscs_pk; + consume_OUTPUT_NEWLINE(in); + + return in; +} + + +template +tbcs_ppzksnark_keypair tbcs_ppzksnark_generator(const tbcs_ppzksnark_circuit &circuit) +{ + typedef Fr FieldT; + + enter_block("Call to tbcs_ppzksnark_generator"); + const uscs_constraint_system uscs_cs = tbcs_to_uscs_instance_map(circuit); + const uscs_ppzksnark_keypair uscs_keypair = uscs_ppzksnark_generator(uscs_cs); + leave_block("Call to tbcs_ppzksnark_generator"); + + return tbcs_ppzksnark_keypair(tbcs_ppzksnark_proving_key(circuit, uscs_keypair.pk), + uscs_keypair.vk); +} + +template +tbcs_ppzksnark_proof tbcs_ppzksnark_prover(const tbcs_ppzksnark_proving_key &pk, + const tbcs_ppzksnark_primary_input &primary_input, + const tbcs_ppzksnark_auxiliary_input &auxiliary_input) +{ + typedef Fr FieldT; + + enter_block("Call to tbcs_ppzksnark_prover"); + const uscs_variable_assignment uscs_va = tbcs_to_uscs_witness_map(pk.circuit, primary_input, auxiliary_input); + const uscs_primary_input uscs_pi = convert_bit_vector_to_field_element_vector(primary_input); + const uscs_auxiliary_input uscs_ai(uscs_va.begin() + primary_input.size(), uscs_va.end()); // TODO: faster to just change bacs_to_r1cs_witness_map into two :( + const uscs_ppzksnark_proof uscs_proof = uscs_ppzksnark_prover(pk.uscs_pk, uscs_pi, uscs_ai); + leave_block("Call to tbcs_ppzksnark_prover"); + + return uscs_proof; +} + +template +tbcs_ppzksnark_processed_verification_key tbcs_ppzksnark_verifier_process_vk(const tbcs_ppzksnark_verification_key &vk) +{ + enter_block("Call to tbcs_ppzksnark_verifier_process_vk"); + const tbcs_ppzksnark_processed_verification_key pvk = uscs_ppzksnark_verifier_process_vk(vk); + leave_block("Call to tbcs_ppzksnark_verifier_process_vk"); + + return pvk; +} + +template +bool tbcs_ppzksnark_verifier_weak_IC(const tbcs_ppzksnark_verification_key &vk, + const tbcs_ppzksnark_primary_input &primary_input, + const tbcs_ppzksnark_proof &proof) +{ + typedef Fr FieldT; + enter_block("Call to tbcs_ppzksnark_verifier_weak_IC"); + const uscs_primary_input uscs_input = convert_bit_vector_to_field_element_vector(primary_input); + const tbcs_ppzksnark_processed_verification_key pvk = tbcs_ppzksnark_verifier_process_vk(vk); + const bool bit = uscs_ppzksnark_online_verifier_weak_IC(pvk, uscs_input, proof); + leave_block("Call to tbcs_ppzksnark_verifier_weak_IC"); + + return bit; +} + +template +bool tbcs_ppzksnark_verifier_strong_IC(const tbcs_ppzksnark_verification_key &vk, + const tbcs_ppzksnark_primary_input &primary_input, + const tbcs_ppzksnark_proof &proof) +{ + typedef Fr FieldT; + enter_block("Call to tbcs_ppzksnark_verifier_strong_IC"); + const tbcs_ppzksnark_processed_verification_key pvk = tbcs_ppzksnark_verifier_process_vk(vk); + const uscs_primary_input uscs_input = convert_bit_vector_to_field_element_vector(primary_input); + const bool bit = uscs_ppzksnark_online_verifier_strong_IC(pvk, uscs_input, proof); + leave_block("Call to tbcs_ppzksnark_verifier_strong_IC"); + + return bit; +} + +template +bool tbcs_ppzksnark_online_verifier_weak_IC(const tbcs_ppzksnark_processed_verification_key &pvk, + const tbcs_ppzksnark_primary_input &primary_input, + const tbcs_ppzksnark_proof &proof) +{ + typedef Fr FieldT; + enter_block("Call to tbcs_ppzksnark_online_verifier_weak_IC"); + const uscs_primary_input uscs_input = convert_bit_vector_to_field_element_vector(primary_input); + const bool bit = uscs_ppzksnark_online_verifier_weak_IC(pvk, uscs_input, proof); + leave_block("Call to tbcs_ppzksnark_online_verifier_weak_IC"); + + return bit; +} + +template +bool tbcs_ppzksnark_online_verifier_strong_IC(const tbcs_ppzksnark_processed_verification_key &pvk, + const tbcs_ppzksnark_primary_input &primary_input, + const tbcs_ppzksnark_proof &proof) +{ + typedef Fr FieldT; + enter_block("Call to tbcs_ppzksnark_online_verifier_strong_IC"); + const uscs_primary_input uscs_input = convert_bit_vector_to_field_element_vector(primary_input); + const bool bit = uscs_ppzksnark_online_verifier_strong_IC(pvk, uscs_input, proof); + leave_block("Call to tbcs_ppzksnark_online_verifier_strong_IC"); + + return bit; +} + +} // libsnark + +#endif // TBCS_PPZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tbcs_ppzksnark_params.hpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tbcs_ppzksnark_params.hpp new file mode 100644 index 0000000..4214b24 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tbcs_ppzksnark_params.hpp @@ -0,0 +1,31 @@ +/** @file + ***************************************************************************** + + Declaration of public-parameter selector for the TBCS ppzkSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TBCS_PPZKSNARK_PARAMS_HPP_ +#define TBCS_PPZKSNARK_PARAMS_HPP_ + +#include "relations/circuit_satisfaction_problems/tbcs/tbcs.hpp" + +namespace libsnark { + +/** + * Below are various typedefs aliases (used for uniformity with other proof systems). + */ + +typedef tbcs_circuit tbcs_ppzksnark_circuit; + +typedef tbcs_primary_input tbcs_ppzksnark_primary_input; + +typedef tbcs_auxiliary_input tbcs_ppzksnark_auxiliary_input; + +} // libsnark + +#endif // TBCS_PPZKSNARK_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tests/test_tbcs_ppzksnark.cpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tests/test_tbcs_ppzksnark.cpp new file mode 100644 index 0000000..22973fe --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tests/test_tbcs_ppzksnark.cpp @@ -0,0 +1,46 @@ +/** @file + ***************************************************************************** + Test program that exercises the ppzkSNARK (first generator, then + prover, then verifier) on a synthetic TBCS instance. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include + +#include "common/default_types/tbcs_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.hpp" +#include "zk_proof_systems/ppzksnark/tbcs_ppzksnark/examples/run_tbcs_ppzksnark.hpp" + +using namespace libsnark; + +template +void test_tbcs_ppzksnark(const size_t primary_input_size, + const size_t auxiliary_input_size, + const size_t num_gates, + const size_t num_outputs) +{ + print_header("(enter) Test TBCS ppzkSNARK"); + + const bool test_serialization = true; + const tbcs_example example = generate_tbcs_example(primary_input_size, auxiliary_input_size, num_gates, num_outputs); +#ifdef DEBUG + example.circuit.print(); +#endif + const bool bit = run_tbcs_ppzksnark(example, test_serialization); + assert(bit); + + print_header("(leave) Test TBCS ppzkSNARK"); +} + +int main() +{ + default_tbcs_ppzksnark_pp::init_public_params(); + start_profiling(); + + test_tbcs_ppzksnark(10, 10, 20, 5); +} diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/uscs_ppzksnark/examples/run_uscs_ppzksnark.hpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/uscs_ppzksnark/examples/run_uscs_ppzksnark.hpp new file mode 100644 index 0000000..7230620 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/uscs_ppzksnark/examples/run_uscs_ppzksnark.hpp @@ -0,0 +1,35 @@ +/** @file + ***************************************************************************** + + Declaration of functionality that runs the USCS ppzkSNARK for + a given USCS example. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_USCS_PPZKSNARK_HPP_ +#define RUN_USCS_PPZKSNARK_HPP_ + +#include "relations/constraint_satisfaction_problems/uscs/examples/uscs_examples.hpp" + +namespace libsnark { + +/** + * Runs the ppzkSNARK (generator, prover, and verifier) for a given + * USCS example (specified by a constraint system, input, and witness). + * + * Optionally, also test the serialization routines for keys and proofs. + * (This takes additional time.) + */ +template +bool run_uscs_ppzksnark(const uscs_example > &example, + const bool test_serialization); + +} // libsnark + +#include "zk_proof_systems/ppzksnark/uscs_ppzksnark/examples/run_uscs_ppzksnark.tcc" + +#endif // RUN_USCS_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/uscs_ppzksnark/examples/run_uscs_ppzksnark.tcc b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/uscs_ppzksnark/examples/run_uscs_ppzksnark.tcc new file mode 100644 index 0000000..7a9a045 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/uscs_ppzksnark/examples/run_uscs_ppzksnark.tcc @@ -0,0 +1,87 @@ +/** @file + ***************************************************************************** + + Implementation of functionality that runs the USCS ppzkSNARK for + a given USCS example. + + See run_uscs_ppzksnark.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_USCS_PPZKSNARK_TCC_ +#define RUN_USCS_PPZKSNARK_TCC_ + +#include "zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark.hpp" + +#include + +#include "common/profiling.hpp" + +namespace libsnark { + +/** + * The code below provides an example of all stages of running a USCS ppzkSNARK. + * + * Of course, in a real-life scenario, we would have three distinct entities, + * mangled into one in the demonstration below. The three entities are as follows. + * (1) The "generator", which runs the ppzkSNARK generator on input a given + * constraint system CS to create a proving and a verification key for CS. + * (2) The "prover", which runs the ppzkSNARK prover on input the proving key, + * a primary input for CS, and an auxiliary input for CS. + * (3) The "verifier", which runs the ppzkSNARK verifier on input the verification key, + * a primary input for CS, and a proof. + */ +template +bool run_uscs_ppzksnark(const uscs_example > &example, + const bool test_serialization) +{ + enter_block("Call to run_uscs_ppzksnark"); + + print_header("USCS ppzkSNARK Generator"); + uscs_ppzksnark_keypair keypair = uscs_ppzksnark_generator(example.constraint_system); + printf("\n"); print_indent(); print_mem("after generator"); + + print_header("Preprocess verification key"); + uscs_ppzksnark_processed_verification_key pvk = uscs_ppzksnark_verifier_process_vk(keypair.vk); + + if (test_serialization) + { + enter_block("Test serialization of keys"); + keypair.pk = reserialize >(keypair.pk); + keypair.vk = reserialize >(keypair.vk); + pvk = reserialize >(pvk); + leave_block("Test serialization of keys"); + } + + print_header("USCS ppzkSNARK Prover"); + uscs_ppzksnark_proof proof = uscs_ppzksnark_prover(keypair.pk, example.primary_input, example.auxiliary_input); + printf("\n"); print_indent(); print_mem("after prover"); + + if (test_serialization) + { + enter_block("Test serialization of proof"); + proof = reserialize >(proof); + leave_block("Test serialization of proof"); + } + + print_header("USCS ppzkSNARK Verifier"); + bool ans = uscs_ppzksnark_verifier_strong_IC(keypair.vk, example.primary_input, proof); + printf("\n"); print_indent(); print_mem("after verifier"); + printf("* The verification result is: %s\n", (ans ? "PASS" : "FAIL")); + + print_header("USCS ppzkSNARK Online Verifier"); + bool ans2 = uscs_ppzksnark_online_verifier_strong_IC(pvk, example.primary_input, proof); + assert(ans == ans2); + + leave_block("Call to run_uscs_ppzksnark"); + + return ans; +} + +} // libsnark + +#endif // RUN_USCS_PPZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/uscs_ppzksnark/profiling/profile_uscs_ppzksnark.cpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/uscs_ppzksnark/profiling/profile_uscs_ppzksnark.cpp new file mode 100644 index 0000000..0edfec6 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/uscs_ppzksnark/profiling/profile_uscs_ppzksnark.cpp @@ -0,0 +1,65 @@ +/** @file + ***************************************************************************** + Profiling program that exercises the ppzkSNARK (first generator, then prover, + then verifier) on a synthetic USCS instance. + + The command + + $ src/zk_proof_systems/ppzksnark/uscs_ppzksnark/profiling/profile_uscs_ppzksnark 1000 10 Fr + + exercises the ppzkSNARK (first generator, then prover, then verifier) on an USCS instance with 1000 equations and an input consisting of 10 field elements. + + (If you get the error `zmInit ERR:can't protect`, see the discussion [above](#elliptic-curve-choices).) + + The command + + $ src/zk_proof_systems/ppzksnark/uscs_ppzksnark/profiling/profile_uscs_ppzksnark 1000 10 bytes + + does the same but now the input consists of 10 bytes. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include + +#include "common/default_types/uscs_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "relations/constraint_satisfaction_problems/uscs/examples/uscs_examples.hpp" +#include "zk_proof_systems/ppzksnark/uscs_ppzksnark/examples/run_uscs_ppzksnark.hpp" + +using namespace libsnark; + +int main(int argc, const char * argv[]) +{ + default_uscs_ppzksnark_pp::init_public_params(); + start_profiling(); + + if (argc == 2 && strcmp(argv[1], "-v") == 0) + { + print_compilation_info(); + return 0; + } + + if (argc != 3) + { + printf("usage: %s num_constraints input_size\n", argv[0]); + return 1; + } + + const int num_constraints = atoi(argv[1]); + const int input_size = atoi(argv[2]); + + enter_block("Generate USCS example"); + uscs_example > example = generate_uscs_example_with_field_input >(num_constraints, input_size); + leave_block("Generate USCS example"); + + print_header("(enter) Profile USCS ppzkSNARK"); + const bool test_serialization = true; + run_uscs_ppzksnark(example, test_serialization); + print_header("(leave) Profile USCS ppzkSNARK"); +} diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/uscs_ppzksnark/tests/test_uscs_ppzksnark.cpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/uscs_ppzksnark/tests/test_uscs_ppzksnark.cpp new file mode 100644 index 0000000..6e8491c --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/uscs_ppzksnark/tests/test_uscs_ppzksnark.cpp @@ -0,0 +1,42 @@ +/** @file + ***************************************************************************** + Test program that exercises the ppzkSNARK (first generator, then + prover, then verifier) on a synthetic USCS instance. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include + +#include "common/default_types/uscs_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "relations/constraint_satisfaction_problems/uscs/examples/uscs_examples.hpp" +#include "zk_proof_systems/ppzksnark/uscs_ppzksnark/examples/run_uscs_ppzksnark.hpp" + +using namespace libsnark; + +template +void test_uscs_ppzksnark(size_t num_constraints, + size_t input_size) +{ + print_header("(enter) Test USCS ppzkSNARK"); + + const bool test_serialization = true; + uscs_example > example = generate_uscs_example_with_binary_input >(num_constraints, input_size); + const bool bit = run_uscs_ppzksnark(example, test_serialization); + assert(bit); + + print_header("(leave) Test USCS ppzkSNARK"); +} + +int main() +{ + default_uscs_ppzksnark_pp::init_public_params(); + start_profiling(); + + test_uscs_ppzksnark(1000, 100); +} diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark.hpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark.hpp new file mode 100644 index 0000000..29c53d3 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark.hpp @@ -0,0 +1,428 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a ppzkSNARK for USCS. + + This includes: + - class for proving key + - class for verification key + - class for processed verification key + - class for key pair (proving key & verification key) + - class for proof + - generator algorithm + - prover algorithm + - verifier algorithm (with strong or weak input consistency) + - online verifier algorithm (with strong or weak input consistency) + + The implementation instantiates the protocol of \[DFGK14], by following + extending, and optimizing the approach described in \[BCTV14]. + + + Acronyms: + + - "ppzkSNARK" = "Pre-Processing Zero-Knowledge Succinct Non-interactive ARgument of Knowledge" + - "USCS" = "Unitary-Square Constraint Systems" + + References: + + \[BCTV14]: + "Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture", + Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, + USENIX Security 2014, + + + \[DFGK14]: + "Square Span Programs with Applications to Succinct NIZK Arguments" + George Danezis, Cedric Fournet, Jens Groth, Markulf Kohlweiss, + ASIACRYPT 2014, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef USCS_PPZKSNARK_HPP_ +#define USCS_PPZKSNARK_HPP_ + +#include + +#include "algebra/curves/public_params.hpp" +#include "common/data_structures/accumulation_vector.hpp" +#include "algebra/knowledge_commitment/knowledge_commitment.hpp" +#include "relations/constraint_satisfaction_problems/uscs/uscs.hpp" +#include "zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark_params.hpp" + +namespace libsnark { + +/******************************** Proving key ********************************/ + +template +class uscs_ppzksnark_proving_key; + +template +std::ostream& operator<<(std::ostream &out, const uscs_ppzksnark_proving_key &pk); + +template +std::istream& operator>>(std::istream &in, uscs_ppzksnark_proving_key &pk); + +/** + * A proving key for the USCS ppzkSNARK. + */ +template +class uscs_ppzksnark_proving_key { +public: + G1_vector V_g1_query; + G1_vector alpha_V_g1_query; + G1_vector H_g1_query; + G2_vector V_g2_query; + + uscs_ppzksnark_constraint_system constraint_system; + + uscs_ppzksnark_proving_key() {}; + uscs_ppzksnark_proving_key& operator=(const uscs_ppzksnark_proving_key &other) = default; + uscs_ppzksnark_proving_key(const uscs_ppzksnark_proving_key &other) = default; + uscs_ppzksnark_proving_key(uscs_ppzksnark_proving_key &&other) = default; + uscs_ppzksnark_proving_key(G1_vector &&V_g1_query, + G1_vector &&alpha_V_g1_query, + G1_vector &&H_g1_query, + G2_vector &&V_g2_query, + uscs_ppzksnark_constraint_system &&constraint_system) : + V_g1_query(std::move(V_g1_query)), + alpha_V_g1_query(std::move(alpha_V_g1_query)), + H_g1_query(std::move(H_g1_query)), + V_g2_query(std::move(V_g2_query)), + constraint_system(std::move(constraint_system)) + {}; + + size_t G1_size() const + { + return V_g1_query.size() + alpha_V_g1_query.size() + H_g1_query.size(); + } + + size_t G2_size() const + { + return V_g2_query.size(); + } + + size_t G1_sparse_size() const + { + return G1_size(); + } + + size_t G2_sparse_size() const + { + return G2_size(); + } + + size_t size_in_bits() const + { + return G1::size_in_bits() * G1_size() + G2::size_in_bits() * G2_size(); + } + + void print_size() const + { + print_indent(); printf("* G1 elements in PK: %zu\n", this->G1_size()); + print_indent(); printf("* Non-zero G1 elements in PK: %zu\n", this->G1_sparse_size()); + print_indent(); printf("* G2 elements in PK: %zu\n", this->G2_size()); + print_indent(); printf("* Non-zero G2 elements in PK: %zu\n", this->G2_sparse_size()); + print_indent(); printf("* PK size in bits: %zu\n", this->size_in_bits()); + } + + bool operator==(const uscs_ppzksnark_proving_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const uscs_ppzksnark_proving_key &pk); + friend std::istream& operator>> (std::istream &in, uscs_ppzksnark_proving_key &pk); +}; + + +/******************************* Verification key ****************************/ + +template +class uscs_ppzksnark_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const uscs_ppzksnark_verification_key &vk); + +template +std::istream& operator>>(std::istream &in, uscs_ppzksnark_verification_key &vk); + +/** + * A verification key for the USCS ppzkSNARK. + */ +template +class uscs_ppzksnark_verification_key { +public: + G2 tilde_g2; + G2 alpha_tilde_g2; + G2 Z_g2; + + accumulation_vector > encoded_IC_query; + + uscs_ppzksnark_verification_key() = default; + uscs_ppzksnark_verification_key(const G2 &tilde_g2, + const G2 &alpha_tilde_g2, + const G2 &Z_g2, + const accumulation_vector > &eIC) : + tilde_g2(tilde_g2), + alpha_tilde_g2(alpha_tilde_g2), + Z_g2(Z_g2), + encoded_IC_query(eIC) + {}; + + size_t G1_size() const + { + return encoded_IC_query.size(); + } + + size_t G2_size() const + { + return 3; + } + + size_t size_in_bits() const + { + return encoded_IC_query.size_in_bits() + 3 * G2::size_in_bits(); + } + + void print_size() const + { + print_indent(); printf("* G1 elements in VK: %zu\n", this->G1_size()); + print_indent(); printf("* G2 elements in VK: %zu\n", this->G2_size()); + print_indent(); printf("* VK size in bits: %zu\n", this->size_in_bits()); + } + + bool operator==(const uscs_ppzksnark_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const uscs_ppzksnark_verification_key &vk); + friend std::istream& operator>> (std::istream &in, uscs_ppzksnark_verification_key &vk); + + static uscs_ppzksnark_verification_key dummy_verification_key(const size_t input_size); +}; + + +/************************ Processed verification key *************************/ + +template +class uscs_ppzksnark_processed_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const uscs_ppzksnark_processed_verification_key &pvk); + +template +std::istream& operator>>(std::istream &in, uscs_ppzksnark_processed_verification_key &pvk); + +/** + * A processed verification key for the USCS ppzkSNARK. + * + * Compared to a (non-processed) verification key, a processed verification key + * contains a small constant amount of additional pre-computed information that + * enables a faster verification time. + */ +template +class uscs_ppzksnark_processed_verification_key { +public: + G1_precomp pp_G1_one_precomp; + G2_precomp pp_G2_one_precomp; + G2_precomp vk_tilde_g2_precomp; + G2_precomp vk_alpha_tilde_g2_precomp; + G2_precomp vk_Z_g2_precomp; + GT pairing_of_g1_and_g2; + + accumulation_vector > encoded_IC_query; + + bool operator==(const uscs_ppzksnark_processed_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const uscs_ppzksnark_processed_verification_key &pvk); + friend std::istream& operator>> (std::istream &in, uscs_ppzksnark_processed_verification_key &pvk); +}; + + +/********************************** Key pair *********************************/ + +/** + * A key pair for the USCS ppzkSNARK, which consists of a proving key and a verification key. + */ +template +class uscs_ppzksnark_keypair { +public: + uscs_ppzksnark_proving_key pk; + uscs_ppzksnark_verification_key vk; + + uscs_ppzksnark_keypair() {}; + uscs_ppzksnark_keypair(uscs_ppzksnark_proving_key &&pk, + uscs_ppzksnark_verification_key &&vk) : + pk(std::move(pk)), + vk(std::move(vk)) + {} + + uscs_ppzksnark_keypair(uscs_ppzksnark_keypair &&other) = default; +}; + + +/*********************************** Proof ***********************************/ + +template +class uscs_ppzksnark_proof; + +template +std::ostream& operator<<(std::ostream &out, const uscs_ppzksnark_proof &proof); + +template +std::istream& operator>>(std::istream &in, uscs_ppzksnark_proof &proof); + +/** + * A proof for the USCS ppzkSNARK. + * + * While the proof has a structure, externally one merely opaquely produces, + * seralizes/deserializes, and verifies proofs. We only expose some information + * about the structure for statistics purposes. + */ +template +class uscs_ppzksnark_proof { +public: + G1 V_g1; + G1 alpha_V_g1; + G1 H_g1; + G2 V_g2; + + uscs_ppzksnark_proof() + { + // invalid proof with valid curve points + this->V_g1 = G1 ::one(); + this->alpha_V_g1 = G1 ::one(); + this->H_g1 = G1 ::one(); + this->V_g2 = G2 ::one(); + } + uscs_ppzksnark_proof(G1 &&V_g1, + G1 &&alpha_V_g1, + G1 &&H_g1, + G2 &&V_g2) : + V_g1(std::move(V_g1)), + alpha_V_g1(std::move(alpha_V_g1)), + H_g1(std::move(H_g1)), + V_g2(std::move(V_g2)) + {}; + + size_t G1_size() const + { + return 3; + } + + size_t G2_size() const + { + return 1; + } + + size_t size_in_bits() const + { + return G1_size() * G1::size_in_bits() + G2_size() * G2::size_in_bits(); + } + + void print_size() const + { + print_indent(); printf("* G1 elements in proof: %zu\n", this->G1_size()); + print_indent(); printf("* G2 elements in proof: %zu\n", this->G2_size()); + print_indent(); printf("* Proof size in bits: %zu\n", this->size_in_bits()); + } + + bool is_well_formed() const + { + return (V_g1.is_well_formed() && + alpha_V_g1.is_well_formed() && + H_g1.is_well_formed() && + V_g2.is_well_formed()); + } + + bool operator==(const uscs_ppzksnark_proof &other) const; + friend std::ostream& operator<< (std::ostream &out, const uscs_ppzksnark_proof &proof); + friend std::istream& operator>> (std::istream &in, uscs_ppzksnark_proof &proof); +}; + + +/***************************** Main algorithms *******************************/ + +/** + * A generator algorithm for the USCS ppzkSNARK. + * + * Given a USCS constraint system CS, this algorithm produces proving and verification keys for CS. + */ +template +uscs_ppzksnark_keypair uscs_ppzksnark_generator(const uscs_ppzksnark_constraint_system &cs); + +/** + * A prover algorithm for the USCS ppzkSNARK. + * + * Given a USCS primary input X and a USCS auxiliary input Y, this algorithm + * produces a proof (of knowledge) that attests to the following statement: + * ``there exists Y such that CS(X,Y)=0''. + * Above, CS is the USCS constraint system that was given as input to the generator algorithm. + */ +template +uscs_ppzksnark_proof uscs_ppzksnark_prover(const uscs_ppzksnark_proving_key &pk, + const uscs_ppzksnark_primary_input &primary_input, + const uscs_ppzksnark_auxiliary_input &auxiliary_input); + +/* + Below are four variants of verifier algorithm for the USCS ppzkSNARK. + + These are the four cases that arise from the following two choices: + + (1) The verifier accepts a (non-processed) verification key or, instead, a processed verification key. + In the latter case, we call the algorithm an "online verifier". + + (2) The verifier checks for "weak" input consistency or, instead, "strong" input consistency. + Strong input consistency requires that |primary_input| = CS.num_inputs, whereas + weak input consistency requires that |primary_input| <= CS.num_inputs (and + the primary input is implicitly padded with zeros up to length CS.num_inputs). + */ + +/** + * A verifier algorithm for the USCS ppzkSNARK that: + * (1) accepts a non-processed verification key, and + * (2) has weak input consistency. + */ +template +bool uscs_ppzksnark_verifier_weak_IC(const uscs_ppzksnark_verification_key &vk, + const uscs_ppzksnark_primary_input &primary_input, + const uscs_ppzksnark_proof &proof); + +/** + * A verifier algorithm for the USCS ppzkSNARK that: + * (1) accepts a non-processed verification key, and + * (2) has strong input consistency. + */ +template +bool uscs_ppzksnark_verifier_strong_IC(const uscs_ppzksnark_verification_key &vk, + const uscs_ppzksnark_primary_input &primary_input, + const uscs_ppzksnark_proof &proof); + +/** + * Convert a (non-processed) verification key into a processed verification key. + */ +template +uscs_ppzksnark_processed_verification_key uscs_ppzksnark_verifier_process_vk(const uscs_ppzksnark_verification_key &vk); + +/** + * A verifier algorithm for the USCS ppzkSNARK that: + * (1) accepts a processed verification key, and + * (2) has weak input consistency. + */ +template +bool uscs_ppzksnark_online_verifier_weak_IC(const uscs_ppzksnark_processed_verification_key &pvk, + const uscs_ppzksnark_primary_input &primary_input, + const uscs_ppzksnark_proof &proof); + +/** + * A verifier algorithm for the USCS ppzkSNARK that: + * (1) accepts a processed verification key, and + * (2) has strong input consistency. + */ +template +bool uscs_ppzksnark_online_verifier_strong_IC(const uscs_ppzksnark_processed_verification_key &pvk, + const uscs_ppzksnark_primary_input &primary_input, + const uscs_ppzksnark_proof &proof); + +} // libsnark + +#include "zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark.tcc" + +#endif // USCS_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark.tcc b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark.tcc new file mode 100644 index 0000000..4d47b40 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark.tcc @@ -0,0 +1,553 @@ +/** @file + ***************************************************************************** + Implementation of interfaces for a ppzkSNARK for USCS. + + See uscs_ppzksnark.hpp . + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef USCS_PPZKSNARK_TCC_ +#define USCS_PPZKSNARK_TCC_ + +#include +#include +#include +#include +#include + +#include "reductions/uscs_to_ssp/uscs_to_ssp.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "algebra/scalar_multiplication/multiexp.hpp" +#include "relations/arithmetic_programs/ssp/ssp.hpp" + +namespace libsnark { + +template +bool uscs_ppzksnark_proving_key::operator==(const uscs_ppzksnark_proving_key &other) const +{ + return (this->V_g1_query == other.V_g1_query && + this->alpha_V_g1_query == other.alpha_V_g1_query && + this->H_g1_query == other.H_g1_query && + this->V_g2_query == other.V_g2_query && + this->constraint_system == other.constraint_system); +} + +template +std::ostream& operator<<(std::ostream &out, const uscs_ppzksnark_proving_key &pk) +{ + out << pk.V_g1_query; + out << pk.alpha_V_g1_query; + out << pk.H_g1_query; + out << pk.V_g2_query; + out << pk.constraint_system; + + return out; +} + +template +std::istream& operator>>(std::istream &in, uscs_ppzksnark_proving_key &pk) +{ + in >> pk.V_g1_query; + in >> pk.alpha_V_g1_query; + in >> pk.H_g1_query; + in >> pk.V_g2_query; + in >> pk.constraint_system; + + return in; +} + +template +bool uscs_ppzksnark_verification_key::operator==(const uscs_ppzksnark_verification_key &other) const +{ + return (this->tilde_g2 == other.tilde_g2 && + this->alpha_tilde_g2 == other.alpha_tilde_g2 && + this->Z_g2 == other.Z_g2 && + this->encoded_IC_query == other.encoded_IC_query); +} + +template +std::ostream& operator<<(std::ostream &out, const uscs_ppzksnark_verification_key &vk) +{ + out << vk.tilde_g2 << OUTPUT_NEWLINE; + out << vk.alpha_tilde_g2 << OUTPUT_NEWLINE; + out << vk.Z_g2 << OUTPUT_NEWLINE; + out << vk.encoded_IC_query << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, uscs_ppzksnark_verification_key &vk) +{ + in >> vk.tilde_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.alpha_tilde_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.Z_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.encoded_IC_query; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +bool uscs_ppzksnark_processed_verification_key::operator==(const uscs_ppzksnark_processed_verification_key &other) const +{ + return (this->pp_G1_one_precomp == other.pp_G1_one_precomp && + this->pp_G2_one_precomp == other.pp_G2_one_precomp && + this->vk_tilde_g2_precomp == other.vk_tilde_g2_precomp && + this->vk_alpha_tilde_g2_precomp == other.vk_alpha_tilde_g2_precomp && + this->vk_Z_g2_precomp == other.vk_Z_g2_precomp && + this->pairing_of_g1_and_g2 == other.pairing_of_g1_and_g2 && + this->encoded_IC_query == other.encoded_IC_query); +} + +template +std::ostream& operator<<(std::ostream &out, const uscs_ppzksnark_processed_verification_key &pvk) +{ + out << pvk.pp_G1_one_precomp << OUTPUT_NEWLINE; + out << pvk.pp_G2_one_precomp << OUTPUT_NEWLINE; + out << pvk.vk_tilde_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_alpha_tilde_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_Z_g2_precomp << OUTPUT_NEWLINE; + out << pvk.pairing_of_g1_and_g2 << OUTPUT_NEWLINE; + out << pvk.encoded_IC_query << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, uscs_ppzksnark_processed_verification_key &pvk) +{ + in >> pvk.pp_G1_one_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.pp_G2_one_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_tilde_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_alpha_tilde_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_Z_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.pairing_of_g1_and_g2; + consume_OUTPUT_NEWLINE(in); + in >> pvk.encoded_IC_query; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +bool uscs_ppzksnark_proof::operator==(const uscs_ppzksnark_proof &other) const +{ + return (this->V_g1 == other.V_g1 && + this->alpha_V_g1 == other.alpha_V_g1 && + this->H_g1 == other.H_g1 && + this->V_g2 == other.V_g2); +} + +template +std::ostream& operator<<(std::ostream &out, const uscs_ppzksnark_proof &proof) +{ + out << proof.V_g1 << OUTPUT_NEWLINE; + out << proof.alpha_V_g1 << OUTPUT_NEWLINE; + out << proof.H_g1 << OUTPUT_NEWLINE; + out << proof.V_g2 << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, uscs_ppzksnark_proof &proof) +{ + in >> proof.V_g1; + consume_OUTPUT_NEWLINE(in); + in >> proof.alpha_V_g1; + consume_OUTPUT_NEWLINE(in); + in >> proof.H_g1; + consume_OUTPUT_NEWLINE(in); + in >> proof.V_g2; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +uscs_ppzksnark_verification_key uscs_ppzksnark_verification_key::dummy_verification_key(const size_t input_size) +{ + uscs_ppzksnark_verification_key result; + result.tilde_g2 = Fr::random_element() * G2::one(); + result.alpha_tilde_g2 = Fr::random_element() * G2::one(); + result.Z_g2 = Fr::random_element() * G2::one(); + + G1 base = Fr::random_element() * G1::one(); + G1_vector v; + for (size_t i = 0; i < input_size; ++i) + { + v.emplace_back(Fr::random_element() * G1::one()); + } + + result.encoded_IC_query = accumulation_vector >(v); + + return result; +} + +template +uscs_ppzksnark_keypair uscs_ppzksnark_generator(const uscs_ppzksnark_constraint_system &cs) +{ + enter_block("Call to uscs_ppzksnark_generator"); + + /* draw random element at which the SSP is evaluated */ + + const Fr t = Fr::random_element(); + + /* perform USCS-to-SSP reduction */ + + ssp_instance_evaluation > ssp_inst = uscs_to_ssp_instance_map_with_evaluation(cs, t); + + print_indent(); printf("* SSP number of variables: %zu\n", ssp_inst.num_variables()); + print_indent(); printf("* SSP pre degree: %zu\n", cs.num_constraints()); + print_indent(); printf("* SSP degree: %zu\n", ssp_inst.degree()); + print_indent(); printf("* SSP number of input variables: %zu\n", ssp_inst.num_inputs()); + + /* construct various tables of FieldT elements */ + + Fr_vector Vt_table = std::move(ssp_inst.Vt); // ssp_inst.Vt is now in unspecified state, but we do not use it later + Fr_vector Ht_table = std::move(ssp_inst.Ht); // ssp_inst.Ht is now in unspecified state, but we do not use it later + + Vt_table.emplace_back(ssp_inst.Zt); + + Fr_vector Xt_table = Fr_vector(Vt_table.begin(), Vt_table.begin() + ssp_inst.num_inputs() + 1); + Fr_vector Vt_table_minus_Xt_table = Fr_vector(Vt_table.begin() + ssp_inst.num_inputs() + 1, Vt_table.end()); + + /* sanity checks */ + + assert(Vt_table.size() == ssp_inst.num_variables() + 2); + printf("Ht_table.size() = %zu, ssp_inst.degree() + 1 = %zu\n", Ht_table.size(), ssp_inst.degree() + 1); + assert(Ht_table.size() == ssp_inst.degree() + 1); + assert(Xt_table.size() == ssp_inst.num_inputs() + 1); + assert(Vt_table_minus_Xt_table.size() == ssp_inst.num_variables() + 2 - ssp_inst.num_inputs() - 1); + for (size_t i = 0; i < ssp_inst.num_inputs()+1; ++i) + { + assert(!Xt_table[i].is_zero()); + } + + const Fr alpha = Fr::random_element(); + + enter_block("Generate USCS proving key"); + + const size_t g1_exp_count = Vt_table.size() + Vt_table_minus_Xt_table.size() + Ht_table.size(); + const size_t g2_exp_count = Vt_table_minus_Xt_table.size(); + + size_t g1_window = get_exp_window_size >(g1_exp_count); + size_t g2_window = get_exp_window_size >(g2_exp_count); + + print_indent(); printf("* G1 window: %zu\n", g1_window); + print_indent(); printf("* G2 window: %zu\n", g2_window); + + enter_block("Generating G1 multiexp table"); + window_table > g1_table = get_window_table(Fr::size_in_bits(), g1_window, G1::one()); + leave_block("Generating G1 multiexp table"); + + enter_block("Generating G2 multiexp table"); + window_table > g2_table = get_window_table(Fr::size_in_bits(), g2_window, G2::one()); + leave_block("Generating G2 multiexp table"); + + enter_block("Generate proof components"); + + enter_block("Compute the query for V_g1", false); + G1_vector V_g1_query = batch_exp(Fr::size_in_bits(), g1_window, g1_table, Vt_table_minus_Xt_table); + leave_block("Compute the query for V_g1", false); + + enter_block("Compute the query for alpha_V_g1", false); + G1_vector alpha_V_g1_query = batch_exp_with_coeff(Fr::size_in_bits(), g1_window, g1_table, alpha, Vt_table_minus_Xt_table); + leave_block("Compute the query for alpha_V_g1", false); + + enter_block("Compute the query for H_g1", false); + G1_vector H_g1_query = batch_exp(Fr::size_in_bits(), g1_window, g1_table, Ht_table); + leave_block("Compute the query for H_g1", false); + + enter_block("Compute the query for V_g2", false); + G2_vector V_g2_query = batch_exp(Fr::size_in_bits(), g2_window, g2_table, Vt_table); + leave_block("Compute the query for V_g2", false); + + leave_block("Generate proof components"); + + leave_block("Generate USCS proving key"); + + enter_block("Generate USCS verification key"); + + const Fr tilde = Fr::random_element(); + G2 tilde_g2 = tilde * G2::one(); + G2 alpha_tilde_g2 = (alpha * tilde) * G2::one(); + G2 Z_g2 = ssp_inst.Zt * G2::one(); + + enter_block("Encode IC query for USCS verification key"); + G1 encoded_IC_base = Xt_table[0] * G1::one(); + G1_vector encoded_IC_values = batch_exp(Fr::size_in_bits(), g1_window, g1_table, Fr_vector(Xt_table.begin() + 1, Xt_table.end())); + leave_block("Encode IC query for USCS verification key"); + + leave_block("Generate USCS verification key"); + + leave_block("Call to uscs_ppzksnark_generator"); + + accumulation_vector > encoded_IC_query(std::move(encoded_IC_base), std::move(encoded_IC_values)); + + uscs_ppzksnark_verification_key vk = uscs_ppzksnark_verification_key(tilde_g2, + alpha_tilde_g2, + Z_g2, + encoded_IC_query); + + uscs_ppzksnark_constraint_system cs_copy = cs; + uscs_ppzksnark_proving_key pk = uscs_ppzksnark_proving_key(std::move(V_g1_query), + std::move(alpha_V_g1_query), + std::move(H_g1_query), + std::move(V_g2_query), + std::move(cs_copy)); + + pk.print_size(); + vk.print_size(); + + return uscs_ppzksnark_keypair(std::move(pk), std::move(vk)); +} + +template +uscs_ppzksnark_proof uscs_ppzksnark_prover(const uscs_ppzksnark_proving_key &pk, + const uscs_ppzksnark_primary_input &primary_input, + const uscs_ppzksnark_auxiliary_input &auxiliary_input) +{ + enter_block("Call to uscs_ppzksnark_prover"); + + const Fr d = Fr::random_element(); + + enter_block("Compute the polynomial H"); + const ssp_witness > ssp_wit = uscs_to_ssp_witness_map(pk.constraint_system, primary_input, auxiliary_input, d); + leave_block("Compute the polynomial H"); + + /* sanity checks */ + assert(pk.constraint_system.is_satisfied(primary_input, auxiliary_input)); + assert(pk.V_g1_query.size() == ssp_wit.num_variables() + 2 - ssp_wit.num_inputs() - 1); + assert(pk.alpha_V_g1_query.size() == ssp_wit.num_variables() + 2 - ssp_wit.num_inputs() - 1); + assert(pk.H_g1_query.size() == ssp_wit.degree() + 1); + assert(pk.V_g2_query.size() == ssp_wit.num_variables() + 2); + +#ifdef DEBUG + const Fr t = Fr::random_element(); + ssp_instance_evaluation > ssp_inst = uscs_to_ssp_instance_map_with_evaluation(pk.constraint_system, t); + assert(ssp_inst.is_satisfied(ssp_wit)); +#endif + + G1 V_g1 = ssp_wit.d*pk.V_g1_query[pk.V_g1_query.size()-1]; + G1 alpha_V_g1 = ssp_wit.d*pk.alpha_V_g1_query[pk.alpha_V_g1_query.size()-1]; + G1 H_g1 = G1::zero(); + G2 V_g2 = pk.V_g2_query[0]+ssp_wit.d*pk.V_g2_query[pk.V_g2_query.size()-1]; + +#ifdef MULTICORE + const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads() +#else + const size_t chunks = 1; +#endif + + // MAYBE LATER: do queries 1,2,4 at once for slightly better speed + + enter_block("Compute the proof"); + + enter_block("Compute V_g1, the 1st component of the proof", false); + V_g1 = V_g1 + multi_exp_with_mixed_addition, Fr >(pk.V_g1_query.begin(), pk.V_g1_query.begin()+(ssp_wit.num_variables()-ssp_wit.num_inputs()), + ssp_wit.coefficients_for_Vs.begin()+ssp_wit.num_inputs(), ssp_wit.coefficients_for_Vs.begin()+ssp_wit.num_variables(), + chunks, + true); + leave_block("Compute V_g1, the 1st component of the proof", false); + + enter_block("Compute alpha_V_g1, the 2nd component of the proof", false); + alpha_V_g1 = alpha_V_g1 + multi_exp_with_mixed_addition, Fr >(pk.alpha_V_g1_query.begin(), pk.alpha_V_g1_query.begin()+(ssp_wit.num_variables()-ssp_wit.num_inputs()), + ssp_wit.coefficients_for_Vs.begin()+ssp_wit.num_inputs(), ssp_wit.coefficients_for_Vs.begin()+ssp_wit.num_variables(), + chunks, + true); + leave_block("Compute alpha_V_g1, the 2nd component of the proof", false); + + enter_block("Compute H_g1, the 3rd component of the proof", false); + H_g1 = H_g1 + multi_exp, Fr >(pk.H_g1_query.begin(), pk.H_g1_query.begin()+ssp_wit.degree()+1, + ssp_wit.coefficients_for_H.begin(), ssp_wit.coefficients_for_H.begin()+ssp_wit.degree()+1, + chunks, + true); + leave_block("Compute H_g1, the 3rd component of the proof", false); + + enter_block("Compute V_g2, the 4th component of the proof", false); + V_g2 = V_g2 + multi_exp, Fr >(pk.V_g2_query.begin()+1, pk.V_g2_query.begin()+ssp_wit.num_variables()+1, + ssp_wit.coefficients_for_Vs.begin(), ssp_wit.coefficients_for_Vs.begin()+ssp_wit.num_variables(), + chunks, + true); + leave_block("Compute V_g2, the 4th component of the proof", false); + + leave_block("Compute the proof"); + + leave_block("Call to uscs_ppzksnark_prover"); + + uscs_ppzksnark_proof proof = uscs_ppzksnark_proof(std::move(V_g1), std::move(alpha_V_g1), std::move(H_g1), std::move(V_g2)); + + proof.print_size(); + + return proof; +} + +template +uscs_ppzksnark_processed_verification_key uscs_ppzksnark_verifier_process_vk(const uscs_ppzksnark_verification_key &vk) +{ + enter_block("Call to uscs_ppzksnark_verifier_process_vk"); + + uscs_ppzksnark_processed_verification_key pvk; + + pvk.pp_G1_one_precomp = ppT::precompute_G1(G1::one()); + pvk.pp_G2_one_precomp = ppT::precompute_G2(G2::one()); + + pvk.vk_tilde_g2_precomp = ppT::precompute_G2(vk.tilde_g2); + pvk.vk_alpha_tilde_g2_precomp = ppT::precompute_G2(vk.alpha_tilde_g2); + pvk.vk_Z_g2_precomp = ppT::precompute_G2(vk.Z_g2); + + pvk.pairing_of_g1_and_g2 = ppT::miller_loop(pvk.pp_G1_one_precomp,pvk.pp_G2_one_precomp); + + pvk.encoded_IC_query = vk.encoded_IC_query; + + leave_block("Call to uscs_ppzksnark_verifier_process_vk"); + + return pvk; +} + +template +bool uscs_ppzksnark_online_verifier_weak_IC(const uscs_ppzksnark_processed_verification_key &pvk, + const uscs_ppzksnark_primary_input &primary_input, + const uscs_ppzksnark_proof &proof) +{ + enter_block("Call to uscs_ppzksnark_online_verifier_weak_IC"); + assert(pvk.encoded_IC_query.domain_size() >= primary_input.size()); + + enter_block("Compute input-dependent part of V"); + const accumulation_vector > accumulated_IC = pvk.encoded_IC_query.template accumulate_chunk >(primary_input.begin(), primary_input.end(), 0); + assert(accumulated_IC.is_fully_accumulated()); + const G1 &acc = accumulated_IC.first; + leave_block("Compute input-dependent part of V"); + + bool result = true; + + enter_block("Check if the proof is well-formed"); + if (!proof.is_well_formed()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("At least one of the proof components is not well-formed.\n"); + } + result = false; + } + leave_block("Check if the proof is well-formed"); + + enter_block("Online pairing computations"); + + enter_block("Check knowledge commitment for V is valid"); + G1_precomp proof_V_g1_with_acc_precomp = ppT::precompute_G1(proof.V_g1 + acc); + G2_precomp proof_V_g2_precomp = ppT::precompute_G2(proof.V_g2); + Fqk V_1 = ppT::miller_loop(proof_V_g1_with_acc_precomp, pvk.pp_G2_one_precomp); + Fqk V_2 = ppT::miller_loop(pvk.pp_G1_one_precomp, proof_V_g2_precomp); + GT V = ppT::final_exponentiation(V_1 * V_2.unitary_inverse()); + if (V != GT::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Knowledge commitment for V invalid.\n"); + } + result = false; + } + leave_block("Check knowledge commitment for V is valid"); + + enter_block("Check SSP divisibility"); // i.e., check that V^2=H*Z+1 + G1_precomp proof_H_g1_precomp = ppT::precompute_G1(proof.H_g1); + Fqk SSP_1 = ppT::miller_loop(proof_V_g1_with_acc_precomp, proof_V_g2_precomp); + Fqk SSP_2 = ppT::miller_loop(proof_H_g1_precomp, pvk.vk_Z_g2_precomp); + GT SSP = ppT::final_exponentiation(SSP_1.unitary_inverse() * SSP_2 * pvk.pairing_of_g1_and_g2); + if (SSP != GT::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("SSP divisibility check failed.\n"); + } + result = false; + } + leave_block("Check SSP divisibility"); + + enter_block("Check same coefficients were used"); + G1_precomp proof_V_g1_precomp = ppT::precompute_G1(proof.V_g1); + G1_precomp proof_alpha_V_g1_precomp = ppT::precompute_G1(proof.alpha_V_g1); + Fqk alpha_V_1 = ppT::miller_loop(proof_V_g1_precomp, pvk.vk_alpha_tilde_g2_precomp); + Fqk alpha_V_2 = ppT::miller_loop(proof_alpha_V_g1_precomp, pvk.vk_tilde_g2_precomp); + GT alpha_V = ppT::final_exponentiation(alpha_V_1 * alpha_V_2.unitary_inverse()); + if (alpha_V != GT::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Same-coefficient check failed.\n"); + } + result = false; + } + leave_block("Check same coefficients were used"); + + leave_block("Online pairing computations"); + + leave_block("Call to uscs_ppzksnark_online_verifier_weak_IC"); + + return result; +} + +template +bool uscs_ppzksnark_verifier_weak_IC(const uscs_ppzksnark_verification_key &vk, + const uscs_ppzksnark_primary_input &primary_input, + const uscs_ppzksnark_proof &proof) +{ + enter_block("Call to uscs_ppzksnark_verifier_weak_IC"); + uscs_ppzksnark_processed_verification_key pvk = uscs_ppzksnark_verifier_process_vk(vk); + bool result = uscs_ppzksnark_online_verifier_weak_IC(pvk, primary_input, proof); + leave_block("Call to uscs_ppzksnark_verifier_weak_IC"); + return result; +} + +template +bool uscs_ppzksnark_online_verifier_strong_IC(const uscs_ppzksnark_processed_verification_key &pvk, + const uscs_ppzksnark_primary_input &primary_input, + const uscs_ppzksnark_proof &proof) +{ + bool result = true; + enter_block("Call to uscs_ppzksnark_online_verifier_strong_IC"); + + if (pvk.encoded_IC_query.domain_size() != primary_input.size()) + { + print_indent(); printf("Input length differs from expected (got %zu, expected %zu).\n", primary_input.size(), pvk.encoded_IC_query.domain_size()); + result = false; + } + else + { + result = uscs_ppzksnark_online_verifier_weak_IC(pvk, primary_input, proof); + } + + leave_block("Call to uscs_ppzksnark_online_verifier_strong_IC"); + return result; +} + +template +bool uscs_ppzksnark_verifier_strong_IC(const uscs_ppzksnark_verification_key &vk, + const uscs_ppzksnark_primary_input &primary_input, + const uscs_ppzksnark_proof &proof) +{ + enter_block("Call to uscs_ppzksnark_verifier_strong_IC"); + uscs_ppzksnark_processed_verification_key pvk = uscs_ppzksnark_verifier_process_vk(vk); + bool result = uscs_ppzksnark_online_verifier_strong_IC(pvk, primary_input, proof); + leave_block("Call to uscs_ppzksnark_verifier_strong_IC"); + return result; +} + +} // libsnark + +#endif // USCS_PPZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark_params.hpp b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark_params.hpp new file mode 100644 index 0000000..8cebb5e --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark_params.hpp @@ -0,0 +1,34 @@ +/** @file + ***************************************************************************** + + Declaration of public-parameter selector for the USCS ppzkSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef USCS_PPZKSNARK_PARAMS_HPP_ +#define USCS_PPZKSNARK_PARAMS_HPP_ + +#include "relations/constraint_satisfaction_problems/uscs/uscs.hpp" + +namespace libsnark { + +/** + * Below are various template aliases (used for convenience). + */ + +template +using uscs_ppzksnark_constraint_system = uscs_constraint_system >; + +template +using uscs_ppzksnark_primary_input = uscs_primary_input >; + +template +using uscs_ppzksnark_auxiliary_input = uscs_auxiliary_input >; + +} // libsnark + +#endif // USCS_PPZKSNARK_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/examples/run_ram_zksnark.hpp b/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/examples/run_ram_zksnark.hpp new file mode 100644 index 0000000..db1a34c --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/examples/run_ram_zksnark.hpp @@ -0,0 +1,36 @@ +/** @file + ***************************************************************************** + + Declaration of functionality that runs the RAM zkSNARK for + a given RAM example. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_RAM_ZKSNARK_HPP_ +#define RUN_RAM_ZKSNARK_HPP_ + +#include "relations/ram_computations/rams/examples/ram_examples.hpp" +#include "zk_proof_systems/zksnark/ram_zksnark/ram_zksnark_params.hpp" + +namespace libsnark { + +/** + * Runs the zkSNARK (generator, prover, and verifier) for a given + * RAM example (specified by an architecture, boot trace, auxiliary input, and time bound). + * + * Optionally, also test the serialization routines for keys and proofs. + * (This takes additional time.) + */ +template +bool run_ram_zksnark(const ram_example > &example, + const bool test_serialization); + +} // libsnark + +#include "zk_proof_systems/zksnark/ram_zksnark/examples/run_ram_zksnark.tcc" + +#endif // RUN_RAM_ZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/examples/run_ram_zksnark.tcc b/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/examples/run_ram_zksnark.tcc new file mode 100644 index 0000000..5f16f27 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/examples/run_ram_zksnark.tcc @@ -0,0 +1,83 @@ +/** @file + ***************************************************************************** + + Implementation of functionality that runs the RAM zkSNARK for + a given RAM example. + + See run_ram_zksnark.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_RAM_ZKSNARK_TCC_ +#define RUN_RAM_ZKSNARK_TCC_ + +#include "zk_proof_systems/zksnark/ram_zksnark/ram_zksnark.hpp" + +#include + +#include "common/profiling.hpp" + +namespace libsnark { + +/** + * The code below provides an example of all stages of running a RAM zkSNARK. + * + * Of course, in a real-life scenario, we would have three distinct entities, + * mangled into one in the demonstration below. The three entities are as follows. + * (1) The "generator", which runs the zkSNARK generator on input a given + * architecture. + * (2) The "prover", which runs the zkSNARK prover on input the proving key, + * a boot trace, and an auxiliary input. + * (3) The "verifier", which runs the zkSNARK verifier on input the verification key, + * a boot trace, a time bound, and a proof. + */ +template +bool run_ram_zksnark(const ram_example > &example, + const bool test_serialization) +{ + enter_block("Call to run_ram_zksnark"); + + printf("This run uses an example with the following parameters:\n"); + example.ap.print(); + printf("* Time bound (T): %zu\n", example.time_bound); + + print_header("RAM zkSNARK Generator"); + ram_zksnark_keypair keypair = ram_zksnark_generator(example.ap); + printf("\n"); print_indent(); print_mem("after generator"); + + if (test_serialization) + { + enter_block("Test serialization of keys"); + keypair.pk = reserialize >(keypair.pk); + keypair.vk = reserialize >(keypair.vk); + leave_block("Test serialization of keys"); + } + + print_header("RAM zkSNARK Prover"); + ram_zksnark_proof proof = ram_zksnark_prover(keypair.pk, example.boot_trace, example.time_bound, example.auxiliary_input); + printf("\n"); print_indent(); print_mem("after prover"); + + if (test_serialization) + { + enter_block("Test serialization of proof"); + proof = reserialize >(proof); + leave_block("Test serialization of proof"); + } + + print_header("RAM zkSNARK Verifier"); + bool ans = ram_zksnark_verifier(keypair.vk, example.boot_trace, example.time_bound, proof); + printf("\n"); print_indent(); print_mem("after verifier"); + printf("* The verification result is: %s\n", (ans ? "PASS" : "FAIL")); + + leave_block("Call to run_ram_zksnark"); + + return ans; +} + +} // libsnark + +#endif // RUN_RAM_ZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/profiling/profile_ram_zksnark.cpp b/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/profiling/profile_ram_zksnark.cpp new file mode 100644 index 0000000..da72dff --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/profiling/profile_ram_zksnark.cpp @@ -0,0 +1,178 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include "common/default_types/ram_zksnark_pp.hpp" +#include "relations/ram_computations/memory/examples/memory_contents_examples.hpp" +#include "relations/ram_computations/rams/examples/ram_examples.hpp" +#include "zk_proof_systems/zksnark/ram_zksnark/ram_zksnark.hpp" +#include "zk_proof_systems/zksnark/ram_zksnark/examples/run_ram_zksnark.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_params.hpp" + +#include + +using namespace libsnark; + +template +void simulate_random_memory_contents(const tinyram_architecture_params &ap, const size_t input_size, const size_t program_size) +{ + const size_t num_addresses = 1ul< dm_random(num_addresses, value_size, init_random); + leave_block("Initialize random delegated memory"); +} + +template +void profile_ram_zksnark_verifier(const tinyram_architecture_params &ap, const size_t input_size, const size_t program_size) +{ + typedef ram_zksnark_machine_pp ramT; + const size_t time_bound = 10; + + const size_t boot_trace_size_bound = program_size + input_size; + const ram_example example = gen_ram_example_complex(ap, boot_trace_size_bound, time_bound, true); + + ram_zksnark_proof pi; + ram_zksnark_verification_key vk = ram_zksnark_verification_key::dummy_verification_key(ap); + + enter_block("Verify fake proof"); + ram_zksnark_verifier(vk, example.boot_trace, time_bound, pi); + leave_block("Verify fake proof"); +} + +template +void print_ram_zksnark_verifier_profiling() +{ + inhibit_profiling_info = true; + for (size_t w : { 16, 32 }) + { + const size_t k = 16; + + for (size_t input_size : { 0, 10, 100 }) + { + for (size_t program_size = 10; program_size <= 10000; program_size *= 10) + { + const tinyram_architecture_params ap(w, k); + + profile_ram_zksnark_verifier(ap, input_size, program_size); + + const double input_map = last_times["Call to ram_zksnark_verifier_input_map"]; + const double preprocessing = last_times["Call to r1cs_ppzksnark_verifier_process_vk"]; + const double accumulate = last_times["Call to r1cs_ppzksnark_IC_query::accumulate"]; + const double pairings = last_times["Online pairing computations"]; + const double total = last_times["Call to ram_zksnark_verifier"]; + const double rest = total - (input_map + preprocessing + accumulate + pairings); + + const double delegated_ra_memory_init = last_times["Construct delegated_ra_memory from memory map"]; + simulate_random_memory_contents >(ap, input_size, program_size); + const double delegated_ra_memory_init_random = last_times["Initialize random delegated memory"]; + const double input_map_random = input_map - delegated_ra_memory_init + delegated_ra_memory_init_random; + const double total_random = total - delegated_ra_memory_init + delegated_ra_memory_init_random; + + printf("w = %zu, k = %zu, program_size = %zu, input_size = %zu, input_map = %0.2fms, preprocessing = %0.2fms, accumulate = %0.2fms, pairings = %0.2fms, rest = %0.2fms, total = %0.2fms (input_map_random = %0.2fms, total_random = %0.2fms)\n", + w, k, program_size, input_size, input_map * 1e-6, preprocessing * 1e-6, accumulate * 1e-6, pairings * 1e-6, rest * 1e-6, total * 1e-6, input_map_random * 1e-6, total_random * 1e-6); + } + } + } +} + +template +void profile_ram_zksnark(const tinyram_architecture_params &ap, const size_t program_size, const size_t input_size, const size_t time_bound) +{ + typedef ram_zksnark_machine_pp ramT; + + const size_t boot_trace_size_bound = program_size + input_size; + const ram_example example = gen_ram_example_complex(ap, boot_trace_size_bound, time_bound, true); + const bool test_serialization = true; + const bool bit = run_ram_zksnark(example, test_serialization); + assert(bit); +} + +namespace po = boost::program_options; + +bool process_command_line(const int argc, const char** argv, + bool &profile_gp, + size_t &w, + size_t &k, + bool &profile_v, + size_t &l) +{ + try + { + po::options_description desc("Usage"); + desc.add_options() + ("help", "print this help message") + ("profile_gp", "profile generator and prover") + ("w", po::value(&w)->default_value(16), "word size") + ("k", po::value(&k)->default_value(16), "register count") + ("profile_v", "profile verifier") + ("v", "print version info") + ("l", po::value(&l)->default_value(10), "program length"); + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + + if (vm.count("v")) + { + print_compilation_info(); + exit(0); + } + + if (vm.count("help")) + { + std::cout << desc << "\n"; + return false; + } + + profile_gp = vm.count("profile_gp"); + profile_v = vm.count("profile_v"); + + if (!(vm.count("profile_gp") ^ vm.count("profile_v"))) + { + std::cout << "Must choose between profiling generator/prover and profiling verifier (see --help)\n"; + return false; + } + + po::notify(vm); + } + catch(std::exception& e) + { + std::cerr << "Error: " << e.what() << "\n"; + return false; + } + + return true; +} + +int main(int argc, const char* argv[]) +{ + start_profiling(); + ram_zksnark_PCD_pp::init_public_params(); + + bool profile_gp; + size_t w; + size_t k; + bool profile_v; + size_t l; + + if (!process_command_line(argc, argv, profile_gp, w, k, profile_v, l)) + { + return 1; + } + + tinyram_architecture_params ap(w, k); + + if (profile_gp) + { + profile_ram_zksnark(ap, 100, 100, 10); // w, k, l, n, T + } + + if (profile_v) + { + profile_ram_zksnark_verifier(ap, l/2, l/2); + } +} diff --git a/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/ram_compliance_predicate.hpp b/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/ram_compliance_predicate.hpp new file mode 100644 index 0000000..9265c5a --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/ram_compliance_predicate.hpp @@ -0,0 +1,248 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a compliance predicate for RAM. + + The implementation follows, extends, and optimizes the approach described + in \[BCTV14]. + + Essentially, the RAM's CPU, which is expressed as an R1CS constraint system, + is augmented to obtain another R1CS constraint ssytem that implements a RAM + compliance predicate. This predicate is responsible for checking: + (1) transitions from a CPU state to the next; + (2) correct load/stores; and + (3) corner cases such as the first and last steps of the machine. + The first can be done by suitably embedding the RAM's CPU in the constraint + system. The second can be done by verifying authentication paths for the values + of memory. The third mostly consists of bookkeepng (with some subtleties arising + from the need to not break zero knowledge). + + The laying out of R1CS constraints is done via gadgetlib1 (a minimalistic + library for writing R1CS constraint systems). + + References: + + \[BCTV14]: + "Scalable Zero Knowledge via Cycles of Elliptic Curves", + Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, + CRYPTO 2014, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_COMPLIANCE_PREDICATE_HPP_ +#define RAM_COMPLIANCE_PREDICATE_HPP_ + +#include "gadgetlib1/gadgets/delegated_ra_memory/memory_load_gadget.hpp" +#include "gadgetlib1/gadgets/delegated_ra_memory/memory_load_store_gadget.hpp" +#include "relations/ram_computations/memory/delegated_ra_memory.hpp" +#include "relations/ram_computations/rams/ram_params.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/cp_handler.hpp" + +namespace libsnark { + +/** + * A RAM message specializes the generic PCD message, in order to + * obtain a more user-friendly print method. + */ +template +class ram_pcd_message : public r1cs_pcd_message > { +private: + void print_bits(const bit_vector &bv) const; + +public: + typedef ram_base_field FieldT; + + ram_architecture_params ap; + + size_t timestamp; + bit_vector root_initial; + bit_vector root; + size_t pc_addr; + bit_vector cpu_state; + size_t pc_addr_initial; + bit_vector cpu_state_initial; + bool has_accepted; + + ram_pcd_message(const size_t type, + const ram_architecture_params &ap, + const size_t timestamp, + const bit_vector root_initial, + const bit_vector root, + const size_t pc_addr, + const bit_vector cpu_state, + const size_t pc_addr_initial, + const bit_vector cpu_state_initial, + const bool has_accepted); + + bit_vector unpacked_payload_as_bits() const; + r1cs_variable_assignment payload_as_r1cs_variable_assignment() const; + void print() const; + + static size_t unpacked_payload_size_in_bits(const ram_architecture_params &ap); +}; + +template +class ram_pcd_message_variable : public r1cs_pcd_message_variable > { +public: + ram_architecture_params ap; + + typedef ram_base_field FieldT; + + pb_variable_array packed_payload; + + pb_variable_array timestamp; + pb_variable_array root_initial; + pb_variable_array root; + pb_variable_array pc_addr; + pb_variable_array cpu_state; + pb_variable_array pc_addr_initial; + pb_variable_array cpu_state_initial; + pb_variable has_accepted; + + pb_variable_array all_unpacked_vars; + + std::shared_ptr > unpack_payload; + + ram_pcd_message_variable(protoboard &pb, + const ram_architecture_params &ap, + const std::string &annotation_prefix); + + void allocate_unpacked_part(); + void generate_r1cs_constraints(); + void generate_r1cs_witness_from_bits(); + void generate_r1cs_witness_from_packed(); + + std::shared_ptr > get_message() const; +}; + +template +class ram_pcd_local_data : public r1cs_pcd_local_data > { +public: + typedef ram_base_field FieldT; + + bool is_halt_case; + + delegated_ra_memory > &mem; + typename ram_input_tape::const_iterator &aux_it; + const typename ram_input_tape::const_iterator &aux_end; + + ram_pcd_local_data(const bool is_halt_case, + delegated_ra_memory > &mem, + typename ram_input_tape::const_iterator &aux_it, + const typename ram_input_tape::const_iterator &aux_end); + + r1cs_variable_assignment as_r1cs_variable_assignment() const; +}; + +template +class ram_pcd_local_data_variable : public r1cs_pcd_local_data_variable > { +public: + typedef ram_base_field FieldT; + + pb_variable is_halt_case; + + ram_pcd_local_data_variable(protoboard &pb, + const std::string &annotation_prefix); +}; + +/** + * A RAM compliance predicate. + */ +template +class ram_compliance_predicate_handler : public compliance_predicate_handler, ram_protoboard > { +protected: + + ram_architecture_params ap; + +public: + + typedef ram_base_field FieldT; + typedef CRH_with_bit_out_gadget HashT; + typedef compliance_predicate_handler, ram_protoboard > base_handler; + + std::shared_ptr > next; + std::shared_ptr > cur; +private: + + pb_variable zero; // TODO: promote linear combinations to first class objects + std::shared_ptr > copy_root_initial; + std::shared_ptr > copy_pc_addr_initial; + std::shared_ptr > copy_cpu_state_initial; + + pb_variable is_base_case; + pb_variable is_not_halt_case; + + pb_variable packed_cur_timestamp; + std::shared_ptr > pack_cur_timestamp; + pb_variable packed_next_timestamp; + std::shared_ptr > pack_next_timestamp; + + pb_variable_array zero_cpu_state; + pb_variable_array zero_pc_addr; + pb_variable_array zero_root; + + std::shared_ptr > initialize_cur_cpu_state; + std::shared_ptr > initialize_prev_pc_addr; + + std::shared_ptr > initialize_root; + + pb_variable_array prev_pc_val; + std::shared_ptr > prev_pc_val_digest; + std::shared_ptr > cur_root_digest; + std::shared_ptr > instruction_fetch_merkle_proof; + std::shared_ptr > instruction_fetch; + + std::shared_ptr > next_root_digest; + + pb_variable_array ls_addr; + pb_variable_array ls_prev_val; + pb_variable_array ls_next_val; + std::shared_ptr > ls_prev_val_digest; + std::shared_ptr > ls_next_val_digest; + std::shared_ptr > load_merkle_proof; + std::shared_ptr > store_merkle_proof; + std::shared_ptr > load_store_checker; + + pb_variable_array temp_next_pc_addr; + pb_variable_array temp_next_cpu_state; + std::shared_ptr > cpu_checker; + + pb_variable do_halt; + std::shared_ptr > clear_next_root; + std::shared_ptr > clear_next_pc_addr; + std::shared_ptr > clear_next_cpu_state; + + std::shared_ptr > copy_temp_next_root; + std::shared_ptr > copy_temp_next_pc_addr; + std::shared_ptr > copy_temp_next_cpu_state; + +public: + const size_t addr_size; + const size_t value_size; + const size_t digest_size; + + size_t message_length; + + ram_compliance_predicate_handler(const ram_architecture_params &ap); + void generate_r1cs_constraints(); + void generate_r1cs_witness(const std::vector > > &incoming_message_values, + const std::shared_ptr > &local_data_value); + + static std::shared_ptr > get_base_case_message(const ram_architecture_params &ap, + const ram_boot_trace &primary_input); + static std::shared_ptr > get_final_case_msg(const ram_architecture_params &ap, + const ram_boot_trace &primary_input, + const size_t time_bound); +}; + +} // libsnark + +#include "zk_proof_systems/zksnark/ram_zksnark/ram_compliance_predicate.tcc" + +#endif // RAM_COMPLIANCE_PREDICATE_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/ram_compliance_predicate.tcc b/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/ram_compliance_predicate.tcc new file mode 100644 index 0000000..cbaf8a2 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/ram_compliance_predicate.tcc @@ -0,0 +1,715 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a compliance predicate for RAM. + + See ram_compliance_predicate.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_COMPLIANCE_PREDICATE_TCC_ +#define RAM_COMPLIANCE_PREDICATE_TCC_ + +namespace libsnark { + +template +ram_pcd_message::ram_pcd_message(const size_t type, + const ram_architecture_params &ap, + const size_t timestamp, + const bit_vector root_initial, + const bit_vector root, + const size_t pc_addr, + const bit_vector cpu_state, + const size_t pc_addr_initial, + const bit_vector cpu_state_initial, + const bool has_accepted) : + r1cs_pcd_message(type), + ap(ap), + timestamp(timestamp), + root_initial(root_initial), + root(root), + pc_addr(pc_addr), + cpu_state(cpu_state), + pc_addr_initial(pc_addr_initial), + cpu_state_initial(cpu_state_initial), + has_accepted(has_accepted) +{ + const size_t digest_size = CRH_with_bit_out_gadget::get_digest_len(); + assert(log2(timestamp) < ramT::timestamp_length); + assert(root_initial.size() == digest_size); + assert(root.size() == digest_size); + assert(log2(pc_addr) < ap.address_size()); + assert(cpu_state.size() == ap.cpu_state_size()); + assert(log2(pc_addr_initial) < ap.address_size()); + assert(cpu_state_initial.size() == ap.cpu_state_size()); +} + +template +bit_vector ram_pcd_message::unpacked_payload_as_bits() const +{ + bit_vector result; + + const bit_vector timestamp_bits = convert_field_element_to_bit_vector(FieldT(timestamp), ramT::timestamp_length); + const bit_vector pc_addr_bits = convert_field_element_to_bit_vector(FieldT(pc_addr), ap.address_size()); + const bit_vector pc_addr_initial_bits = convert_field_element_to_bit_vector(FieldT(pc_addr_initial), ap.address_size()); + + result.insert(result.end(), timestamp_bits.begin(), timestamp_bits.end()); + result.insert(result.end(), root_initial.begin(), root_initial.end()); + result.insert(result.end(), root.begin(), root.end()); + result.insert(result.end(), pc_addr_bits.begin(), pc_addr_bits.end()); + result.insert(result.end(), cpu_state.begin(), cpu_state.end()); + result.insert(result.end(), pc_addr_initial_bits.begin(), pc_addr_initial_bits.end()); + result.insert(result.end(), cpu_state_initial.begin(), cpu_state_initial.end()); + result.insert(result.end(), has_accepted); + + assert(result.size() == unpacked_payload_size_in_bits(ap)); + return result; +} + +template +r1cs_variable_assignment > ram_pcd_message::payload_as_r1cs_variable_assignment() const +{ + const bit_vector payload_bits = unpacked_payload_as_bits(); + const r1cs_variable_assignment result = pack_bit_vector_into_field_element_vector(payload_bits); + return result; +} + +template +void ram_pcd_message::print_bits(const bit_vector &bv) const +{ + for (bool b : bv) + { + printf("%d", b ? 1 : 0); + } + printf("\n"); +} + +template +void ram_pcd_message::print() const +{ + printf("ram_pcd_message:\n"); + printf(" type: %zu\n", this->type); + printf(" timestamp: %zu\n", timestamp); + printf(" root_initial: "); + print_bits(root_initial); + printf(" root: "); + print_bits(root); + printf(" pc_addr: %zu\n", pc_addr); + printf(" cpu_state: "); + print_bits(cpu_state); + printf(" pc_addr_initial: %zu\n", pc_addr_initial); + printf(" cpu_state_initial: "); + print_bits(cpu_state_initial); + printf(" has_accepted: %s\n", has_accepted ? "YES" : "no"); +} + +template +size_t ram_pcd_message::unpacked_payload_size_in_bits(const ram_architecture_params &ap) +{ + const size_t digest_size = CRH_with_bit_out_gadget::get_digest_len(); + + return (ramT::timestamp_length + // timestamp + 2*digest_size + // root, root_initial + 2*ap.address_size() + // pc_addr, pc_addr_initial + 2*ap.cpu_state_size() + // cpu_state, cpu_state_initial + 1); // has_accepted +} + +template +ram_pcd_message_variable::ram_pcd_message_variable(protoboard &pb, + const ram_architecture_params &ap, + const std::string &annotation_prefix) : + r1cs_pcd_message_variable >(pb, annotation_prefix), ap(ap) +{ + const size_t unpacked_payload_size_in_bits = ram_pcd_message::unpacked_payload_size_in_bits(ap); + const size_t packed_payload_size = div_ceil(unpacked_payload_size_in_bits, FieldT::capacity()); + packed_payload.allocate(pb, packed_payload_size, FMT(annotation_prefix, " packed_payload")); + + this->update_all_vars(); +} + +template +void ram_pcd_message_variable::allocate_unpacked_part() +{ + const size_t digest_size = CRH_with_bit_out_gadget::get_digest_len(); + + timestamp.allocate(this->pb, ramT::timestamp_length, FMT(this->annotation_prefix, " timestamp")); + root_initial.allocate(this->pb, digest_size, FMT(this->annotation_prefix, " root_initial")); + root.allocate(this->pb, digest_size, FMT(this->annotation_prefix, " root")); + pc_addr.allocate(this->pb, ap.address_size(), FMT(this->annotation_prefix, " pc_addr")); + cpu_state.allocate(this->pb, ap.cpu_state_size(), FMT(this->annotation_prefix, " cpu_state")); + pc_addr_initial.allocate(this->pb, ap.address_size(), FMT(this->annotation_prefix, " pc_addr_initial")); + cpu_state_initial.allocate(this->pb, ap.cpu_state_size(), FMT(this->annotation_prefix, " cpu_state_initial")); + has_accepted.allocate(this->pb, FMT(this->annotation_prefix, " has_accepted")); + + all_unpacked_vars.insert(all_unpacked_vars.end(), timestamp.begin(), timestamp.end()); + all_unpacked_vars.insert(all_unpacked_vars.end(), root_initial.begin(), root_initial.end()); + all_unpacked_vars.insert(all_unpacked_vars.end(), root.begin(), root.end()); + all_unpacked_vars.insert(all_unpacked_vars.end(), pc_addr.begin(), pc_addr.end()); + all_unpacked_vars.insert(all_unpacked_vars.end(), cpu_state.begin(), cpu_state.end()); + all_unpacked_vars.insert(all_unpacked_vars.end(), pc_addr_initial.begin(), pc_addr_initial.end()); + all_unpacked_vars.insert(all_unpacked_vars.end(), cpu_state_initial.begin(), cpu_state_initial.end()); + all_unpacked_vars.insert(all_unpacked_vars.end(), has_accepted); + + unpack_payload.reset(new multipacking_gadget(this->pb, all_unpacked_vars, packed_payload, FieldT::capacity(), FMT(this->annotation_prefix, " unpack_payload"))); +} + +template +void ram_pcd_message_variable::generate_r1cs_witness_from_bits() +{ + unpack_payload->generate_r1cs_witness_from_bits(); +} + +template +void ram_pcd_message_variable::generate_r1cs_witness_from_packed() +{ + unpack_payload->generate_r1cs_witness_from_packed(); +} + +template +void ram_pcd_message_variable::generate_r1cs_constraints() +{ + unpack_payload->generate_r1cs_constraints(true); +} + +template +std::shared_ptr > > ram_pcd_message_variable::get_message() const +{ + const size_t type_val = this->pb.val(this->type).as_ulong(); + const size_t timestamp_val = timestamp.get_field_element_from_bits(this->pb).as_ulong(); + const bit_vector root_initial_val = root_initial.get_bits(this->pb); + const bit_vector root_val = root.get_bits(this->pb); + const size_t pc_addr_val = pc_addr.get_field_element_from_bits(this->pb).as_ulong(); + const bit_vector cpu_state_val = cpu_state.get_bits(this->pb); + const size_t pc_addr_initial_val = pc_addr_initial.get_field_element_from_bits(this->pb).as_ulong(); + const bit_vector cpu_state_initial_val = cpu_state_initial.get_bits(this->pb); + const bool has_accepted_val = (this->pb.val(has_accepted) == FieldT::one()); + + std::shared_ptr > result; + result.reset(new ram_pcd_message(type_val, + ap, + timestamp_val, + root_initial_val, + root_val, + pc_addr_val, + cpu_state_val, + pc_addr_initial_val, + cpu_state_initial_val, + has_accepted_val)); + return result; +} + +template +ram_pcd_local_data::ram_pcd_local_data(const bool is_halt_case, + delegated_ra_memory > &mem, + typename ram_input_tape::const_iterator &aux_it, + const typename ram_input_tape::const_iterator &aux_end) : + is_halt_case(is_halt_case), mem(mem), aux_it(aux_it), aux_end(aux_end) +{ +} + +template +r1cs_variable_assignment > ram_pcd_local_data::as_r1cs_variable_assignment() const +{ + r1cs_variable_assignment result; + result.emplace_back(is_halt_case ? FieldT::one() : FieldT::zero()); + return result; +} + +template +ram_pcd_local_data_variable::ram_pcd_local_data_variable(protoboard &pb, + const std::string &annotation_prefix) : + r1cs_pcd_local_data_variable >(pb, annotation_prefix) +{ + is_halt_case.allocate(pb, FMT(annotation_prefix, " is_halt_case")); + + this->update_all_vars(); +} + +/* + We need to perform the following checks: + + Always: + next.root_initial = cur.root_initial + next.pc_addr_init = cur.pc_addr_initial + next.cpu_state_initial = cur.cpu_state_initial + + If is_is_base_case = 1: (base case) + that cur.timestamp = 0, cur.cpu_state = cpu_state_init, cur.pc_addr = pc_addr_initial, cur.has_accepted = 0 + that cur.root = cur.root_initial + + If do_halt = 0: (regular case) + that instruction fetch was correctly executed + next.timestamp = cur.timestamp + 1 + that CPU accepted on (cur, temp) + that load-then-store was correctly handled + that next.root = temp.root, next.cpu_state = temp.cpu_state, next.pc_addr = temp.pc_addr + + If do_halt = 1: (final case) + that cur.has_accepted = 1 + that next.root = 0, next.cpu_state = 0, next.pc_addr = 0 + that next.timestamp = cur.timestamp and next.has_accepted = cur.has_accepted +*/ + +template +ram_compliance_predicate_handler::ram_compliance_predicate_handler(const ram_architecture_params &ap) : + compliance_predicate_handler, ram_protoboard >(ram_protoboard(ap), + 100, + 1, + 1, + true, + std::set{1}), + ap(ap), + addr_size(ap.address_size()), + value_size(ap.value_size()), + digest_size(CRH_with_bit_out_gadget::get_digest_len()) +{ + // TODO: assert that message has fields of lengths consistent with num_addresses/value_size (as a method for ram_message) + // choose a constant for timestamp_len + // check that value_size <= digest_size; digest_size is not assumed to fit in chunk size (more precisely, it is handled correctly in the other gadgets). + // check if others fit (timestamp_length, value_size, addr_size) + + // the variables allocated are: next, cur, local data (nil for us), is_base_case, witness + + this->outgoing_message.reset(new ram_pcd_message_variable(this->pb, ap, "outgoing_message")); + this->arity.allocate(this->pb, "arity"); + this->incoming_messages[0].reset(new ram_pcd_message_variable(this->pb, ap, "incoming_message")); + this->local_data.reset(new ram_pcd_local_data_variable(this->pb, "local_data")); + + is_base_case.allocate(this->pb, "is_base_case"); + + next = std::dynamic_pointer_cast >(this->outgoing_message); + cur = std::dynamic_pointer_cast >(this->incoming_messages[0]); + + next->allocate_unpacked_part(); + cur->allocate_unpacked_part(); + + // work-around for bad linear combination handling + zero.allocate(this->pb, "zero"); // will go away when we properly support linear terms + + temp_next_pc_addr.allocate(this->pb, addr_size, "temp_next_pc_addr"); + temp_next_cpu_state.allocate(this->pb, ap.cpu_state_size(), "temp_next_cpu_state"); + + const size_t chunk_size = FieldT::capacity(); + + /* + Always: + next.root_initial = cur.root_initial + next.pc_addr_init = cur.pc_addr_initial + next.cpu_state_initial = cur.cpu_state_initial + */ + copy_root_initial.reset(new bit_vector_copy_gadget(this->pb, cur->root_initial, next->root_initial, ONE, chunk_size, "copy_root_initial")); + copy_pc_addr_initial.reset(new bit_vector_copy_gadget(this->pb, cur->pc_addr_initial, next->pc_addr_initial, ONE, chunk_size, "copy_pc_addr_initial")); + copy_cpu_state_initial.reset(new bit_vector_copy_gadget(this->pb, cur->cpu_state_initial, next->cpu_state_initial, ONE, chunk_size, "copy_cpu_state_initial")); + + /* + If is_base_case = 1: (base case) + that cur.timestamp = 0, cur.cpu_state = 0, cur.pc_addr = 0, cur.has_accepted = 0 + that cur.root = cur.root_initial + */ + packed_cur_timestamp.allocate(this->pb, "packed_cur_timestamp"); + pack_cur_timestamp.reset(new packing_gadget(this->pb, cur->timestamp, packed_cur_timestamp, "pack_cur_timestamp")); + + zero_cpu_state = pb_variable_array(cur->cpu_state.size(), zero); + zero_pc_addr = pb_variable_array(cur->pc_addr.size(), zero); + + initialize_cur_cpu_state.reset(new bit_vector_copy_gadget(this->pb, cur->cpu_state_initial, cur->cpu_state, is_base_case, chunk_size, "initialize_cur_cpu_state")); + initialize_prev_pc_addr.reset(new bit_vector_copy_gadget(this->pb, cur->pc_addr_initial, cur->pc_addr, is_base_case, chunk_size, "initialize_prev_pc_addr")); + + initialize_root.reset(new bit_vector_copy_gadget(this->pb, cur->root_initial, cur->root, is_base_case, chunk_size, "initialize_root")); + /* + If do_halt = 0: (regular case) + that instruction fetch was correctly executed + next.timestamp = cur.timestamp + 1 + that CPU accepted on (cur, next) + that load-then-store was correctly handled + */ + is_not_halt_case.allocate(this->pb, "is_not_halt_case"); + // for performing instruction fetch + prev_pc_val.allocate(this->pb, value_size, "prev_pc_val"); + prev_pc_val_digest.reset(new digest_variable(this->pb, digest_size, prev_pc_val, zero, "prev_pc_val_digest")); + cur_root_digest.reset(new digest_variable(this->pb, digest_size, cur->root, zero, "cur_root_digest")); + instruction_fetch_merkle_proof.reset(new merkle_authentication_path_variable(this->pb, addr_size, "instruction_fetch_merkle_proof")); + instruction_fetch.reset(new memory_load_gadget(this->pb, addr_size, + cur->pc_addr, + *prev_pc_val_digest, + *cur_root_digest, + *instruction_fetch_merkle_proof, + ONE, + "instruction_fetch")); + + // for next.timestamp = cur.timestamp + 1 + packed_next_timestamp.allocate(this->pb, "packed_next_timestamp"); + pack_next_timestamp.reset(new packing_gadget(this->pb, next->timestamp, packed_next_timestamp, "pack_next_timestamp")); + + // that CPU accepted on (cur, temp) + ls_addr.allocate(this->pb, addr_size, "ls_addr"); + ls_prev_val.allocate(this->pb, value_size, "ls_prev_val"); + ls_next_val.allocate(this->pb, value_size, "ls_next_val"); + cpu_checker.reset(new ram_cpu_checker(this->pb, cur->pc_addr, prev_pc_val, cur->cpu_state, + ls_addr, ls_prev_val, ls_next_val, + temp_next_cpu_state, temp_next_pc_addr, next->has_accepted, + "cpu_checker")); + + // that load-then-store was correctly handled + ls_prev_val_digest.reset(new digest_variable(this->pb, digest_size, ls_prev_val, zero, "ls_prev_val_digest")); + ls_next_val_digest.reset(new digest_variable(this->pb, digest_size, ls_next_val, zero, "ls_next_val_digest")); + next_root_digest.reset(new digest_variable(this->pb, digest_size, next->root, zero, "next_root_digest")); + load_merkle_proof.reset(new merkle_authentication_path_variable(this->pb, addr_size, "load_merkle_proof")); + store_merkle_proof.reset(new merkle_authentication_path_variable(this->pb, addr_size, "store_merkle_proof")); + load_store_checker.reset(new memory_load_store_gadget(this->pb, addr_size, ls_addr, + *ls_prev_val_digest, *cur_root_digest, *load_merkle_proof, + *ls_next_val_digest, *next_root_digest, *store_merkle_proof, is_not_halt_case, + "load_store_checker")); + /* + If do_halt = 1: (final case) + that cur.has_accepted = 1 + that next.root = 0, next.cpu_state = 0, next.pc_addr = 0 + that next.timestamp = cur.timestamp and next.has_accepted = cur.has_accepted + */ + do_halt.allocate(this->pb, "do_halt"); + zero_root = pb_variable_array(next->root.size(), zero); + clear_next_root.reset(new bit_vector_copy_gadget(this->pb, zero_root, next->root, do_halt, chunk_size, "clear_next_root")); + clear_next_pc_addr.reset(new bit_vector_copy_gadget(this->pb, zero_pc_addr, next->pc_addr, do_halt, chunk_size, "clear_next_pc_addr")); + clear_next_cpu_state.reset(new bit_vector_copy_gadget(this->pb, zero_cpu_state, next->cpu_state, do_halt, chunk_size, "clear_cpu_state")); + + copy_temp_next_pc_addr.reset(new bit_vector_copy_gadget(this->pb, temp_next_pc_addr, next->pc_addr, is_not_halt_case, chunk_size, "copy_temp_next_pc_addr")); + copy_temp_next_cpu_state.reset(new bit_vector_copy_gadget(this->pb, temp_next_cpu_state, next->cpu_state, is_not_halt_case, chunk_size, "copy_temp_next_cpu_state")); +} + +template +void ram_compliance_predicate_handler::generate_r1cs_constraints() +{ + print_indent(); printf("* Message size: %zu\n", next->all_vars.size()); + print_indent(); printf("* Address size: %zu\n", addr_size); + print_indent(); printf("* CPU state size: %zu\n", ap.cpu_state_size()); + print_indent(); printf("* Digest size: %zu\n", digest_size); + + PROFILE_CONSTRAINTS(this->pb, "handle next_type, arity and cur_type") + { + generate_r1cs_equals_const_constraint(this->pb, next->type, FieldT::one(), "next_type"); + generate_r1cs_equals_const_constraint(this->pb, this->arity, FieldT::one(), "arity"); + this->pb.add_r1cs_constraint(r1cs_constraint(is_base_case, cur->type, 0), "nonzero_cur_type_implies_base_case_0"); + generate_boolean_r1cs_constraint(this->pb, cur->type, "cur_type_boolean"); + generate_boolean_r1cs_constraint(this->pb, is_base_case, "is_base_case_boolean"); + } + + PROFILE_CONSTRAINTS(this->pb, "unpack messages") + { + next->generate_r1cs_constraints(); + cur->generate_r1cs_constraints(); + } + + // work-around for bad linear combination handling + generate_r1cs_equals_const_constraint(this->pb, zero, FieldT::zero(), " zero"); + + /* recall that Booleanity of PCD messages has already been enforced by the PCD machine, which is explains the absence of Booleanity checks */ + /* + We need to perform the following checks: + + Always: + next.root_initial = cur.root_initial + next.pc_addr_init = cur.pc_addr_initial + next.cpu_state_initial = cur.cpu_state_initial + */ + PROFILE_CONSTRAINTS(this->pb, "copy root_initial") + { + copy_root_initial->generate_r1cs_constraints(false, false); + } + + PROFILE_CONSTRAINTS(this->pb, "copy pc_addr_initial and cpu_state_initial") + { + copy_pc_addr_initial->generate_r1cs_constraints(false, false); + copy_cpu_state_initial->generate_r1cs_constraints(false, false); + } + + /* + If is_base_case = 1: (base case) + that cur.timestamp = 0, cur.cpu_state = 0, cur.pc_addr = 0, cur.has_accepted = 0 + that cur.root = cur.root_initial + */ + pack_cur_timestamp->generate_r1cs_constraints(false); + this->pb.add_r1cs_constraint(r1cs_constraint(is_base_case, packed_cur_timestamp, 0), "clear_ts_on_is_base_case"); + PROFILE_CONSTRAINTS(this->pb, "copy cur_cpu_state and prev_pc_addr") + { + initialize_cur_cpu_state->generate_r1cs_constraints(false, false); + initialize_prev_pc_addr->generate_r1cs_constraints(false, false); + } + this->pb.add_r1cs_constraint(r1cs_constraint(is_base_case, cur->has_accepted, 0), "is_base_case_is_not_accepting"); + PROFILE_CONSTRAINTS(this->pb, "initialize root") + { + initialize_root->generate_r1cs_constraints(false, false); + } + + /* + If do_halt = 0: (regular case) + that instruction fetch was correctly executed + next.timestamp = cur.timestamp + 1 + that CPU accepted on (cur, next) + that load-then-store was correctly handled + that next.root = temp.root, next.cpu_state = temp.cpu_state, next.pc_addr = temp.pc_addr + */ + this->pb.add_r1cs_constraint(r1cs_constraint(1, 1 - do_halt, is_not_halt_case), "is_not_halt_case"); + PROFILE_CONSTRAINTS(this->pb, "instruction fetch") + { + instruction_fetch_merkle_proof->generate_r1cs_constraints(); + instruction_fetch->generate_r1cs_constraints(); + } + pack_next_timestamp->generate_r1cs_constraints(false); + this->pb.add_r1cs_constraint(r1cs_constraint(is_not_halt_case, (packed_cur_timestamp + 1) - packed_next_timestamp, 0), "increment_timestamp"); + PROFILE_CONSTRAINTS(this->pb, "CPU checker") + { + cpu_checker->generate_r1cs_constraints(); + } + PROFILE_CONSTRAINTS(this->pb, "load/store checker") + { + // See comment in merkle_tree_check_update_gadget::generate_r1cs_witness() for why we don't need to call store_merkle_proof->generate_r1cs_constraints() + load_merkle_proof->generate_r1cs_constraints(); + load_store_checker->generate_r1cs_constraints(); + } + + PROFILE_CONSTRAINTS(this->pb, "copy temp_next_pc_addr and temp_next_cpu_state") + { + copy_temp_next_pc_addr->generate_r1cs_constraints(true, false); + copy_temp_next_cpu_state->generate_r1cs_constraints(true, false); + } + + /* + If do_halt = 1: (final case) + that cur.has_accepted = 1 + that next.root = 0, next.cpu_state = 0, next.pc_addr = 0 + that next.timestamp = cur.timestamp and next.has_accepted = cur.has_accepted + */ + this->pb.add_r1cs_constraint(r1cs_constraint(do_halt, 1 - cur->has_accepted, 0), "final_case_must_be_accepting"); + + PROFILE_CONSTRAINTS(this->pb, "clear next root") + { + clear_next_root->generate_r1cs_constraints(false, false); + } + + PROFILE_CONSTRAINTS(this->pb, "clear next_pc_addr and next_cpu_state") + { + clear_next_pc_addr->generate_r1cs_constraints(false, false); + clear_next_cpu_state->generate_r1cs_constraints(false, false); + } + + this->pb.add_r1cs_constraint(r1cs_constraint(do_halt, packed_cur_timestamp - packed_next_timestamp, 0), "equal_ts_on_halt"); + + const size_t accounted = PRINT_CONSTRAINT_PROFILING(); + const size_t total = this->pb.num_constraints(); + print_indent(); printf("* Unaccounted constraints: %zu\n", total - accounted); + print_indent(); printf("* Number of constraints in ram_compliance_predicate: %zu\n", total); +} + +template +void ram_compliance_predicate_handler::generate_r1cs_witness(const std::vector > > &incoming_message_values, + const std::shared_ptr > &local_data_value) +{ + const std::shared_ptr > ram_local_data_value = std::dynamic_pointer_cast >(local_data_value); + assert(ram_local_data_value->mem.num_addresses == 1ul << addr_size); // check value_size and num_addresses too + + base_handler::generate_r1cs_witness(incoming_message_values, local_data_value); + cur->generate_r1cs_witness_from_packed(); + + this->pb.val(next->type) = FieldT::one(); + this->pb.val(this->arity) = FieldT::one(); + this->pb.val(is_base_case) = (this->pb.val(cur->type) == FieldT::zero() ? FieldT::one() : FieldT::zero()); + + this->pb.val(zero) = FieldT::zero(); + /* + Always: + next.root_initial = cur.root_initial + next.pc_addr_init = cur.pc_addr_initial + next.cpu_state_initial = cur.cpu_state_initial + */ + copy_root_initial->generate_r1cs_witness(); + for (size_t i = 0 ; i < next->root_initial.size(); ++i) + { + this->pb.val(cur->root_initial[i]).print(); + this->pb.val(next->root_initial[i]).print(); + assert(this->pb.val(cur->root_initial[i]) == this->pb.val(next->root_initial[i])); + } + + copy_pc_addr_initial->generate_r1cs_witness(); + copy_cpu_state_initial->generate_r1cs_witness(); + + /* + If is_base_case = 1: (base case) + that cur.timestamp = 0, cur.cpu_state = 0, cur.pc_addr = 0, cur.has_accepted = 0 + that cur.root = cur.root_initial + */ + const bool base_case = (incoming_message_values[0]->type == 0); + this->pb.val(is_base_case) = base_case ? FieldT::one() : FieldT::zero(); + + initialize_cur_cpu_state->generate_r1cs_witness(); + initialize_prev_pc_addr->generate_r1cs_witness(); + + if (base_case) + { + this->pb.val(packed_cur_timestamp) = FieldT::zero(); + this->pb.val(cur->has_accepted) = FieldT::zero(); + pack_cur_timestamp->generate_r1cs_witness_from_packed(); + } + else + { + pack_cur_timestamp->generate_r1cs_witness_from_bits(); + } + + initialize_root->generate_r1cs_witness(); + + /* + If do_halt = 0: (regular case) + that instruction fetch was correctly executed + next.timestamp = cur.timestamp + 1 + that CPU accepted on (cur, temp) + that load-then-store was correctly handled + */ + this->pb.val(do_halt) = ram_local_data_value->is_halt_case ? FieldT::one() : FieldT::zero(); + this->pb.val(is_not_halt_case) = FieldT::one() - this->pb.val(do_halt); + + // that instruction fetch was correctly executed + const size_t int_pc_addr = convert_bit_vector_to_field_element(cur->pc_addr.get_bits(this->pb)).as_ulong(); + const size_t int_pc_val = ram_local_data_value->mem.get_value(int_pc_addr); +#ifdef DEBUG + printf("pc_addr (in units) = %zu, pc_val = %zu (0x%08zx)\n", int_pc_addr, int_pc_val, int_pc_val); +#endif + bit_vector pc_val_bv = int_list_to_bits({ int_pc_val }, value_size); + std::reverse(pc_val_bv.begin(), pc_val_bv.end()); + + prev_pc_val.fill_with_bits(this->pb, pc_val_bv); + const merkle_authentication_path pc_path = ram_local_data_value->mem.get_path(int_pc_addr); + instruction_fetch_merkle_proof->generate_r1cs_witness(int_pc_addr, pc_path); + instruction_fetch->generate_r1cs_witness(); + + // next.timestamp = cur.timestamp + 1 (or cur.timestamp if do_halt) + this->pb.val(packed_next_timestamp) = this->pb.val(packed_cur_timestamp) + this->pb.val(is_not_halt_case); + pack_next_timestamp->generate_r1cs_witness_from_packed(); + + // that CPU accepted on (cur, temp) + // Step 1: Get address and old witnesses for delegated memory. + cpu_checker->generate_r1cs_witness_address(); + const size_t int_ls_addr = ls_addr.get_field_element_from_bits(this->pb).as_ulong(); + const size_t int_ls_prev_val = ram_local_data_value->mem.get_value(int_ls_addr); + const merkle_authentication_path prev_path = ram_local_data_value->mem.get_path(int_ls_addr); + ls_prev_val.fill_with_bits_of_ulong(this->pb, int_ls_prev_val); + assert(ls_prev_val.get_field_element_from_bits(this->pb) == FieldT(int_ls_prev_val, true)); + // Step 2: Execute CPU checker and delegated memory + cpu_checker->generate_r1cs_witness_other(ram_local_data_value->aux_it, ram_local_data_value->aux_end); +#ifdef DEBUG + printf("Debugging information from transition function:\n"); + cpu_checker->dump(); +#endif + const size_t int_ls_next_val = ls_next_val.get_field_element_from_bits(this->pb).as_ulong(); + ram_local_data_value->mem.set_value(int_ls_addr, int_ls_next_val); +#ifdef DEBUG + printf("Memory location %zu changed from %zu (0x%08zx) to %zu (0x%08zx)\n", int_ls_addr, int_ls_prev_val, int_ls_prev_val, int_ls_next_val, int_ls_next_val); +#endif + // Step 4: Use both to satisfy load_store_checker + load_merkle_proof->generate_r1cs_witness(int_ls_addr, prev_path); + load_store_checker->generate_r1cs_witness(); + + /* + If do_halt = 1: (final case) + that cur.has_accepted = 1 + that next.root = 0, next.cpu_state = 0, next.pc_addr = 0 + that next.timestamp = cur.timestamp and next.has_accepted = cur.has_accepted + */ + + // Order matters here: both witness maps touch next_root, but the + // one that does not set values must be executed the last, so its + // auxiliary variables are filled in correctly according to values + // actually set by the other witness map. + if (this->pb.val(do_halt).is_zero()) + { + copy_temp_next_pc_addr->generate_r1cs_witness(); + copy_temp_next_cpu_state->generate_r1cs_witness(); + + clear_next_root->generate_r1cs_witness(); + clear_next_pc_addr->generate_r1cs_witness(); + clear_next_cpu_state->generate_r1cs_witness(); + } + else + { + clear_next_root->generate_r1cs_witness(); + clear_next_pc_addr->generate_r1cs_witness(); + clear_next_cpu_state->generate_r1cs_witness(); + + copy_temp_next_pc_addr->generate_r1cs_witness(); + copy_temp_next_cpu_state->generate_r1cs_witness(); + } + +#ifdef DEBUG + printf("next.has_accepted: "); + this->pb.val(next->has_accepted).print(); +#endif + + next->generate_r1cs_witness_from_bits(); +} + +template +std::shared_ptr > > ram_compliance_predicate_handler::get_base_case_message(const ram_architecture_params &ap, + const ram_boot_trace &primary_input) +{ + enter_block("Call to ram_compliance_predicate_handler::get_base_case_message"); + const size_t num_addresses = 1ul << ap.address_size(); + const size_t value_size = ap.value_size(); + delegated_ra_memory > mem(num_addresses, value_size, primary_input.as_memory_contents()); + + const size_t type = 0; + + const size_t timestamp = 0; + + const bit_vector root_initial = mem.get_root(); + const size_t pc_addr_initial = ap.initial_pc_addr(); + const bit_vector cpu_state_initial(ap.cpu_state_size(), false); + + const bit_vector root = root_initial; + const size_t pc_addr = pc_addr_initial; + const bit_vector cpu_state = cpu_state_initial; + + const bool has_accepted = false; + + std::shared_ptr > result; + result.reset(new ram_pcd_message(type, ap, timestamp, root_initial, root, pc_addr, cpu_state, pc_addr_initial, cpu_state_initial, has_accepted)); + leave_block("Call to ram_compliance_predicate_handler::get_base_case_message"); + return result; +} + +template +std::shared_ptr > > ram_compliance_predicate_handler::get_final_case_msg(const ram_architecture_params &ap, + const ram_boot_trace &primary_input, + const size_t time_bound) +{ + enter_block("Call to ram_compliance_predicate_handler::get_final_case_msg"); + const size_t num_addresses = 1ul << ap.address_size(); + const size_t value_size = ap.value_size(); + delegated_ra_memory > mem(num_addresses, value_size, primary_input.as_memory_contents()); + + const size_t type = 1; + + const size_t timestamp = time_bound; + + const bit_vector root_initial = mem.get_root(); + const size_t pc_addr_initial = ap.initial_pc_addr(); + const bit_vector cpu_state_initial(ap.cpu_state_size(), false); + + const bit_vector root(root_initial.size(), false); + const size_t pc_addr = 0; + const bit_vector cpu_state = cpu_state_initial; + + const bool has_accepted = true; + + std::shared_ptr > result; + result.reset(new ram_pcd_message(type, ap, timestamp, root_initial, root, pc_addr, cpu_state, pc_addr_initial, cpu_state_initial, has_accepted)); + leave_block("Call to ram_compliance_predicate_handler::get_final_case_msg"); + + return result; +} + +} // libsnark + +#endif // RAM_COMPLIANCE_PREDICATE_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/ram_zksnark.hpp b/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/ram_zksnark.hpp new file mode 100644 index 0000000..27eddb4 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/ram_zksnark.hpp @@ -0,0 +1,224 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a zkSNARK for RAM. + + This includes: + - the class for a proving key; + - the class for a verification key; + - the class for a key pair (proving key & verification key); + - the class for a proof; + - the generator algorithm; + - the prover algorithm; + - the verifier algorithm. + + The implementation follows, extends, and optimizes the approach described + in \[BCTV14]. Thus, the zkSNARK is constructed from a ppzkPCD for R1CS. + + + Acronyms: + + "R1CS" = "Rank-1 Constraint Systems" + "RAM" = "Random-Access Machines" + "zkSNARK" = "Zero-Knowledge Succinct Non-interactive ARgument of Knowledge" + "ppzkPCD" = "Pre-Processing Zero-Knowledge Proof-Carrying Data" + + References: + + \[BCTV14]: + "Scalable Zero Knowledge via Cycles of Elliptic Curves", + Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, + CRYPTO 2014, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_ZKSNARK_HPP_ +#define RAM_ZKSNARK_HPP_ + +#include + +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd.hpp" +#include "zk_proof_systems/zksnark/ram_zksnark/ram_compliance_predicate.hpp" +#include "zk_proof_systems/zksnark/ram_zksnark/ram_zksnark_params.hpp" + +namespace libsnark { + +/******************************** Proving key ********************************/ + +template +class ram_zksnark_proving_key; + +template +std::ostream& operator<<(std::ostream &out, const ram_zksnark_proving_key &pk); + +template +std::istream& operator>>(std::istream &in, ram_zksnark_proving_key &pk); + +/** + * A proving key for the RAM zkSNARK. + */ +template +class ram_zksnark_proving_key { +public: + ram_zksnark_architecture_params ap; + r1cs_sp_ppzkpcd_proving_key > pcd_pk; + + ram_zksnark_proving_key() {} + ram_zksnark_proving_key(const ram_zksnark_proving_key &other) = default; + ram_zksnark_proving_key(ram_zksnark_proving_key &&other) = default; + ram_zksnark_proving_key(const ram_zksnark_architecture_params &ap, + r1cs_sp_ppzkpcd_proving_key > &&pcd_pk) : + ap(ap), + pcd_pk(std::move(pcd_pk)) + {}; + + ram_zksnark_proving_key& operator=(const ram_zksnark_proving_key &other) = default; + + bool operator==(const ram_zksnark_proving_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const ram_zksnark_proving_key &pk); + friend std::istream& operator>> (std::istream &in, ram_zksnark_proving_key &pk); +}; + + +/******************************* Verification key ****************************/ + +template +class ram_zksnark_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const ram_zksnark_verification_key &vk); + +template +std::istream& operator>>(std::istream &in, ram_zksnark_verification_key &vk); + +/** + * A verification key for the RAM zkSNARK. + */ +template +class ram_zksnark_verification_key { +public: + ram_zksnark_architecture_params ap; + r1cs_sp_ppzkpcd_verification_key > pcd_vk; + + ram_zksnark_verification_key() = default; + ram_zksnark_verification_key(const ram_zksnark_verification_key &other) = default; + ram_zksnark_verification_key(ram_zksnark_verification_key &&other) = default; + ram_zksnark_verification_key(const ram_zksnark_architecture_params &ap, + r1cs_sp_ppzkpcd_verification_key > &&pcd_vk) : + ap(ap), + pcd_vk(std::move(pcd_vk)) + {}; + + ram_zksnark_verification_key& operator=(const ram_zksnark_verification_key &other) = default; + + bool operator==(const ram_zksnark_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const ram_zksnark_verification_key &vk); + friend std::istream& operator>> (std::istream &in, ram_zksnark_verification_key &vk); + + static ram_zksnark_verification_key dummy_verification_key(const ram_zksnark_architecture_params &ap); +}; + + +/********************************** Key pair *********************************/ + +/** + * A key pair for the RAM zkSNARK, which consists of a proving key and a verification key. + */ +template +struct ram_zksnark_keypair { +public: + ram_zksnark_proving_key pk; + ram_zksnark_verification_key vk; + + ram_zksnark_keypair() {}; + ram_zksnark_keypair(ram_zksnark_keypair &&other) = default; + ram_zksnark_keypair(ram_zksnark_proving_key &&pk, + ram_zksnark_verification_key &&vk) : + pk(std::move(pk)), + vk(std::move(vk)) + {}; +}; + + +/*********************************** Proof ***********************************/ + +template +class ram_zksnark_proof; + +template +std::ostream& operator<<(std::ostream &out, const ram_zksnark_proof &proof); + +template +std::istream& operator>>(std::istream &in, ram_zksnark_proof &proof); + +/** + * A proof for the RAM zkSNARK. + */ +template +class ram_zksnark_proof { +public: + r1cs_sp_ppzkpcd_proof > PCD_proof; + + ram_zksnark_proof() = default; + ram_zksnark_proof(r1cs_sp_ppzkpcd_proof > &&PCD_proof) : + PCD_proof(std::move(PCD_proof)) {}; + ram_zksnark_proof(const r1cs_sp_ppzkpcd_proof > &PCD_proof) : + PCD_proof(PCD_proof) {}; + + size_t size_in_bits() const + { + return PCD_proof.size_in_bits(); + } + + bool operator==(const ram_zksnark_proof &other) const; + friend std::ostream& operator<< (std::ostream &out, const ram_zksnark_proof &proof); + friend std::istream& operator>> (std::istream &in, ram_zksnark_proof &proof); +}; + + +/***************************** Main algorithms *******************************/ + +/** + * A generator algorithm for the RAM zkSNARK. + * + * Given a choice of architecture parameters, this algorithm produces proving + * and verification keys for all computations that respect this choice. + */ +template +ram_zksnark_keypair ram_zksnark_generator(const ram_zksnark_architecture_params &ap); + +/** + * A prover algorithm for the RAM zkSNARK. + * + * Given a proving key, primary input X, time bound T, and auxiliary input Y, this algorithm + * produces a proof (of knowledge) that attests to the following statement: + * ``there exists Y such that X(Y) accepts within T steps''. + */ +template +ram_zksnark_proof ram_zksnark_prover(const ram_zksnark_proving_key &pk, + const ram_zksnark_primary_input &primary_input, + const size_t time_bound, + const ram_zksnark_auxiliary_input &auxiliary_input); + +/** + * A verifier algorithm for the RAM zkSNARK. + * + * This algorithm is universal in the sense that the verification key + * supports proof verification for *any* choice of primary input and time bound. + */ +template +bool ram_zksnark_verifier(const ram_zksnark_verification_key &vk, + const ram_zksnark_primary_input &primary_input, + const size_t time_bound, + const ram_zksnark_proof &proof); + +} // libsnark + +#include "zk_proof_systems/zksnark/ram_zksnark/ram_zksnark.tcc" + +#endif // RAM_ZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/ram_zksnark.tcc b/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/ram_zksnark.tcc new file mode 100644 index 0000000..dbdf954 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/ram_zksnark.tcc @@ -0,0 +1,230 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a zkSNARK for RAM. + + See ram_zksnark.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_ZKSNARK_TCC_ +#define RAM_ZKSNARK_TCC_ + +#include "common/profiling.hpp" + +namespace libsnark { + +template +bool ram_zksnark_proving_key::operator==(const ram_zksnark_proving_key &other) const +{ + return (this->ap == other.ap && + this->pcd_pk == other.pcd_pk); +} + +template +std::ostream& operator<<(std::ostream &out, const ram_zksnark_proving_key &pk) +{ + out << pk.ap; + out << pk.pcd_pk; + + return out; +} + +template +std::istream& operator>>(std::istream &in, ram_zksnark_proving_key &pk) +{ + in >> pk.ap; + in >> pk.pcd_pk; + + return in; +} + +template +bool ram_zksnark_verification_key::operator==(const ram_zksnark_verification_key &other) const +{ + return (this->ap == other.ap && + this->pcd_vk == other.pcd_vk); +} + +template +std::ostream& operator<<(std::ostream &out, const ram_zksnark_verification_key &vk) +{ + out << vk.ap; + out << vk.pcd_vk; + + return out; +} + +template +std::istream& operator>>(std::istream &in, ram_zksnark_verification_key &vk) +{ + in >> vk.ap; + in >> vk.pcd_vk; + + return in; +} + +template +bool ram_zksnark_proof::operator==(const ram_zksnark_proof &other) const +{ + return (this->PCD_proof == other.PCD_proof); +} + +template +std::ostream& operator<<(std::ostream &out, const ram_zksnark_proof &proof) +{ + out << proof.PCD_proof; + return out; +} + +template +std::istream& operator>>(std::istream &in, ram_zksnark_proof &proof) +{ + in >> proof.PCD_proof; + return in; +} + +template +ram_zksnark_verification_key ram_zksnark_verification_key::dummy_verification_key(const ram_zksnark_architecture_params &ap) +{ + typedef ram_zksnark_PCD_pp pcdT; + + return ram_zksnark_verification_key(ap, r1cs_sp_ppzkpcd_verification_key::dummy_verification_key()); +} + +template +ram_zksnark_keypair ram_zksnark_generator(const ram_zksnark_architecture_params &ap) +{ + typedef ram_zksnark_machine_pp ramT; + typedef ram_zksnark_PCD_pp pcdT; + enter_block("Call to ram_zksnark_generator"); + + enter_block("Generate compliance predicate for RAM"); + ram_compliance_predicate_handler cp_handler(ap); + cp_handler.generate_r1cs_constraints(); + r1cs_sp_ppzkpcd_compliance_predicate ram_compliance_predicate = cp_handler.get_compliance_predicate(); + leave_block("Generate compliance predicate for RAM"); + + enter_block("Generate PCD key pair"); + r1cs_sp_ppzkpcd_keypair kp = r1cs_sp_ppzkpcd_generator(ram_compliance_predicate); + leave_block("Generate PCD key pair"); + + leave_block("Call to ram_zksnark_generator"); + + ram_zksnark_proving_key pk = ram_zksnark_proving_key(ap, std::move(kp.pk)); + ram_zksnark_verification_key vk = ram_zksnark_verification_key(ap, std::move(kp.vk)); + + return ram_zksnark_keypair(std::move(pk), std::move(vk)); +} + +template +ram_zksnark_proof ram_zksnark_prover(const ram_zksnark_proving_key &pk, + const ram_zksnark_primary_input &primary_input, + const size_t time_bound, + const ram_zksnark_auxiliary_input &auxiliary_input) +{ + typedef ram_zksnark_machine_pp ramT; + typedef ram_zksnark_PCD_pp pcdT; + typedef Fr FieldT; // XXX + + assert(log2(time_bound) <= ramT::timestamp_length); + + enter_block("Call to ram_zksnark_prover"); + enter_block("Generate compliance predicate for RAM"); + ram_compliance_predicate_handler cp_handler(pk.ap); + leave_block("Generate compliance predicate for RAM"); + + enter_block("Initialize the RAM computation"); + r1cs_sp_ppzkpcd_proof cur_proof; // start out with an empty proof + + /* initialize memory with the correct values */ + const size_t num_addresses = 1ul << pk.ap.address_size(); + const size_t value_size = pk.ap.value_size(); + + delegated_ra_memory > mem(num_addresses, value_size, primary_input.as_memory_contents()); + std::shared_ptr > msg = ram_compliance_predicate_handler::get_base_case_message(pk.ap, primary_input); + + typename ram_input_tape::const_iterator aux_it = auxiliary_input.begin(); + leave_block("Initialize the RAM computation"); + + enter_block("Execute and prove the computation"); + bool want_halt = false; + for (size_t step = 1; step <= time_bound; ++step) + { + enter_block(FORMAT("", "Prove step %zu out of %zu", step, time_bound)); + + enter_block("Execute witness map"); + + std::shared_ptr > local_data; + local_data.reset(new ram_pcd_local_data(want_halt, mem, aux_it, auxiliary_input.end())); + + cp_handler.generate_r1cs_witness({ msg }, local_data); + + const r1cs_pcd_compliance_predicate_primary_input cp_primary_input(cp_handler.get_outgoing_message()); + const r1cs_pcd_compliance_predicate_auxiliary_input cp_auxiliary_input({ msg }, local_data, cp_handler.get_witness()); + +#ifdef DEBUG + printf("Current state:\n"); + msg->print(); +#endif + + msg = cp_handler.get_outgoing_message(); + +#ifdef DEBUG + printf("Next state:\n"); + msg->print(); +#endif + leave_block("Execute witness map"); + + cur_proof = r1cs_sp_ppzkpcd_prover(pk.pcd_pk, cp_primary_input, cp_auxiliary_input, { cur_proof }); + leave_block(FORMAT("", "Prove step %zu out of %zu", step, time_bound)); + } + leave_block("Execute and prove the computation"); + + enter_block("Finalize the computation"); + want_halt = true; + + enter_block("Execute witness map"); + + std::shared_ptr > local_data; + local_data.reset(new ram_pcd_local_data(want_halt, mem, aux_it, auxiliary_input.end())); + + cp_handler.generate_r1cs_witness({ msg }, local_data); + + const r1cs_pcd_compliance_predicate_primary_input cp_primary_input(cp_handler.get_outgoing_message()); + const r1cs_pcd_compliance_predicate_auxiliary_input cp_auxiliary_input({ msg }, local_data, cp_handler.get_witness()); + leave_block("Execute witness map"); + + cur_proof = r1cs_sp_ppzkpcd_prover(pk.pcd_pk, cp_primary_input, cp_auxiliary_input, { cur_proof }); + leave_block("Finalize the computation"); + + leave_block("Call to ram_zksnark_prover"); + + return cur_proof; +} + +template +bool ram_zksnark_verifier(const ram_zksnark_verification_key &vk, + const ram_zksnark_primary_input &primary_input, + const size_t time_bound, + const ram_zksnark_proof &proof) +{ + typedef ram_zksnark_machine_pp ramT; + typedef ram_zksnark_PCD_pp pcdT; + typedef Fr FieldT; // XXX + + enter_block("Call to ram_zksnark_verifier"); + const r1cs_pcd_compliance_predicate_primary_input cp_primary_input(ram_compliance_predicate_handler::get_final_case_msg(vk.ap, primary_input, time_bound)); + bool ans = r1cs_sp_ppzkpcd_verifier(vk.pcd_vk, cp_primary_input, proof.PCD_proof); + leave_block("Call to ram_zksnark_verifier"); + + return ans; +} + +} // libsnark + +#endif // RAM_ZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/ram_zksnark_params.hpp b/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/ram_zksnark_params.hpp new file mode 100644 index 0000000..8f802c6 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/ram_zksnark_params.hpp @@ -0,0 +1,73 @@ +/** @file + ***************************************************************************** + + Declaration of public-parameter selector for the RAM zkSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_ZKSNARK_PARAMS_HPP_ +#define RAM_ZKSNARK_PARAMS_HPP_ + +namespace libsnark { + +/** + * The interfaces of the RAM zkSNARK are templatized via the parameter + * ram_zksnark_ppT. When used, the interfaces must be invoked with + * a particular parameter choice; let 'my_ram_zksnark_pp' denote this choice. + * + * The class my_ram_zksnark_pp must contain typedefs for the typenames + * - PCD_pp, and + * - machine_pp. + * + * As well as a method with type signature: + * static void init_public_params() + * + * For example, if you want to use the types my_PCD_pp and my_machine_pp, + * then you would declare my_ram_zksnark_pp as follows: + * + * class my_ram_zksnark_pp { + * public: + * typedef my_PCD_pp PCD_pp; + * typedef my_machine_pp machine_pp; + * static void init_public_params() + * { + * PCD_pp::init_public_params(); // plus other necessary initialization + * } + * }; + * + * Having done the above, my_ram_zksnark_pp can be used as a template parameter. + * + * See default_tinyram_zksnark_pp in the file + * + * common/default_types/tinyram_zksnark_pp.hpp + * + * for an example of the above steps for the case of "RAM=TinyRAM". + * + */ + +/* + * Below are various template aliases (used for convenience). + */ + +template +using ram_zksnark_PCD_pp = typename ram_zksnark_ppT::PCD_pp; + +template +using ram_zksnark_machine_pp = typename ram_zksnark_ppT::machine_pp; + +template +using ram_zksnark_architecture_params = ram_architecture_params >; + +template +using ram_zksnark_primary_input = ram_boot_trace >; + +template +using ram_zksnark_auxiliary_input = ram_input_tape >; + +} // libsnark + +#endif // RAM_ZKSNARK_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/tests/test_ram_zksnark.cpp b/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/tests/test_ram_zksnark.cpp new file mode 100644 index 0000000..70c4193 --- /dev/null +++ b/privacy/zsl/zsl/zk_proof_systems/zksnark/ram_zksnark/tests/test_ram_zksnark.cpp @@ -0,0 +1,41 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include "common/default_types/ram_zksnark_pp.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_params.hpp" +#include "zk_proof_systems/zksnark/ram_zksnark/examples/run_ram_zksnark.hpp" +#include "relations/ram_computations/rams/examples/ram_examples.hpp" + +using namespace libsnark; + +template +void test_ram_zksnark(const size_t w, + const size_t k, + const size_t boot_trace_size_bound, + const size_t time_bound) +{ + typedef ram_zksnark_machine_pp ramT; + const ram_architecture_params ap(w, k); + const ram_example example = gen_ram_example_complex(ap, boot_trace_size_bound, time_bound, true); + const bool test_serialization = true; + const bool ans = run_ram_zksnark(example, test_serialization); + assert(ans); +} + +int main(void) +{ + start_profiling(); + ram_zksnark_PCD_pp::init_public_params(); + + const size_t w = 32; + const size_t k = 16; + + const size_t boot_trace_size_bound = 20; + const size_t time_bound = 10; + + test_ram_zksnark(w, k, boot_trace_size_bound, time_bound); +} diff --git a/privacy/zsl/zsl/zsl.h b/privacy/zsl/zsl/zsl.h new file mode 100644 index 0000000..529b68c --- /dev/null +++ b/privacy/zsl/zsl/zsl.h @@ -0,0 +1,95 @@ +// Copyright 2017 Zerocoin Electric Coin Company LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _ZSL_H_ +#define _ZSL_H_ + +#include +#include +#include + +//#ifdef __cplusplus +//extern "C" { +//#endif + + void zsl_initialize(); + bool zsl_verify_shielding( + void *proof, + void *send_nf, + void *cm, + uint64_t value + ); + void zsl_prove_shielding( + void *rho, + void *pk, + uint64_t value, + void *output_proof + ); + void zsl_paramgen_shielding(); + + void zsl_prove_unshielding( + void *rho, + void *sk, + uint64_t value, + uint64_t tree_position, + void *authentication_path, + void *output_proof + ); + bool zsl_verify_unshielding( + void *proof_ptr, + void *spend_nf_ptr, + void *rt_ptr, + uint64_t value + ); + + void zsl_paramgen_unshielding(); + + void zsl_paramgen_transfer(); + + void zsl_prove_transfer( + void *output_proof_ptr, + void *input_rho_ptr_1, + void *input_pk_ptr_1, + uint64_t input_value_1, + uint64_t input_tree_position_1, + void *input_authentication_path_ptr_1, + void *input_rho_ptr_2, + void *input_pk_ptr_2, + uint64_t input_value_2, + uint64_t input_tree_position_2, + void *input_authentication_path_ptr_2, + void *output_rho_ptr_1, + void *output_pk_ptr_1, + uint64_t output_value_1, + void *output_rho_ptr_2, + void *output_pk_ptr_2, + uint64_t output_value_2 + ); + + bool zsl_verify_transfer( + void *proof_ptr, + void *anchor_ptr, + void *spend_nf_ptr_1, + void *spend_nf_ptr_2, + void *send_nf_ptr_1, + void *send_nf_ptr_2, + void *cm_ptr_1, + void *cm_ptr_2 + ); + +//#ifdef __cplusplus +//} +//#endif + +#endif diff --git a/privacy/zsl/zsl_contract.js b/privacy/zsl/zsl_contract.js new file mode 100644 index 0000000..e69de29