Fix libsnark dependency build.

This changes libsnark to build in-place, instead of copying first to
a build directory. Previously, modifications made to the original
sources wouldn't get rebuilt without a 'make clean' because users
would be pointing to the copies.

This closes #2689.
This commit is contained in:
syd
2017-11-24 13:54:17 -05:00
parent 7888624f74
commit a55c186a74
119 changed files with 114 additions and 119 deletions

View File

@@ -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<size_t> alt_bn128_G1::wnaf_window_table;
std::vector<size_t> 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<alt_bn128_G1> &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<alt_bn128_G1> &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<alt_bn128_G1>(std::vector<alt_bn128_G1> &vec)
{
std::vector<alt_bn128_Fq> Z_vec;
Z_vec.reserve(vec.size());
for (auto &el: vec)
{
Z_vec.emplace_back(el.Z);
}
batch_invert<alt_bn128_Fq>(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

View File

@@ -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 <vector>
#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<size_t> wnaf_window_table;
static std::vector<size_t> 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::num_limbs> base_field_char() { return base_field::field_char(); }
static bigint<scalar_field::num_limbs> 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<mp_size_t m>
alt_bn128_G1 operator*(const bigint<m> &lhs, const alt_bn128_G1 &rhs)
{
return scalar_mul<alt_bn128_G1, m>(rhs, lhs);
}
template<mp_size_t m, const bigint<m>& modulus_p>
alt_bn128_G1 operator*(const Fp_model<m,modulus_p> &lhs, const alt_bn128_G1 &rhs)
{
return scalar_mul<alt_bn128_G1, m>(rhs, lhs.as_bigint());
}
std::ostream& operator<<(std::ostream& out, const std::vector<alt_bn128_G1> &v);
std::istream& operator>>(std::istream& in, std::vector<alt_bn128_G1> &v);
template<typename T>
void batch_to_special_all_non_zeros(std::vector<T> &vec);
template<>
void batch_to_special_all_non_zeros<alt_bn128_G1>(std::vector<alt_bn128_G1> &vec);
} // libsnark
#endif // ALT_BN128_G1_HPP_

View File

@@ -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<size_t> alt_bn128_G2::wnaf_window_table;
std::vector<size_t> 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<alt_bn128_G2>(std::vector<alt_bn128_G2> &vec)
{
std::vector<alt_bn128_Fq2> Z_vec;
Z_vec.reserve(vec.size());
for (auto &el: vec)
{
Z_vec.emplace_back(el.Z);
}
batch_invert<alt_bn128_Fq2>(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

View File

@@ -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 <vector>
#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<size_t> wnaf_window_table;
static std::vector<size_t> 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::num_limbs> base_field_char() { return base_field::field_char(); }
static bigint<scalar_field::num_limbs> 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<mp_size_t m>
alt_bn128_G2 operator*(const bigint<m> &lhs, const alt_bn128_G2 &rhs)
{
return scalar_mul<alt_bn128_G2, m>(rhs, lhs);
}
template<mp_size_t m, const bigint<m>& modulus_p>
alt_bn128_G2 operator*(const Fp_model<m,modulus_p> &lhs, const alt_bn128_G2 &rhs)
{
return scalar_mul<alt_bn128_G2, m>(rhs, lhs.as_bigint());
}
template<typename T>
void batch_to_special_all_non_zeros(std::vector<T> &vec);
template<>
void batch_to_special_all_non_zeros<alt_bn128_G2>(std::vector<alt_bn128_G2> &vec);
} // libsnark
#endif // ALT_BN128_G2_HPP_

View File

@@ -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_r_limbs> alt_bn128_modulus_r;
bigint<alt_bn128_q_limbs> 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_q_limbs> 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_q_limbs> alt_bn128_final_exponent_z;
bool alt_bn128_final_exponent_is_z_neg;
void init_alt_bn128_params()
{
typedef bigint<alt_bn128_r_limbs> bigint_r;
typedef bigint<alt_bn128_q_limbs> 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

View File

@@ -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_r_limbs> alt_bn128_modulus_r;
extern bigint<alt_bn128_q_limbs> alt_bn128_modulus_q;
typedef Fp_model<alt_bn128_r_limbs, alt_bn128_modulus_r> alt_bn128_Fr;
typedef Fp_model<alt_bn128_q_limbs, alt_bn128_modulus_q> alt_bn128_Fq;
typedef Fp2_model<alt_bn128_q_limbs, alt_bn128_modulus_q> alt_bn128_Fq2;
typedef Fp6_3over2_model<alt_bn128_q_limbs, alt_bn128_modulus_q> alt_bn128_Fq6;
typedef Fp12_2over3over2_model<alt_bn128_q_limbs, alt_bn128_modulus_q> 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_q_limbs> 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_q_limbs> 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_

View File

@@ -0,0 +1,547 @@
/** @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 <cassert>
#include "common/profiling.hpp"
#include "common/assert_except.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 &current,
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 &current,
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<alt_bn128_Fr::num_limbs> &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_except(Q1.Z == alt_bn128_Fq2::one());
alt_bn128_G2 Q2 = Q1.mul_by_q();
assert_except(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<alt_bn128_Fr::num_limbs> &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<alt_bn128_Fr::num_limbs> &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

View File

@@ -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 <vector>
#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<alt_bn128_ate_ell_coeffs> 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_

View File

@@ -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

View File

@@ -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_

View File

@@ -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 <cstdint>
#include "algebra/fields/bigint.hpp"
namespace libsnark {
template<typename GroupT, mp_size_t m>
GroupT scalar_mul(const GroupT &base, const bigint<m> &scalar);
} // libsnark
#include "algebra/curves/curve_utils.tcc"
#endif // CURVE_UTILS_HPP_

View File

@@ -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<typename GroupT, mp_size_t m>
GroupT scalar_mul(const GroupT &base, const bigint<m> &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_

View File

@@ -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 <vector>
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<EC_ppT> final_exponentiation(const Fqk<EC_ppT> &elt);
G1_precomp<EC_ppT> precompute_G1(const G1<EC_ppT> &P);
G2_precomp<EC_ppT> precompute_G2(const G2<EC_ppT> &Q);
Fqk<EC_ppT> miller_loop(const G1_precomp<EC_ppT> &prec_P,
const G2_precomp<EC_ppT> &prec_Q);
affine_ate_G1_precomp<EC_ppT> affine_ate_precompute_G1(const G1<EC_ppT> &P);
affine_ate_G2_precomp<EC_ppT> affine_ate_precompute_G2(const G2<EC_ppT> &Q);
Fqk<EC_ppT> affine_ate_miller_loop(const affine_ate_G1_precomp<EC_ppT> &prec_P,
const affine_ate_G2_precomp<EC_ppT> &prec_Q);
Fqk<EC_ppT> affine_ate_e_over_e_miller_loop(const affine_ate_G1_precomp<EC_ppT> &prec_P1,
const affine_ate_G2_precomp<EC_ppT> &prec_Q1,
const affine_ate_G1_precomp<EC_ppT> &prec_P2,
const affine_ate_G2_precomp<EC_ppT> &prec_Q2);
Fqk<EC_ppT> affine_ate_e_times_e_over_e_miller_loop(const affine_ate_G1_precomp<EC_ppT> &prec_P1,
const affine_ate_G2_precomp<EC_ppT> &prec_Q1,
const affine_ate_G1_precomp<EC_ppT> &prec_P2,
const affine_ate_G2_precomp<EC_ppT> &prec_Q2,
const affine_ate_G1_precomp<EC_ppT> &prec_P3,
const affine_ate_G2_precomp<EC_ppT> &prec_Q3);
Fqk<EC_ppT> double_miller_loop(const G1_precomp<EC_ppT> &prec_P1,
const G2_precomp<EC_ppT> &prec_Q1,
const G1_precomp<EC_ppT> &prec_P2,
const G2_precomp<EC_ppT> &prec_Q2);
Fqk<EC_ppT> pairing(const G1<EC_ppT> &P,
const G2<EC_ppT> &Q);
GT<EC_ppT> reduced_pairing(const G1<EC_ppT> &P,
const G2<EC_ppT> &Q);
GT<EC_ppT> affine_reduced_pairing(const G1<EC_ppT> &P,
const G2<EC_ppT> &Q);
*/
template<typename EC_ppT>
using Fr = typename EC_ppT::Fp_type;
template<typename EC_ppT>
using G1 = typename EC_ppT::G1_type;
template<typename EC_ppT>
using G2 = typename EC_ppT::G2_type;
template<typename EC_ppT>
using G1_precomp = typename EC_ppT::G1_precomp_type;
template<typename EC_ppT>
using G2_precomp = typename EC_ppT::G2_precomp_type;
template<typename EC_ppT>
using affine_ate_G1_precomp = typename EC_ppT::affine_ate_G1_precomp_type;
template<typename EC_ppT>
using affine_ate_G2_precomp = typename EC_ppT::affine_ate_G2_precomp_type;
template<typename EC_ppT>
using Fq = typename EC_ppT::Fq_type;
template<typename EC_ppT>
using Fqe = typename EC_ppT::Fqe_type;
template<typename EC_ppT>
using Fqk = typename EC_ppT::Fqk_type;
template<typename EC_ppT>
using GT = typename EC_ppT::GT_type;
template<typename EC_ppT>
using Fr_vector = std::vector<Fr<EC_ppT> >;
template<typename EC_ppT>
using G1_vector = std::vector<G1<EC_ppT> >;
template<typename EC_ppT>
using G2_vector = std::vector<G2<EC_ppT> >;
} // libsnark
#endif // PUBLIC_PARAMS_HPP_

View File

@@ -0,0 +1,121 @@
/**
*****************************************************************************
* @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"
#ifdef CURVE_BN128
#include "algebra/curves/bn128/bn128_pp.hpp"
#endif
#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp"
#include <gtest/gtest.h>
using namespace libsnark;
template<typename ppT>
void pairing_test()
{
GT<ppT> GT_one = GT<ppT>::one();
printf("Running bilinearity tests:\n");
G1<ppT> P = (Fr<ppT>::random_element()) * G1<ppT>::one();
//G1<ppT> P = Fr<ppT>("2") * G1<ppT>::one();
G2<ppT> Q = (Fr<ppT>::random_element()) * G2<ppT>::one();
//G2<ppT> Q = Fr<ppT>("3") * G2<ppT>::one();
printf("P:\n");
P.print();
P.print_coordinates();
printf("Q:\n");
Q.print();
Q.print_coordinates();
printf("\n\n");
Fr<ppT> s = Fr<ppT>::random_element();
//Fr<ppT> s = Fr<ppT>("2");
G1<ppT> sP = s * P;
G2<ppT> sQ = s * Q;
printf("Pairing bilinearity tests (three must match):\n");
GT<ppT> ans1 = ppT::reduced_pairing(sP, Q);
GT<ppT> ans2 = ppT::reduced_pairing(P, sQ);
GT<ppT> ans3 = ppT::reduced_pairing(P, Q)^s;
ans1.print();
ans2.print();
ans3.print();
EXPECT_EQ(ans1, ans2);
EXPECT_EQ(ans2, ans3);
EXPECT_NE(ans1, GT_one);
EXPECT_EQ((ans1^Fr<ppT>::field_char()), GT_one);
printf("\n\n");
}
template<typename ppT>
void double_miller_loop_test()
{
const G1<ppT> P1 = (Fr<ppT>::random_element()) * G1<ppT>::one();
const G1<ppT> P2 = (Fr<ppT>::random_element()) * G1<ppT>::one();
const G2<ppT> Q1 = (Fr<ppT>::random_element()) * G2<ppT>::one();
const G2<ppT> Q2 = (Fr<ppT>::random_element()) * G2<ppT>::one();
const G1_precomp<ppT> prec_P1 = ppT::precompute_G1(P1);
const G1_precomp<ppT> prec_P2 = ppT::precompute_G1(P2);
const G2_precomp<ppT> prec_Q1 = ppT::precompute_G2(Q1);
const G2_precomp<ppT> prec_Q2 = ppT::precompute_G2(Q2);
const Fqk<ppT> ans_1 = ppT::miller_loop(prec_P1, prec_Q1);
const Fqk<ppT> ans_2 = ppT::miller_loop(prec_P2, prec_Q2);
const Fqk<ppT> ans_12 = ppT::double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2);
EXPECT_EQ(ans_1 * ans_2, ans_12);
}
template<typename ppT>
void affine_pairing_test()
{
GT<ppT> GT_one = GT<ppT>::one();
printf("Running bilinearity tests:\n");
G1<ppT> P = (Fr<ppT>::random_element()) * G1<ppT>::one();
G2<ppT> Q = (Fr<ppT>::random_element()) * G2<ppT>::one();
printf("P:\n");
P.print();
printf("Q:\n");
Q.print();
printf("\n\n");
Fr<ppT> s = Fr<ppT>::random_element();
G1<ppT> sP = s * P;
G2<ppT> sQ = s * Q;
printf("Pairing bilinearity tests (three must match):\n");
GT<ppT> ans1 = ppT::affine_reduced_pairing(sP, Q);
GT<ppT> ans2 = ppT::affine_reduced_pairing(P, sQ);
GT<ppT> ans3 = ppT::affine_reduced_pairing(P, Q)^s;
ans1.print();
ans2.print();
ans3.print();
EXPECT_EQ(ans1, ans2);
EXPECT_EQ(ans2, ans3);
EXPECT_NE(ans1, GT_one);
EXPECT_EQ((ans1^Fr<ppT>::field_char()), GT_one);
printf("\n\n");
}
TEST(algebra, bilinearity)
{
start_profiling();
alt_bn128_pp::init_public_params();
pairing_test<alt_bn128_pp>();
double_miller_loop_test<alt_bn128_pp>();
#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled
bn128_pp::init_public_params();
pairing_test<bn128_pp>();
double_miller_loop_test<bn128_pp>();
#endif
}

View File

@@ -0,0 +1,153 @@
/**
*****************************************************************************
* @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"
#ifdef CURVE_BN128
#include "algebra/curves/bn128/bn128_pp.hpp"
#endif
#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp"
#include <sstream>
#include <gtest/gtest.h>
using namespace libsnark;
template<typename GroupT>
void test_mixed_add()
{
GroupT base, el, result;
base = GroupT::zero();
el = GroupT::zero();
el.to_special();
result = base.mixed_add(el);
EXPECT_EQ(result, base + el);
base = GroupT::zero();
el = GroupT::random_element();
el.to_special();
result = base.mixed_add(el);
EXPECT_EQ(result, base + el);
base = GroupT::random_element();
el = GroupT::zero();
el.to_special();
result = base.mixed_add(el);
EXPECT_EQ(result, base + el);
base = GroupT::random_element();
el = GroupT::random_element();
el.to_special();
result = base.mixed_add(el);
EXPECT_EQ(result, base + el);
base = GroupT::random_element();
el = base;
el.to_special();
result = base.mixed_add(el);
EXPECT_EQ(result, base.dbl());
}
template<typename GroupT>
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();
EXPECT_EQ(zero, zero);
GroupT one = GroupT::one();
EXPECT_EQ(one, one);
GroupT two = bigint<1>(2l) * GroupT::one();
EXPECT_EQ(two, two);
GroupT five = bigint<1>(5l) * GroupT::one();
GroupT three = bigint<1>(3l) * GroupT::one();
GroupT four = bigint<1>(4l) * GroupT::one();
EXPECT_EQ(two+five, three+four);
GroupT a = GroupT::random_element();
GroupT b = GroupT::random_element();
EXPECT_NE(one, zero);
EXPECT_NE(a, zero);
EXPECT_NE(a, one);
EXPECT_NE(b, zero);
EXPECT_NE(b, one);
EXPECT_EQ(a.dbl(), a + a);
EXPECT_EQ(b.dbl(), b + b);
EXPECT_EQ(one.add(two), three);
EXPECT_EQ(two.add(one), three);
EXPECT_EQ(a + b, b + a);
EXPECT_EQ(a - a, zero);
EXPECT_EQ(a - b, a + (-b));
EXPECT_EQ(a - b, (-b) + a);
// handle special cases
EXPECT_EQ(zero + (-a), -a);
EXPECT_EQ(zero - a, -a);
EXPECT_EQ(a - zero, a);
EXPECT_EQ(a + zero, a);
EXPECT_EQ(zero + a, a);
EXPECT_EQ((a + b).dbl(), (a + b) + (b + a));
EXPECT_EQ(bigint<1>("2") * (a + b), (a + b) + (b + a));
EXPECT_EQ((rand1 * a) + (rand2 * a), (randsum * a));
EXPECT_EQ(GroupT::order() * a, zero);
EXPECT_EQ(GroupT::order() * one, zero);
EXPECT_NE((GroupT::order() * a) - a, zero);
EXPECT_NE((GroupT::order() * one) - one, zero);
test_mixed_add<GroupT>();
}
template<typename GroupT>
void test_mul_by_q()
{
GroupT a = GroupT::random_element();
EXPECT_EQ((GroupT::base_field_char()*a), a.mul_by_q());
}
template<typename GroupT>
void test_output()
{
GroupT g = GroupT::zero();
for (size_t i = 0; i < 1000; ++i)
{
std::stringstream ss;
ss << g;
GroupT gg;
ss >> gg;
EXPECT_EQ(g, gg);
/* use a random point in next iteration */
g = GroupT::random_element();
}
}
TEST(algebra, groups)
{
alt_bn128_pp::init_public_params();
test_group<G1<alt_bn128_pp> >();
test_output<G1<alt_bn128_pp> >();
test_group<G2<alt_bn128_pp> >();
test_output<G2<alt_bn128_pp> >();
test_mul_by_q<G2<alt_bn128_pp> >();
#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled
bn128_pp::init_public_params();
test_group<G1<bn128_pp> >();
test_output<G1<bn128_pp> >();
test_group<G2<bn128_pp> >();
test_output<G2<bn128_pp> >();
#endif
}