diff --git a/Makefile b/Makefile index 44875f0e..2a73e9d2 100644 --- a/Makefile +++ b/Makefile @@ -108,6 +108,18 @@ ifeq ($(CURVE),BN128) AR_LIBS += $(DEPINST)/lib/libzm.a endif +ifeq ($(CURVE),MCL_BN128) + LIB_SRCS += \ + src/algebra/curves/mcl_bn128/mcl_bn128_g1.cpp \ + src/algebra/curves/mcl_bn128/mcl_bn128_g2.cpp \ + src/algebra/curves/mcl_bn128/mcl_bn128_gt.cpp \ + src/algebra/curves/mcl_bn128/mcl_bn128_init.cpp \ + src/algebra/curves/mcl_bn128/mcl_bn128_pairing.cpp \ + src/algebra/curves/mcl_bn128/mcl_bn128_pp.cpp + + AR_LIBS += $(DEPINST)/lib/libmcl.a +endif + EXECUTABLES = \ src/algebra/curves/tests/test_bilinearity \ src/algebra/curves/tests/test_groups \ diff --git a/prepare-depends.sh b/prepare-depends.sh index 05929044..a6581af1 100755 --- a/prepare-depends.sh +++ b/prepare-depends.sh @@ -20,6 +20,18 @@ cd ../.. cp -rv $DEPSRC/ate-pairing/include $DEPINST/ cp -rv $DEPSRC/ate-pairing/lib $DEPINST/ +# mcl library, and its dependency, xbyak and cybozulib (needed for MCL_BN128 curve) +cd $DEPSRC +[ ! -d xbyak ] && git clone git://github.com/herumi/xbyak.git +[ ! -d cybozulib ] && git clone git://github.com/herumi/cybozulib.git +[ ! -d mcl ] && git clone git://github.com/herumi/mcl.git +cd mcl +make -j +cd ../.. +cp -rv $DEPSRC/mcl/include/mcl $DEPINST/include/ +cp -rv $DEPSRC/cybozulib/include/cybozu $DEPINST/include/ +cp -rv $DEPSRC/mcl/lib $DEPINST/ + # SUPERCOP library (optimized crypto implementations, used by ADSNARK) cd $DEPSRC [ ! -d libsnark-supercop ] && git clone git://github.com/mbbarbosa/libsnark-supercop.git diff --git a/src/algebra/curves/mcl_bn128/bn_utils.hpp b/src/algebra/curves/mcl_bn128/bn_utils.hpp new file mode 100644 index 00000000..ea8e7ab8 --- /dev/null +++ b/src/algebra/curves/mcl_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/mcl_bn128/bn_utils.tcc" + +#endif // BN_UTILS_HPP_ diff --git a/src/algebra/curves/mcl_bn128/bn_utils.tcc b/src/algebra/curves/mcl_bn128/bn_utils.tcc new file mode 100644 index 00000000..2188a911 --- /dev/null +++ b/src/algebra/curves/mcl_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; + FieldT::inv(acc_inverse, acc); + + 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/src/algebra/curves/mcl_bn128/mcl_bn128_g1.cpp b/src/algebra/curves/mcl_bn128/mcl_bn128_g1.cpp new file mode 100644 index 00000000..a8eb5e90 --- /dev/null +++ b/src/algebra/curves/mcl_bn128/mcl_bn128_g1.cpp @@ -0,0 +1,310 @@ +/** @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/mcl_bn128/mcl_bn128_g1.hpp" +#include "algebra/curves/mcl_bn128/bn_utils.hpp" + +using namespace mcl::bn256; + +namespace libsnark { + +static struct LibInit { + LibInit() + { + mcl::bn256::bn256init(mcl::bn::CurveSNARK1); // init mcl library + mcl::bn256::Fp::setIoMode(mcl::IoDec); + } +} s_libInit; + +#ifdef PROFILE_OP_COUNTS +long long mcl_bn128_G1::add_cnt = 0; +long long mcl_bn128_G1::dbl_cnt = 0; +#endif + +std::vector mcl_bn128_G1::wnaf_window_table; +std::vector mcl_bn128_G1::fixed_base_exp_window_table; +mcl_bn128_G1 mcl_bn128_G1::G1_zero; +mcl_bn128_G1 mcl_bn128_G1::G1_one; + +Fp mcl_bn128_G1::sqrt(const Fp &el) +{ + Fp x; + bool ok = Fp::squareRoot(x, el); + assert(ok); + (void)ok; + return x; +} + +mcl_bn128_G1::mcl_bn128_G1() +{ + this->pt.clear(); +} + +void mcl_bn128_G1::print() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + pt.normalize(); + std::cout << "(" << pt.x << " : " << pt.y << " : " << pt.z << ")\n"; + } +} + +void mcl_bn128_G1::print_coordinates() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + std::cout << "(" << pt.x << " : " << pt.y << " : " << pt.z << ")\n"; + } +} + +void mcl_bn128_G1::to_affine_coordinates() +{ + pt.normalize(); +} + +void mcl_bn128_G1::to_special() +{ + this->to_affine_coordinates(); +} + +bool mcl_bn128_G1::is_special() const +{ + return (this->is_zero() || this->pt.z == 1); +} + +bool mcl_bn128_G1::is_zero() const +{ + return pt.isZero(); +} + +bool mcl_bn128_G1::operator==(const mcl_bn128_G1 &other) const +{ + return this->pt == other.pt; +} + +bool mcl_bn128_G1::operator!=(const mcl_bn128_G1& other) const +{ + return !(operator==(other)); +} + +mcl_bn128_G1 mcl_bn128_G1::operator+(const mcl_bn128_G1 &other) const +{ + return this->add(other); +} + +mcl_bn128_G1 mcl_bn128_G1::operator-() const +{ + mcl_bn128_G1 result; + G1::neg(result.pt, pt); + return result; +} + +mcl_bn128_G1 mcl_bn128_G1::operator-(const mcl_bn128_G1 &other) const +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + mcl_bn128_G1 result; + G1::sub(result.pt, pt, other.pt); + return result; +} + +mcl_bn128_G1 mcl_bn128_G1::add(const mcl_bn128_G1 &other) const +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + mcl_bn128_G1 result; + G1::add(result.pt, pt, other.pt); + return result; +} + +mcl_bn128_G1 mcl_bn128_G1::mixed_add(const mcl_bn128_G1 &other) const +{ + mcl_bn128_G1 result; + G1::add(result.pt, pt, other.pt); +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + return result; +} + +mcl_bn128_G1 mcl_bn128_G1::dbl() const +{ +#ifdef PROFILE_OP_COUNTS + this->dbl_cnt++; +#endif + mcl_bn128_G1 result; + G1::dbl(result.pt, pt); + return result; +} + +mcl_bn128_G1 mcl_bn128_G1::zero() +{ + return G1_zero; +} + +mcl_bn128_G1 mcl_bn128_G1::one() +{ + return G1_one; +} + +mcl_bn128_G1 mcl_bn128_G1::random_element() +{ + return mcl_bn128_Fr::random_element().as_bigint() * G1_one; +} + +std::ostream& operator<<(std::ostream &out, const mcl_bn128_G1 &g) +{ + g.pt.normalize(); + + out << (g.is_zero() ? '1' : '0') << OUTPUT_SEPARATOR; + +#ifdef NO_PT_COMPRESSION + /* no point compression case */ +#ifndef BINARY_OUTPUT + out << g.pt.x << OUTPUT_SEPARATOR << g.pt.y; +#else + out.write((char*) &g.pt, sizeof(g.pt)); +#endif + +#else + /* point compression case */ +#ifndef BINARY_OUTPUT + out << g.pt.x; +#else + out.write((char*) &g.pt.x, sizeof(g.pt.x)); +#endif + out << OUTPUT_SEPARATOR << (g.pt.y.getUnit()[0] & 1 ? '1' : '0'); +#endif + + return out; +} + +bool mcl_bn128_G1::is_well_formed() const +{ + return pt.isValid(); +} + +std::istream& operator>>(std::istream &in, mcl_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.pt.x; + consume_OUTPUT_SEPARATOR(in); + in >> g.pt.y; +#else + in.read((char*) &g.pt, sizeof(g.pt)); +#endif + +#else + /* point compression case */ +#ifndef BINARY_OUTPUT + in >> g.pt.x; +#else + in.read((char*)&g.pt.x, sizeof(g.pt.x)); +#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) + { + mcl::bn256::G1::getWeierstrass(g.pt.y, g.pt.x); + Fp::squareRoot(g.pt.y, g.pt.y); + if ((g.pt.y.getUnit()[0] & 1) != Y_lsb) + { + Fp::neg(g.pt.y, g.pt.y); + } + } +#endif + + /* finalize */ + if (!is_zero) + { + g.pt.z = Fp::one(); + } + else + { + g.pt.clear(); + } + + return in; +} + +std::ostream& operator<<(std::ostream& out, const std::vector &v) +{ + out << v.size() << "\n"; + for (const mcl_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) + { + mcl_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.pt.z); + } + bn_batch_invert(Z_vec); + + const Fp one = 1; + + for (size_t i = 0; i < vec.size(); ++i) + { + Fp Z2, Z3; + Fp::sqr(Z2, Z_vec[i]); + Fp::mul(Z3, Z2, Z_vec[i]); + + Fp::mul(vec[i].pt.x, vec[i].pt.x, Z2); + Fp::mul(vec[i].pt.y, vec[i].pt.y, Z3); + vec[i].pt.z = one; + } +} + +} // libsnark diff --git a/src/algebra/curves/mcl_bn128/mcl_bn128_g1.hpp b/src/algebra/curves/mcl_bn128/mcl_bn128_g1.hpp new file mode 100644 index 00000000..3b1969bd --- /dev/null +++ b/src/algebra/curves/mcl_bn128/mcl_bn128_g1.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 MCL_BN128_G1_HPP_ +#define MCL_BN128_G1_HPP_ +#include +#include "algebra/curves/mcl_bn128/mcl_bn128_init.hpp" +#include "algebra/curves/curve_utils.hpp" +#include "mcl/bn256.hpp" + +namespace libsnark { + +class mcl_bn128_G1; +std::ostream& operator<<(std::ostream &, const mcl_bn128_G1&); +std::istream& operator>>(std::istream &, mcl_bn128_G1&); + +class mcl_bn128_G1 { +private: + typedef mcl::bn256::Fp Fp; + typedef mcl::bn256::G1 G1; + static Fp sqrt(const 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 mcl_bn128_G1 G1_zero; + static mcl_bn128_G1 G1_one; + + mcl::bn256::G1 pt; + mcl_bn128_G1(); + typedef mcl_bn128_Fq base_field; + typedef mcl_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 mcl_bn128_G1 &other) const; + bool operator!=(const mcl_bn128_G1 &other) const; + + mcl_bn128_G1 operator+(const mcl_bn128_G1 &other) const; + mcl_bn128_G1 operator-() const; + mcl_bn128_G1 operator-(const mcl_bn128_G1 &other) const; + + mcl_bn128_G1 add(const mcl_bn128_G1 &other) const; + mcl_bn128_G1 mixed_add(const mcl_bn128_G1 &other) const; + mcl_bn128_G1 dbl() const; + + bool is_well_formed() const; + + static mcl_bn128_G1 zero(); + static mcl_bn128_G1 one(); + static mcl_bn128_G1 random_element(); + + static size_t size_in_bits() { return mcl_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 mcl_bn128_G1 &g); + friend std::istream& operator>>(std::istream &in, mcl_bn128_G1 &g); +}; + +template +mcl_bn128_G1 operator*(const bigint &lhs, const mcl_bn128_G1 &rhs) +{ + return scalar_mul(rhs, lhs); +} + +template& modulus_p> +mcl_bn128_G1 operator*(const Fp_model &lhs, const mcl_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 // MCL_BN128_G1_HPP_ diff --git a/src/algebra/curves/mcl_bn128/mcl_bn128_g2.cpp b/src/algebra/curves/mcl_bn128/mcl_bn128_g2.cpp new file mode 100644 index 00000000..08ba9c6c --- /dev/null +++ b/src/algebra/curves/mcl_bn128/mcl_bn128_g2.cpp @@ -0,0 +1,281 @@ +/** @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/mcl_bn128/mcl_bn128_g2.hpp" +#include "algebra/curves/mcl_bn128/bn_utils.hpp" + +using namespace mcl::bn256; + +namespace libsnark { + +#ifdef PROFILE_OP_COUNTS +long long mcl_bn128_G2::add_cnt = 0; +long long mcl_bn128_G2::dbl_cnt = 0; +#endif + +std::vector mcl_bn128_G2::wnaf_window_table; +std::vector mcl_bn128_G2::fixed_base_exp_window_table; +mcl_bn128_G2 mcl_bn128_G2::G2_zero; +mcl_bn128_G2 mcl_bn128_G2::G2_one; + +Fp2 mcl_bn128_G2::sqrt(const Fp2 &el) +{ + Fp2 x; + bool ok = Fp2::squareRoot(x, el); + assert(ok); + (void)ok; + return x; +} + +mcl_bn128_G2::mcl_bn128_G2() +{ + this->pt.clear(); +} + +void mcl_bn128_G2::print() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + pt.normalize(); + std::cout << "(" << pt.x << " : " << pt.y << " : " << pt.z << ")\n"; + } +} + +void mcl_bn128_G2::print_coordinates() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + std::cout << "(" << pt.x << " : " << pt.y << " : " << pt.z << ")\n"; + } +} + +void mcl_bn128_G2::to_affine_coordinates() +{ + pt.normalize(); +} + +void mcl_bn128_G2::to_special() +{ + this->to_affine_coordinates(); +} + +bool mcl_bn128_G2::is_special() const +{ + return (this->is_zero() || this->pt.z == 1); +} + +bool mcl_bn128_G2::is_zero() const +{ + return pt.isZero(); +} + +bool mcl_bn128_G2::operator==(const mcl_bn128_G2 &other) const +{ + return pt == other.pt; +} + +bool mcl_bn128_G2::operator!=(const mcl_bn128_G2& other) const +{ + return !(operator==(other)); +} + +mcl_bn128_G2 mcl_bn128_G2::operator+(const mcl_bn128_G2 &other) const +{ + return this->add(other); +} + +mcl_bn128_G2 mcl_bn128_G2::operator-() const +{ + mcl_bn128_G2 result; + G2::neg(result.pt, pt); + return result; +} + +mcl_bn128_G2 mcl_bn128_G2::operator-(const mcl_bn128_G2 &other) const +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + mcl_bn128_G2 result; + G2::sub(result.pt, pt, other.pt); + return result; +} + +mcl_bn128_G2 mcl_bn128_G2::add(const mcl_bn128_G2 &other) const +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + mcl_bn128_G2 result; + mcl::bn256::G2::add(result.pt, pt, other.pt); + return result; +} + +mcl_bn128_G2 mcl_bn128_G2::mixed_add(const mcl_bn128_G2 &other) const +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + mcl_bn128_G2 result; + G2::add(result.pt, pt, other.pt); + return result; +} + +mcl_bn128_G2 mcl_bn128_G2::dbl() const +{ +#ifdef PROFILE_OP_COUNTS + this->dbl_cnt++; +#endif + mcl_bn128_G2 result; + G2::dbl(result.pt, pt); + return result; +} + +bool mcl_bn128_G2::is_well_formed() const +{ + return pt.isValid(); +} + +mcl_bn128_G2 mcl_bn128_G2::zero() +{ + return G2_zero; +} + +mcl_bn128_G2 mcl_bn128_G2::one() +{ + return G2_one; +} + +mcl_bn128_G2 mcl_bn128_G2::random_element() +{ + return mcl_bn128_Fr::random_element().as_bigint() * G2_one; +} + +std::ostream& operator<<(std::ostream &out, const mcl_bn128_G2 &g) +{ + g.pt.normalize(); + + out << (g.is_zero() ? '1' : '0') << OUTPUT_SEPARATOR; + +#ifdef NO_PT_COMPRESSION + /* no point compression case */ +#ifndef BINARY_OUTPUT + out << g.pt.x.a << OUTPUT_SEPARATOR << g.pt.x.b << OUTPUT_SEPARATOR; + out << g.pt.y.a << OUTPUT_SEPARATOR << g.pt.y.b; +#else + out.write((char*) &g.pt, sizeof(g.pt)); +#endif + +#else + /* point compression case */ +#ifndef BINARY_OUTPUT + out << g.pt.x.a << OUTPUT_SEPARATOR << g.pt.x.b; +#else + out.write((char*) &g.pt.x, sizeof(g.pt.x)); +#endif + out << OUTPUT_SEPARATOR << (g.pt.y.a.getUnit()[0] & 1 ? '1' : '0'); +#endif + + return out; +} + +std::istream& operator>>(std::istream &in, mcl_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.pt.x.a; + consume_OUTPUT_SEPARATOR(in); + in >> g.pt.x.b; + consume_OUTPUT_SEPARATOR(in); + in >> g.pt.y.a; + consume_OUTPUT_SEPARATOR(in); + in >> g.pt.y.b; +#else + in.read((char*) &g.pt, sizeof(g.pt)); +#endif + +#else + /* point compression case */ +#ifndef BINARY_OUTPUT + in >> g.pt.x.a; + consume_OUTPUT_SEPARATOR(in); + in >> g.pt.x.b; +#else + in.read((char*)&g.pt.x, sizeof(g.pt.x)); +#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) + { + mcl::bn256::G2::getWeierstrass(g.pt.y, g.pt.x); + Fp2::squareRoot(g.pt.y, g.pt.y); + if ((g.pt.y.a.getUnit()[0] & 1) != Y_lsb) + { + Fp2::neg(g.pt.y, g.pt.y); + } + } +#endif + + /* finalize */ + if (!is_zero) + { + g.pt.z.a = Fp::one(); + g.pt.z.b.clear(); + } + else + { + g.pt.clear(); + } + + 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.pt.z); + } + bn_batch_invert(Z_vec); + + const Fp2 one = 1; + + for (size_t i = 0; i < vec.size(); ++i) + { + Fp2 Z2, Z3; + Fp2::sqr(Z2, Z_vec[i]); + Fp2::mul(Z3, Z2, Z_vec[i]); + + Fp2::mul(vec[i].pt.x, vec[i].pt.x, Z2); + Fp2::mul(vec[i].pt.y, vec[i].pt.y, Z3); + vec[i].pt.z = one; + } +} + +} // libsnark diff --git a/src/algebra/curves/mcl_bn128/mcl_bn128_g2.hpp b/src/algebra/curves/mcl_bn128/mcl_bn128_g2.hpp new file mode 100644 index 00000000..1501f8c6 --- /dev/null +++ b/src/algebra/curves/mcl_bn128/mcl_bn128_g2.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 MCL_BN128_G2_HPP_ +#define MCL_BN128_G2_HPP_ +#include +#include +#include "algebra/curves/mcl_bn128/mcl_bn128_init.hpp" +#include "algebra/curves/curve_utils.hpp" +#include "mcl/bn256.hpp" + +namespace libsnark { + +class mcl_bn128_G2; +std::ostream& operator<<(std::ostream &, const mcl_bn128_G2&); +std::istream& operator>>(std::istream &, mcl_bn128_G2&); + +class mcl_bn128_G2 { +private: + typedef mcl::bn256::Fp2 Fp2; + typedef mcl::bn256::G2 G2; + static Fp2 sqrt(const 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 mcl_bn128_G2 G2_zero; + static mcl_bn128_G2 G2_one; + + mcl::bn256::G2 pt; + mcl_bn128_G2(); + typedef mcl_bn128_Fq base_field; + typedef mcl_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 mcl_bn128_G2 &other) const; + bool operator!=(const mcl_bn128_G2 &other) const; + + mcl_bn128_G2 operator+(const mcl_bn128_G2 &other) const; + mcl_bn128_G2 operator-() const; + mcl_bn128_G2 operator-(const mcl_bn128_G2 &other) const; + + mcl_bn128_G2 add(const mcl_bn128_G2 &other) const; + mcl_bn128_G2 mixed_add(const mcl_bn128_G2 &other) const; + mcl_bn128_G2 dbl() const; + + bool is_well_formed() const; + + static mcl_bn128_G2 zero(); + static mcl_bn128_G2 one(); + static mcl_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 mcl_bn128_G2 &g); + friend std::istream& operator>>(std::istream &in, mcl_bn128_G2 &g); +}; + +template +mcl_bn128_G2 operator*(const bigint &lhs, const mcl_bn128_G2 &rhs) +{ + return scalar_mul(rhs, lhs); +} + +template& modulus_p> +mcl_bn128_G2 operator*(const Fp_model &lhs, const mcl_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 // MCL_BN128_G2_HPP_ diff --git a/src/algebra/curves/mcl_bn128/mcl_bn128_gt.cpp b/src/algebra/curves/mcl_bn128/mcl_bn128_gt.cpp new file mode 100644 index 00000000..efed1f77 --- /dev/null +++ b/src/algebra/curves/mcl_bn128/mcl_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/mcl_bn128/mcl_bn128_gt.hpp" + +using namespace mcl::bn256; + +namespace libsnark { + +mcl_bn128_GT mcl_bn128_GT::GT_one; +mcl_bn128_GT::mcl_bn128_GT() +{ + this->elem.clear(); +} + +bool mcl_bn128_GT::operator==(const mcl_bn128_GT &other) const +{ + return (this->elem == other.elem); +} + +bool mcl_bn128_GT::operator!=(const mcl_bn128_GT& other) const +{ + return !(operator==(other)); +} + +mcl_bn128_GT mcl_bn128_GT::operator*(const mcl_bn128_GT &other) const +{ + mcl_bn128_GT result; + Fp12::mul(result.elem, this->elem, other.elem); + return result; +} + +mcl_bn128_GT mcl_bn128_GT::unitary_inverse() const +{ + mcl_bn128_GT result(*this); + Fp6::neg(result.elem.b, result.elem.b); + return result; +} + +mcl_bn128_GT mcl_bn128_GT::one() +{ + return GT_one; +} + +std::ostream& operator<<(std::ostream &out, const mcl_bn128_GT &g) +{ +#ifndef BINARY_OUTPUT + out << g.elem.a << OUTPUT_SEPARATOR << g.elem.b; +#else + out.write((char*) &g.elem, sizeof(g.elem)); +#endif + return out; +} + +std::istream& operator>>(std::istream &in, mcl_bn128_GT &g) +{ +#ifndef BINARY_OUTPUT + in >> g.elem.a; + consume_OUTPUT_SEPARATOR(in); + in >> g.elem.b; +#else + in.read((char*) &g.elem, sizeof(g.elem)); +#endif + return in; +} +} // libsnark diff --git a/src/algebra/curves/mcl_bn128/mcl_bn128_gt.hpp b/src/algebra/curves/mcl_bn128/mcl_bn128_gt.hpp new file mode 100644 index 00000000..6ba92e27 --- /dev/null +++ b/src/algebra/curves/mcl_bn128/mcl_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 MCL_BN128_GT_HPP_ +#define MCL_BN128_GT_HPP_ +#include "algebra/fields/fp.hpp" +#include "algebra/fields/field_utils.hpp" +#include +#include "mcl/bn256.hpp" + +namespace libsnark { + +class mcl_bn128_GT; +std::ostream& operator<<(std::ostream &, const mcl_bn128_GT&); +std::istream& operator>>(std::istream &, mcl_bn128_GT&); + +class mcl_bn128_GT { +public: + static mcl_bn128_GT GT_one; + mcl::bn256::Fp12 elem; + + mcl_bn128_GT(); + bool operator==(const mcl_bn128_GT &other) const; + bool operator!=(const mcl_bn128_GT &other) const; + + mcl_bn128_GT operator*(const mcl_bn128_GT &other) const; + mcl_bn128_GT unitary_inverse() const; + + static mcl_bn128_GT one(); + + void print() { std::cout << this->elem << "\n"; }; + + friend std::ostream& operator<<(std::ostream &out, const mcl_bn128_GT &g); + friend std::istream& operator>>(std::istream &in, mcl_bn128_GT &g); +}; + +template +mcl_bn128_GT operator^(const mcl_bn128_GT &rhs, const bigint &lhs) +{ + return power(rhs, lhs); +} + + +template& modulus_p> +mcl_bn128_GT operator^(const mcl_bn128_GT &rhs, const Fp_model &lhs) +{ + return power(rhs, lhs.as_bigint()); +} + +} // libsnark +#endif // MCL_BN128_GT_HPP_ diff --git a/src/algebra/curves/mcl_bn128/mcl_bn128_init.cpp b/src/algebra/curves/mcl_bn128/mcl_bn128_init.cpp new file mode 100644 index 00000000..874ffae3 --- /dev/null +++ b/src/algebra/curves/mcl_bn128/mcl_bn128_init.cpp @@ -0,0 +1,229 @@ +/** @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/mcl_bn128/mcl_bn128_init.hpp" +#include "algebra/curves/mcl_bn128/mcl_bn128_g1.hpp" +#include "algebra/curves/mcl_bn128/mcl_bn128_g2.hpp" +#include "algebra/curves/mcl_bn128/mcl_bn128_gt.hpp" + +using namespace mcl::bn256; + +namespace libsnark { + +bigint mcl_bn128_modulus_r; +bigint mcl_bn128_modulus_q; + +Fp mcl_bn128_coeff_b; +size_t mcl_bn128_Fq_s; +Fp mcl_bn128_Fq_nqr_to_t; +mpz_class mcl_bn128_Fq_t_minus_1_over_2; + +Fp2 mcl_bn128_twist_coeff_b; +size_t mcl_bn128_Fq2_s; +Fp2 mcl_bn128_Fq2_nqr_to_t; +mpz_class mcl_bn128_Fq2_t_minus_1_over_2; + +void init_mcl_bn128_params() +{ + // call bn256init at first before static initializer of g1 +// mcl::bn256::bn256init(mcl::bn::CurveSNARK1); // init mcl 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 */ + mcl_bn128_modulus_r = bigint_r("21888242871839275222246405745257275088548364400416034343698204186575808495617"); + assert(mcl_bn128_Fr::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + mcl_bn128_Fr::Rsquared = bigint_r("944936681149208446651664254269745548490766851729442924617792859073125903783"); + mcl_bn128_Fr::Rcubed = bigint_r("5866548545943845227489894872040244720403868105578784105281690076696998248512"); + mcl_bn128_Fr::inv = 0xc2e1f593efffffff; + } + if (sizeof(mp_limb_t) == 4) + { + mcl_bn128_Fr::Rsquared = bigint_r("944936681149208446651664254269745548490766851729442924617792859073125903783"); + mcl_bn128_Fr::Rcubed = bigint_r("5866548545943845227489894872040244720403868105578784105281690076696998248512"); + mcl_bn128_Fr::inv = 0xefffffff; + } + mcl_bn128_Fr::num_bits = 254; + mcl_bn128_Fr::euler = bigint_r("10944121435919637611123202872628637544274182200208017171849102093287904247808"); + mcl_bn128_Fr::s = 28; + mcl_bn128_Fr::t = bigint_r("81540058820840996586704275553141814055101440848469862132140264610111"); + mcl_bn128_Fr::t_minus_1_over_2 = bigint_r("40770029410420498293352137776570907027550720424234931066070132305055"); + mcl_bn128_Fr::multiplicative_generator = mcl_bn128_Fr("5"); + mcl_bn128_Fr::root_of_unity = mcl_bn128_Fr("19103219067921713944291392827692070036145651957329286315305642004821462161904"); + mcl_bn128_Fr::nqr = mcl_bn128_Fr("5"); + mcl_bn128_Fr::nqr_to_t = mcl_bn128_Fr("19103219067921713944291392827692070036145651957329286315305642004821462161904"); + + /* parameters for base field Fq */ + mcl_bn128_modulus_q = bigint_q("21888242871839275222246405745257275088696311157297823662689037894645226208583"); + assert(mcl_bn128_Fq::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + mcl_bn128_Fq::Rsquared = bigint_q("3096616502983703923843567936837374451735540968419076528771170197431451843209"); + mcl_bn128_Fq::Rcubed = bigint_q("14921786541159648185948152738563080959093619838510245177710943249661917737183"); + mcl_bn128_Fq::inv = 0x87d20782e4866389; + } + if (sizeof(mp_limb_t) == 4) + { + mcl_bn128_Fq::Rsquared = bigint_q("3096616502983703923843567936837374451735540968419076528771170197431451843209"); + mcl_bn128_Fq::Rcubed = bigint_q("14921786541159648185948152738563080959093619838510245177710943249661917737183"); + mcl_bn128_Fq::inv = 0xe4866389; + } + mcl_bn128_Fq::num_bits = 254; + mcl_bn128_Fq::euler = bigint_q("10944121435919637611123202872628637544348155578648911831344518947322613104291"); + mcl_bn128_Fq::s = 1; + mcl_bn128_Fq::t = bigint_q("10944121435919637611123202872628637544348155578648911831344518947322613104291"); + mcl_bn128_Fq::t_minus_1_over_2 = bigint_q("5472060717959818805561601436314318772174077789324455915672259473661306552145"); + mcl_bn128_Fq::multiplicative_generator = mcl_bn128_Fq("3"); + mcl_bn128_Fq::root_of_unity = mcl_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + mcl_bn128_Fq::nqr = mcl_bn128_Fq("3"); + mcl_bn128_Fq::nqr_to_t = mcl_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + + /* additional parameters for square roots in Fq/Fq2 */ + mcl_bn128_coeff_b = Fp(3); + mcl_bn128_Fq_s = 1; + mcl_bn128_Fq_nqr_to_t = Fp("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + mcl_bn128_Fq_t_minus_1_over_2 = mpz_class("5472060717959818805561601436314318772174077789324455915672259473661306552145"); + + mcl_bn128_twist_coeff_b = Fp2(Fp("19485874751759354771024239261021720505790618469301721065564631296452457478373"), + Fp("266929791119991161246907387137283842545076965332900288569378510910307636690")); + mcl_bn128_Fq2_s = 4; + mcl_bn128_Fq2_nqr_to_t = Fp2(Fp("5033503716262624267312492558379982687175200734934877598599011485707452665730"), + Fp("314498342015008975724433667930697407966947188435857772134235984660852259084")); + mcl_bn128_Fq2_t_minus_1_over_2 = mpz_class("14971724250519463826312126413021210649976634891596900701138993820439690427699319920245032869357433499099632259837909383182382988566862092145199781964621"); + + /* choice of group G1 */ + mcl_bn128_G1::G1_zero.pt.x = Fp(1); + mcl_bn128_G1::G1_zero.pt.y = Fp(1); + mcl_bn128_G1::G1_zero.pt.z = Fp(0); + + mcl_bn128_G1::G1_one.pt.x = Fp(1); + mcl_bn128_G1::G1_one.pt.y = Fp(2); + mcl_bn128_G1::G1_one.pt.z = Fp(1); + + mcl_bn128_G1::wnaf_window_table.resize(0); + mcl_bn128_G1::wnaf_window_table.push_back(10); + mcl_bn128_G1::wnaf_window_table.push_back(24); + mcl_bn128_G1::wnaf_window_table.push_back(40); + mcl_bn128_G1::wnaf_window_table.push_back(132); + + mcl_bn128_G1::fixed_base_exp_window_table.resize(0); + // window 1 is unbeaten in [-inf, 4.24] + mcl_bn128_G1::fixed_base_exp_window_table.push_back(1); + // window 2 is unbeaten in [4.24, 10.43] + mcl_bn128_G1::fixed_base_exp_window_table.push_back(4); + // window 3 is unbeaten in [10.43, 24.88] + mcl_bn128_G1::fixed_base_exp_window_table.push_back(10); + // window 4 is unbeaten in [24.88, 62.10] + mcl_bn128_G1::fixed_base_exp_window_table.push_back(25); + // window 5 is unbeaten in [62.10, 157.80] + mcl_bn128_G1::fixed_base_exp_window_table.push_back(62); + // window 6 is unbeaten in [157.80, 362.05] + mcl_bn128_G1::fixed_base_exp_window_table.push_back(158); + // window 7 is unbeaten in [362.05, 806.67] + mcl_bn128_G1::fixed_base_exp_window_table.push_back(362); + // window 8 is unbeaten in [806.67, 2090.34] + mcl_bn128_G1::fixed_base_exp_window_table.push_back(807); + // window 9 is unbeaten in [2090.34, 4459.58] + mcl_bn128_G1::fixed_base_exp_window_table.push_back(2090); + // window 10 is unbeaten in [4459.58, 9280.12] + mcl_bn128_G1::fixed_base_exp_window_table.push_back(4460); + // window 11 is unbeaten in [9280.12, 43302.64] + mcl_bn128_G1::fixed_base_exp_window_table.push_back(9280); + // window 12 is unbeaten in [43302.64, 210998.73] + mcl_bn128_G1::fixed_base_exp_window_table.push_back(43303); + // window 13 is never the best + mcl_bn128_G1::fixed_base_exp_window_table.push_back(0); + // window 14 is never the best + mcl_bn128_G1::fixed_base_exp_window_table.push_back(0); + // window 15 is unbeaten in [210998.73, 506869.47] + mcl_bn128_G1::fixed_base_exp_window_table.push_back(210999); + // window 16 is unbeaten in [506869.47, 930023.36] + mcl_bn128_G1::fixed_base_exp_window_table.push_back(506869); + // window 17 is unbeaten in [930023.36, 8350812.20] + mcl_bn128_G1::fixed_base_exp_window_table.push_back(930023); + // window 18 is never the best + mcl_bn128_G1::fixed_base_exp_window_table.push_back(0); + // window 19 is never the best + mcl_bn128_G1::fixed_base_exp_window_table.push_back(0); + // window 20 is unbeaten in [8350812.20, 21708138.87] + mcl_bn128_G1::fixed_base_exp_window_table.push_back(8350812); + // window 21 is unbeaten in [21708138.87, 29482995.52] + mcl_bn128_G1::fixed_base_exp_window_table.push_back(21708139); + // window 22 is unbeaten in [29482995.52, inf] + mcl_bn128_G1::fixed_base_exp_window_table.push_back(29482996); + + /* choice of group G2 */ + mcl_bn128_G2::G2_zero.pt.x = Fp2(Fp(1), Fp(0)); + mcl_bn128_G2::G2_zero.pt.y = Fp2(Fp(1), Fp(0)); + mcl_bn128_G2::G2_zero.pt.z = Fp2(Fp(0), Fp(0)); + + mcl_bn128_G2::G2_one.pt.x = Fp2(Fp("15267802884793550383558706039165621050290089775961208824303765753922461897946"), + Fp("9034493566019742339402378670461897774509967669562610788113215988055021632533")); + mcl_bn128_G2::G2_one.pt.y = Fp2(Fp("644888581738283025171396578091639672120333224302184904896215738366765861164"), + Fp("20532875081203448695448744255224543661959516361327385779878476709582931298750")); + mcl_bn128_G2::G2_one.pt.z = Fp2(Fp(1), Fp(0)); + + mcl_bn128_G2::wnaf_window_table.resize(0); + mcl_bn128_G2::wnaf_window_table.push_back(7); + mcl_bn128_G2::wnaf_window_table.push_back(18); + mcl_bn128_G2::wnaf_window_table.push_back(35); + mcl_bn128_G2::wnaf_window_table.push_back(116); + + mcl_bn128_G2::fixed_base_exp_window_table.resize(0); + // window 1 is unbeaten in [-inf, 4.13] + mcl_bn128_G2::fixed_base_exp_window_table.push_back(1); + // window 2 is unbeaten in [4.13, 10.72] + mcl_bn128_G2::fixed_base_exp_window_table.push_back(4); + // window 3 is unbeaten in [10.72, 25.60] + mcl_bn128_G2::fixed_base_exp_window_table.push_back(11); + // window 4 is unbeaten in [25.60, 60.99] + mcl_bn128_G2::fixed_base_exp_window_table.push_back(26); + // window 5 is unbeaten in [60.99, 153.66] + mcl_bn128_G2::fixed_base_exp_window_table.push_back(61); + // window 6 is unbeaten in [153.66, 353.13] + mcl_bn128_G2::fixed_base_exp_window_table.push_back(154); + // window 7 is unbeaten in [353.13, 771.87] + mcl_bn128_G2::fixed_base_exp_window_table.push_back(353); + // window 8 is unbeaten in [771.87, 2025.85] + mcl_bn128_G2::fixed_base_exp_window_table.push_back(772); + // window 9 is unbeaten in [2025.85, 4398.65] + mcl_bn128_G2::fixed_base_exp_window_table.push_back(2026); + // window 10 is unbeaten in [4398.65, 10493.42] + mcl_bn128_G2::fixed_base_exp_window_table.push_back(4399); + // window 11 is unbeaten in [10493.42, 37054.73] + mcl_bn128_G2::fixed_base_exp_window_table.push_back(10493); + // window 12 is unbeaten in [37054.73, 49928.78] + mcl_bn128_G2::fixed_base_exp_window_table.push_back(37055); + // window 13 is unbeaten in [49928.78, 114502.82] + mcl_bn128_G2::fixed_base_exp_window_table.push_back(49929); + // window 14 is unbeaten in [114502.82, 161445.26] + mcl_bn128_G2::fixed_base_exp_window_table.push_back(114503); + // window 15 is unbeaten in [161445.26, 470648.01] + mcl_bn128_G2::fixed_base_exp_window_table.push_back(161445); + // window 16 is unbeaten in [470648.01, 1059821.87] + mcl_bn128_G2::fixed_base_exp_window_table.push_back(470648); + // window 17 is unbeaten in [1059821.87, 5450848.25] + mcl_bn128_G2::fixed_base_exp_window_table.push_back(1059822); + // window 18 is never the best + mcl_bn128_G2::fixed_base_exp_window_table.push_back(0); + // window 19 is unbeaten in [5450848.25, 5566795.57] + mcl_bn128_G2::fixed_base_exp_window_table.push_back(5450848); + // window 20 is unbeaten in [5566795.57, 33055217.52] + mcl_bn128_G2::fixed_base_exp_window_table.push_back(5566796); + // window 21 is never the best + mcl_bn128_G2::fixed_base_exp_window_table.push_back(0); + // window 22 is unbeaten in [33055217.52, inf] + mcl_bn128_G2::fixed_base_exp_window_table.push_back(33055218); + + mcl_bn128_GT::GT_one.elem = Fp12(1); +} +} // libsnark diff --git a/src/algebra/curves/mcl_bn128/mcl_bn128_init.hpp b/src/algebra/curves/mcl_bn128/mcl_bn128_init.hpp new file mode 100644 index 00000000..70c79534 --- /dev/null +++ b/src/algebra/curves/mcl_bn128/mcl_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 MCL_BN128_INIT_HPP_ +#define MCL_BN128_INIT_HPP_ +#include "algebra/curves/public_params.hpp" +#include "algebra/fields/fp.hpp" +#include "mcl/bn256.hpp" // If you're missing this file, run libsnark's ./prepare-depends.sh + +namespace libsnark { + +const mp_size_t mcl_bn128_r_bitcount = 254; +const mp_size_t mcl_bn128_q_bitcount = 254; + +const mp_size_t mcl_bn128_r_limbs = (mcl_bn128_r_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; +const mp_size_t mcl_bn128_q_limbs = (mcl_bn128_q_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; + +extern bigint mcl_bn128_modulus_r; +extern bigint mcl_bn128_modulus_q; + +extern mcl::bn256::Fp mcl_bn128_coeff_b; +extern size_t mcl_bn128_Fq_s; +extern mcl::bn256::Fp mcl_bn128_Fq_nqr_to_t; +extern mpz_class mcl_bn128_Fq_t_minus_1_over_2; + +extern mcl::bn256::Fp2 mcl_bn128_twist_coeff_b; +extern size_t mcl_bn128_Fq2_s; +extern mcl::bn256::Fp2 mcl_bn128_Fq2_nqr_to_t; +extern mpz_class mcl_bn128_Fq2_t_minus_1_over_2; + +typedef Fp_model mcl_bn128_Fr; +typedef Fp_model mcl_bn128_Fq; + +void init_mcl_bn128_params(); + +class mcl_bn128_G1; +class mcl_bn128_G2; +class mcl_bn128_GT; +typedef mcl_bn128_GT mcl_bn128_Fq12; + +} // libsnark +#endif // MCL_BN128_INIT_HPP_ diff --git a/src/algebra/curves/mcl_bn128/mcl_bn128_pairing.cpp b/src/algebra/curves/mcl_bn128/mcl_bn128_pairing.cpp new file mode 100644 index 00000000..35923689 --- /dev/null +++ b/src/algebra/curves/mcl_bn128/mcl_bn128_pairing.cpp @@ -0,0 +1,165 @@ +/** @file + ******************************************************************************** + Implements functions for computing Ate pairings over the mcl_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/mcl_bn128/mcl_bn128_pairing.hpp" +#include "common/profiling.hpp" +#include "algebra/curves/mcl_bn128/mcl_bn128_init.hpp" +#include "algebra/curves/mcl_bn128/mcl_bn128_g1.hpp" +#include "algebra/curves/mcl_bn128/mcl_bn128_g2.hpp" +#include "algebra/curves/mcl_bn128/mcl_bn128_gt.hpp" + +using namespace mcl::bn256; + +namespace libsnark { + +bool mcl_bn128_ate_G1_precomp::operator==(const mcl_bn128_ate_G1_precomp &other) const +{ + return this->P == other.P; +} + +std::ostream& operator<<(std::ostream &out, const mcl_bn128_ate_G1_precomp &precP) +{ +#ifndef BINARY_OUTPUT + out << precP.P << "\n"; +#else + out.write((char*) &precP.P, sizeof(precP.P)); +#endif + return out; +} + +std::istream& operator>>(std::istream &in, mcl_bn128_ate_G1_precomp &precP) +{ +#ifndef BINARY_OUTPUT + in >> precP.P; + consume_newline(in); +#else + in.read((char*) &precP.P, sizeof(precP.P)); +#endif + return in; +} + +bool mcl_bn128_ate_G2_precomp::operator==(const mcl_bn128_ate_G2_precomp &other) const +{ + if (!(this->Q == other.Q && this->coeffs.size() == other.coeffs.size())) + { + return false; + } + + for (size_t i = 0; i < this->coeffs.size(); ++i) + { + if (this->coeffs[i] != other.coeffs[i]) + { + return false; + } + } + + return true; +} + +std::ostream& operator<<(std::ostream &out, const mcl_bn128_ate_G2_precomp &precQ) +{ +#ifndef BINARY_OUTPUT + out << precQ.Q << "\n"; +#else + out.write((char*) &precQ.Q, sizeof(precQ.Q)); +#endif + + out << precQ.coeffs.size() << "\n"; + + for (size_t i = 0; i < precQ.coeffs.size(); ++i) + { +#ifndef BINARY_OUTPUT + out << precQ.coeffs[i] << "\n"; +#else + out.write((char*) &precQ.coeffs[i], sizeof(precQ.coeffs[i])); +#endif + } + + return out; +} + +std::istream& operator>>(std::istream &in, mcl_bn128_ate_G2_precomp &precQ) +{ +#ifndef BINARY_OUTPUT + in >> precQ.Q; + consume_newline(in); +#else + in.read((char*) &precQ.Q, sizeof(precQ.Q)); +#endif + + size_t count; + in >> count; + consume_newline(in); + precQ.coeffs.resize(count); + for (size_t i = 0; i < count; ++i) + { +#ifndef BINARY_OUTPUT + in >> precQ.coeffs[i]; + consume_newline(in); +#else + in.read((char*) &precQ.coeffs[i], sizeof(precQ.coeffs[i])); +#endif + } + return in; +} + +mcl_bn128_ate_G1_precomp mcl_bn128_ate_precompute_G1(const mcl_bn128_G1& P) +{ + enter_block("Call to mcl_bn128_ate_precompute_G1"); + + mcl_bn128_ate_G1_precomp result; + result.P = P.pt; + result.P.normalize(); + + leave_block("Call to mcl_bn128_ate_precompute_G1"); + return result; +} + +mcl_bn128_ate_G2_precomp mcl_bn128_ate_precompute_G2(const mcl_bn128_G2& Q) +{ + enter_block("Call to mcl_bn128_ate_precompute_G2"); + + mcl_bn128_ate_G2_precomp result; + result.Q = Q.pt; + mcl::bn256::BN::precomputeG2(result.coeffs, result.Q); + + leave_block("Call to mcl_bn128_ate_precompute_G2"); + return result; +} + +mcl_bn128_Fq12 mcl_bn128_ate_miller_loop(const mcl_bn128_ate_G1_precomp &precP, + const mcl_bn128_ate_G2_precomp &precQ) +{ + mcl_bn128_Fq12 f; + mcl::bn256::BN::precomputedMillerLoop(f.elem, precP.P, precQ.coeffs); + return f; +} + +mcl_bn128_Fq12 mcl_bn128_double_ate_miller_loop(const mcl_bn128_ate_G1_precomp &precP1, + const mcl_bn128_ate_G2_precomp &precQ1, + const mcl_bn128_ate_G1_precomp &precP2, + const mcl_bn128_ate_G2_precomp &precQ2) +{ + mcl_bn128_Fq12 f; + mcl::bn256::BN::precomputedMillerLoop2(f.elem, precP1.P, precQ1.coeffs, precP2.P, precQ2.coeffs); + return f; +} + +mcl_bn128_GT mcl_bn128_final_exponentiation(const mcl_bn128_Fq12 &elt) +{ + enter_block("Call to mcl_bn128_final_exponentiation"); + mcl_bn128_GT eltcopy; + mcl::bn256::BN::finalExp(eltcopy.elem, elt.elem); + leave_block("Call to mcl_bn128_final_exponentiation"); + return eltcopy; +} +} // libsnark diff --git a/src/algebra/curves/mcl_bn128/mcl_bn128_pairing.hpp b/src/algebra/curves/mcl_bn128/mcl_bn128_pairing.hpp new file mode 100644 index 00000000..d2aaccec --- /dev/null +++ b/src/algebra/curves/mcl_bn128/mcl_bn128_pairing.hpp @@ -0,0 +1,52 @@ +/** @file + ******************************************************************************** + Declares functions for computing Ate pairings over the mcl_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 MCL_BN128_PAIRING_HPP_ +#define MCL_BN128_PAIRING_HPP_ +#include "algebra/curves/mcl_bn128/mcl_bn128_g1.hpp" +#include "algebra/curves/mcl_bn128/mcl_bn128_g2.hpp" +#include "algebra/curves/mcl_bn128/mcl_bn128_gt.hpp" +#include "mcl/bn256.hpp" + +namespace libsnark { + +struct mcl_bn128_ate_G1_precomp { + mcl::bn256::G1 P; + + bool operator==(const mcl_bn128_ate_G1_precomp &other) const; + friend std::ostream& operator<<(std::ostream &out, const mcl_bn128_ate_G1_precomp &prec_P); + friend std::istream& operator>>(std::istream &in, mcl_bn128_ate_G1_precomp &prec_P); +}; + +typedef mcl::bn256::Fp6 mcl_bn128_ate_ell_coeffs; + +struct mcl_bn128_ate_G2_precomp { + mcl::bn256::G2 Q; + std::vector coeffs; + + bool operator==(const mcl_bn128_ate_G2_precomp &other) const; + friend std::ostream& operator<<(std::ostream &out, const mcl_bn128_ate_G2_precomp &prec_Q); + friend std::istream& operator>>(std::istream &in, mcl_bn128_ate_G2_precomp &prec_Q); +}; + +mcl_bn128_ate_G1_precomp mcl_bn128_ate_precompute_G1(const mcl_bn128_G1& P); +mcl_bn128_ate_G2_precomp mcl_bn128_ate_precompute_G2(const mcl_bn128_G2& Q); + +mcl_bn128_Fq12 mcl_bn128_double_ate_miller_loop(const mcl_bn128_ate_G1_precomp &prec_P1, + const mcl_bn128_ate_G2_precomp &prec_Q1, + const mcl_bn128_ate_G1_precomp &prec_P2, + const mcl_bn128_ate_G2_precomp &prec_Q2); +mcl_bn128_Fq12 mcl_bn128_ate_miller_loop(const mcl_bn128_ate_G1_precomp &prec_P, + const mcl_bn128_ate_G2_precomp &prec_Q); + +mcl_bn128_GT mcl_bn128_final_exponentiation(const mcl_bn128_Fq12 &elt); + +} // libsnark +#endif // MCL_BN128_PAIRING_HPP_ diff --git a/src/algebra/curves/mcl_bn128/mcl_bn128_pp.cpp b/src/algebra/curves/mcl_bn128/mcl_bn128_pp.cpp new file mode 100644 index 00000000..dc3bbb85 --- /dev/null +++ b/src/algebra/curves/mcl_bn128/mcl_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/mcl_bn128/mcl_bn128_pp.hpp" +#include "common/profiling.hpp" + +namespace libsnark { + +void mcl_bn128_pp::init_public_params() +{ + init_mcl_bn128_params(); +} + +mcl_bn128_GT mcl_bn128_pp::final_exponentiation(const mcl_bn128_GT &elt) +{ + return mcl_bn128_final_exponentiation(elt); +} + +mcl_bn128_ate_G1_precomp mcl_bn128_pp::precompute_G1(const mcl_bn128_G1 &P) +{ + return mcl_bn128_ate_precompute_G1(P); +} + +mcl_bn128_ate_G2_precomp mcl_bn128_pp::precompute_G2(const mcl_bn128_G2 &Q) +{ + return mcl_bn128_ate_precompute_G2(Q); +} + +mcl_bn128_Fq12 mcl_bn128_pp::miller_loop(const mcl_bn128_ate_G1_precomp &prec_P, + const mcl_bn128_ate_G2_precomp &prec_Q) +{ + enter_block("Call to miller_loop"); + mcl_bn128_Fq12 result = mcl_bn128_ate_miller_loop(prec_P, prec_Q); + leave_block("Call to miller_loop"); + return result; +} + +mcl_bn128_Fq12 mcl_bn128_pp::double_miller_loop(const mcl_bn128_ate_G1_precomp &prec_P1, + const mcl_bn128_ate_G2_precomp &prec_Q1, + const mcl_bn128_ate_G1_precomp &prec_P2, + const mcl_bn128_ate_G2_precomp &prec_Q2) +{ + enter_block("Call to double_miller_loop"); + mcl_bn128_Fq12 result = mcl_bn128_double_ate_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); + leave_block("Call to double_miller_loop"); + return result; +} + +mcl_bn128_Fq12 mcl_bn128_pp::pairing(const mcl_bn128_G1 &P, + const mcl_bn128_G2 &Q) +{ + enter_block("Call to pairing"); + mcl_bn128_ate_G1_precomp prec_P = mcl_bn128_pp::precompute_G1(P); + mcl_bn128_ate_G2_precomp prec_Q = mcl_bn128_pp::precompute_G2(Q); + + mcl_bn128_Fq12 result = mcl_bn128_pp::miller_loop(prec_P, prec_Q); + leave_block("Call to pairing"); + return result; +} + +mcl_bn128_GT mcl_bn128_pp::reduced_pairing(const mcl_bn128_G1 &P, + const mcl_bn128_G2 &Q) +{ + enter_block("Call to reduced_pairing"); + const mcl_bn128_Fq12 f = mcl_bn128_pp::pairing(P, Q); + const mcl_bn128_GT result = mcl_bn128_pp::final_exponentiation(f); + leave_block("Call to reduced_pairing"); + return result; +} + +} // libsnark diff --git a/src/algebra/curves/mcl_bn128/mcl_bn128_pp.hpp b/src/algebra/curves/mcl_bn128/mcl_bn128_pp.hpp new file mode 100644 index 00000000..af043521 --- /dev/null +++ b/src/algebra/curves/mcl_bn128/mcl_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 MCL_BN128_PP_HPP_ +#define MCL_BN128_PP_HPP_ +#include "algebra/curves/public_params.hpp" +#include "algebra/curves/mcl_bn128/mcl_bn128_init.hpp" +#include "algebra/curves/mcl_bn128/mcl_bn128_g1.hpp" +#include "algebra/curves/mcl_bn128/mcl_bn128_g2.hpp" +#include "algebra/curves/mcl_bn128/mcl_bn128_gt.hpp" +#include "algebra/curves/mcl_bn128/mcl_bn128_pairing.hpp" + +namespace libsnark { + +class mcl_bn128_pp { +public: + typedef mcl_bn128_Fr Fp_type; + typedef mcl_bn128_G1 G1_type; + typedef mcl_bn128_G2 G2_type; + typedef mcl_bn128_ate_G1_precomp G1_precomp_type; + typedef mcl_bn128_ate_G2_precomp G2_precomp_type; + typedef mcl_bn128_Fq Fq_type; + typedef mcl_bn128_Fq12 Fqk_type; + typedef mcl_bn128_GT GT_type; + + static const bool has_affine_pairing = false; + + static void init_public_params(); + static mcl_bn128_GT final_exponentiation(const mcl_bn128_Fq12 &elt); + static mcl_bn128_ate_G1_precomp precompute_G1(const mcl_bn128_G1 &P); + static mcl_bn128_ate_G2_precomp precompute_G2(const mcl_bn128_G2 &Q); + static mcl_bn128_Fq12 miller_loop(const mcl_bn128_ate_G1_precomp &prec_P, + const mcl_bn128_ate_G2_precomp &prec_Q); + static mcl_bn128_Fq12 double_miller_loop(const mcl_bn128_ate_G1_precomp &prec_P1, + const mcl_bn128_ate_G2_precomp &prec_Q1, + const mcl_bn128_ate_G1_precomp &prec_P2, + const mcl_bn128_ate_G2_precomp &prec_Q2); + + /* the following are used in test files */ + static mcl_bn128_GT pairing(const mcl_bn128_G1 &P, + const mcl_bn128_G2 &Q); + static mcl_bn128_GT reduced_pairing(const mcl_bn128_G1 &P, + const mcl_bn128_G2 &Q); +}; + +} // libsnark +#endif // MCL_BN128_PP_HPP_ diff --git a/src/algebra/curves/tests/test_bilinearity.cpp b/src/algebra/curves/tests/test_bilinearity.cpp index 29574528..af5e1a66 100644 --- a/src/algebra/curves/tests/test_bilinearity.cpp +++ b/src/algebra/curves/tests/test_bilinearity.cpp @@ -9,6 +9,9 @@ #ifdef CURVE_BN128 #include "algebra/curves/bn128/bn128_pp.hpp" #endif +#ifdef CURVE_MCL_BN128 +#include "algebra/curves/mcl_bn128/mcl_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" @@ -133,4 +136,10 @@ int main(void) pairing_test(); double_miller_loop_test(); #endif + +#ifdef CURVE_MCL_BN128 + mcl_bn128_pp::init_public_params(); + pairing_test(); + double_miller_loop_test(); +#endif } diff --git a/src/algebra/curves/tests/test_groups.cpp b/src/algebra/curves/tests/test_groups.cpp index 725e490d..9e4d2339 100644 --- a/src/algebra/curves/tests/test_groups.cpp +++ b/src/algebra/curves/tests/test_groups.cpp @@ -11,6 +11,9 @@ #ifdef CURVE_BN128 #include "algebra/curves/bn128/bn128_pp.hpp" #endif +#ifdef CURVE_MCL_BN128 +#include "algebra/curves/mcl_bn128/mcl_bn128_pp.hpp" +#endif #include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" #include @@ -172,4 +175,12 @@ int main(void) test_group >(); test_output >(); #endif + +#ifdef CURVE_MCL_BN128 + mcl_bn128_pp::init_public_params(); + test_group >(); + test_output >(); + test_group >(); + test_output >(); +#endif } diff --git a/src/algebra/fields/tests/test_fields.cpp b/src/algebra/fields/tests/test_fields.cpp index a05f601e..93ee2748 100644 --- a/src/algebra/fields/tests/test_fields.cpp +++ b/src/algebra/fields/tests/test_fields.cpp @@ -11,6 +11,9 @@ #ifdef CURVE_BN128 #include "algebra/curves/bn128/bn128_pp.hpp" #endif +#ifdef CURVE_MCL_BN128 +#include "algebra/curves/mcl_bn128/mcl_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" @@ -242,4 +245,10 @@ int main(void) test_field >(); test_field >(); #endif + +#ifdef CURVE_MCL_BN128 + mcl_bn128_pp::init_public_params(); + test_field >(); + test_field >(); +#endif } diff --git a/src/common/default_types/ec_pp.hpp b/src/common/default_types/ec_pp.hpp index b08c2da8..92d26094 100644 --- a/src/common/default_types/ec_pp.hpp +++ b/src/common/default_types/ec_pp.hpp @@ -29,6 +29,13 @@ typedef bn128_pp default_ec_pp; } // libsnark #endif +#ifdef CURVE_MCL_BN128 +#include "algebra/curves/mcl_bn128/mcl_bn128_pp.hpp" +namespace libsnark { +typedef mcl_bn128_pp default_ec_pp; +} // libsnark +#endif + #ifdef CURVE_EDWARDS #include "algebra/curves/edwards/edwards_pp.hpp" namespace libsnark {