1 /** @file
2  ********************************************************************************
3  Implements functions for computing Ate pairings over the bn128 curves, split into a
4  offline and online stages.
5  ********************************************************************************
6  * @author     This file is part of libff, developed by SCIPR Lab
7  *             and contributors (see AUTHORS).
8  * @copyright  MIT license (see LICENSE file)
9  *******************************************************************************/
10 
11 #include <sstream>
12 
13 #include <libff/algebra/curves/bn128/bn128_g1.hpp>
14 #include <libff/algebra/curves/bn128/bn128_g2.hpp>
15 #include <libff/algebra/curves/bn128/bn128_gt.hpp>
16 #include <libff/algebra/curves/bn128/bn128_init.hpp>
17 #include <libff/algebra/curves/bn128/bn128_pairing.hpp>
18 #include <libff/common/profiling.hpp>
19 
20 namespace libff {
21 
operator ==(const bn128_ate_G1_precomp & other) const22 bool bn128_ate_G1_precomp::operator==(const bn128_ate_G1_precomp &other) const
23 {
24     return (this->P[0] == other.P[0] &&
25             this->P[1] == other.P[1] &&
26             this->P[2] == other.P[2]);
27 }
28 
operator <<(std::ostream & out,const bn128_ate_G1_precomp & prec_P)29 std::ostream& operator<<(std::ostream &out, const bn128_ate_G1_precomp &prec_P)
30 {
31     for (size_t i = 0; i < 3; ++i)
32     {
33 #ifndef BINARY_OUTPUT
34         out << prec_P.P[i] << "\n";
35 #else
36         out.write((char*) &prec_P.P[i], sizeof(prec_P.P[i]));
37 #endif
38     }
39     return out;
40 }
41 
operator >>(std::istream & in,bn128_ate_G1_precomp & prec_P)42 std::istream& operator>>(std::istream &in, bn128_ate_G1_precomp &prec_P)
43 {
44     for (size_t i = 0; i < 3; ++i)
45     {
46 #ifndef BINARY_OUTPUT
47         in >> prec_P.P[i];
48         consume_newline(in);
49 #else
50         in.read((char*) &prec_P.P[i], sizeof(prec_P.P[i]));
51 #endif
52     }
53     return in;
54 }
55 
operator ==(const bn128_ate_G2_precomp & other) const56 bool bn128_ate_G2_precomp::operator==(const bn128_ate_G2_precomp &other) const
57 {
58     if (!(this->Q[0] == other.Q[0] &&
59           this->Q[1] == other.Q[1] &&
60           this->Q[2] == other.Q[2] &&
61           this->coeffs.size() == other.coeffs.size()))
62     {
63         return false;
64     }
65 
66     /* work around for upstream serialization bug */
67     for (size_t i = 0; i < this->coeffs.size(); ++i)
68     {
69         std::stringstream this_ss, other_ss;
70         this_ss << this->coeffs[i];
71         other_ss << other.coeffs[i];
72         if (this_ss.str() != other_ss.str())
73         {
74             return false;
75         }
76     }
77 
78     return true;
79 }
80 
operator <<(std::ostream & out,const bn128_ate_G2_precomp & prec_Q)81 std::ostream& operator<<(std::ostream &out, const bn128_ate_G2_precomp &prec_Q)
82 {
83     for (size_t i = 0; i < 3; ++i)
84     {
85 #ifndef BINARY_OUTPUT
86         out << prec_Q.Q[i].a_ << "\n";
87         out << prec_Q.Q[i].b_ << "\n";
88 #else
89         out.write((char*) &prec_Q.Q[i].a_, sizeof(prec_Q.Q[i].a_));
90         out.write((char*) &prec_Q.Q[i].b_, sizeof(prec_Q.Q[i].b_));
91 #endif
92     }
93 
94     out << prec_Q.coeffs.size() << "\n";
95 
96     for (size_t i = 0; i < prec_Q.coeffs.size(); ++i)
97     {
98 #ifndef BINARY_OUTPUT
99         out << prec_Q.coeffs[i].a_.a_ << "\n";
100         out << prec_Q.coeffs[i].a_.b_ << "\n";
101         out << prec_Q.coeffs[i].b_.a_ << "\n";
102         out << prec_Q.coeffs[i].b_.b_ << "\n";
103         out << prec_Q.coeffs[i].c_.a_ << "\n";
104         out << prec_Q.coeffs[i].c_.b_ << "\n";
105 #else
106         out.write((char*) &prec_Q.coeffs[i].a_.a_, sizeof(prec_Q.coeffs[i].a_.a_));
107         out.write((char*) &prec_Q.coeffs[i].a_.b_, sizeof(prec_Q.coeffs[i].a_.b_));
108         out.write((char*) &prec_Q.coeffs[i].b_.a_, sizeof(prec_Q.coeffs[i].b_.a_));
109         out.write((char*) &prec_Q.coeffs[i].b_.b_, sizeof(prec_Q.coeffs[i].b_.b_));
110         out.write((char*) &prec_Q.coeffs[i].c_.a_, sizeof(prec_Q.coeffs[i].c_.a_));
111         out.write((char*) &prec_Q.coeffs[i].c_.b_, sizeof(prec_Q.coeffs[i].c_.b_));
112 #endif
113     }
114 
115     return out;
116 }
117 
operator >>(std::istream & in,bn128_ate_G2_precomp & prec_Q)118 std::istream& operator>>(std::istream &in, bn128_ate_G2_precomp &prec_Q)
119 {
120     for (size_t i = 0; i < 3; ++i)
121     {
122 #ifndef BINARY_OUTPUT
123         in >> prec_Q.Q[i].a_;
124         consume_newline(in);
125         in >> prec_Q.Q[i].b_;
126         consume_newline(in);
127 #else
128         in.read((char*) &prec_Q.Q[i].a_, sizeof(prec_Q.Q[i].a_));
129         in.read((char*) &prec_Q.Q[i].b_, sizeof(prec_Q.Q[i].b_));
130 #endif
131     }
132 
133     size_t count;
134     in >> count;
135     consume_newline(in);
136     prec_Q.coeffs.resize(count);
137     for (size_t i = 0; i < count; ++i)
138     {
139 #ifndef BINARY_OUTPUT
140         in >> prec_Q.coeffs[i].a_.a_;
141         consume_newline(in);
142         in >> prec_Q.coeffs[i].a_.b_;
143         consume_newline(in);
144         in >> prec_Q.coeffs[i].b_.a_;
145         consume_newline(in);
146         in >> prec_Q.coeffs[i].b_.b_;
147         consume_newline(in);
148         in >> prec_Q.coeffs[i].c_.a_;
149         consume_newline(in);
150         in >> prec_Q.coeffs[i].c_.b_;
151         consume_newline(in);
152 #else
153         in.read((char*) &prec_Q.coeffs[i].a_.a_, sizeof(prec_Q.coeffs[i].a_.a_));
154         in.read((char*) &prec_Q.coeffs[i].a_.b_, sizeof(prec_Q.coeffs[i].a_.b_));
155         in.read((char*) &prec_Q.coeffs[i].b_.a_, sizeof(prec_Q.coeffs[i].b_.a_));
156         in.read((char*) &prec_Q.coeffs[i].b_.b_, sizeof(prec_Q.coeffs[i].b_.b_));
157         in.read((char*) &prec_Q.coeffs[i].c_.a_, sizeof(prec_Q.coeffs[i].c_.a_));
158         in.read((char*) &prec_Q.coeffs[i].c_.b_, sizeof(prec_Q.coeffs[i].c_.b_));
159 #endif
160     }
161     return in;
162 }
163 
bn128_ate_precompute_G1(const bn128_G1 & P)164 bn128_ate_G1_precomp bn128_ate_precompute_G1(const bn128_G1& P)
165 {
166     enter_block("Call to bn128_ate_precompute_G1");
167 
168     bn128_ate_G1_precomp result;
169     bn::ecop::NormalizeJac(result.P, P.coord);
170 
171     leave_block("Call to bn128_ate_precompute_G1");
172     return result;
173 }
174 
bn128_ate_precompute_G2(const bn128_G2 & Q)175 bn128_ate_G2_precomp bn128_ate_precompute_G2(const bn128_G2& Q)
176 {
177     enter_block("Call to bn128_ate_precompute_G2");
178 
179     bn128_ate_G2_precomp result;
180     bn::components::precomputeG2(result.coeffs, result.Q, Q.coord);
181 
182     leave_block("Call to bn128_ate_precompute_G2");
183     return result;
184 }
185 
bn128_ate_miller_loop(const bn128_ate_G1_precomp & prec_P,const bn128_ate_G2_precomp & prec_Q)186 bn128_Fq12 bn128_ate_miller_loop(const bn128_ate_G1_precomp &prec_P,
187                                  const bn128_ate_G2_precomp &prec_Q)
188 {
189     bn128_Fq12 f;
190     bn::components::millerLoop(f.elem, prec_Q.coeffs, prec_P.P);
191     return f;
192 }
193 
bn128_double_ate_miller_loop(const bn128_ate_G1_precomp & prec_P1,const bn128_ate_G2_precomp & prec_Q1,const bn128_ate_G1_precomp & prec_P2,const bn128_ate_G2_precomp & prec_Q2)194 bn128_Fq12 bn128_double_ate_miller_loop(const bn128_ate_G1_precomp &prec_P1,
195                                         const bn128_ate_G2_precomp &prec_Q1,
196                                         const bn128_ate_G1_precomp &prec_P2,
197                                         const bn128_ate_G2_precomp &prec_Q2)
198 {
199     bn128_Fq12 f;
200     bn::components::millerLoop2(f.elem, prec_Q1.coeffs, prec_P1.P, prec_Q2.coeffs, prec_P2.P);
201     return f;
202 }
203 
bn128_final_exponentiation(const bn128_Fq12 & elt)204 bn128_GT bn128_final_exponentiation(const bn128_Fq12 &elt)
205 {
206     enter_block("Call to bn128_final_exponentiation");
207     bn128_GT eltcopy = elt;
208     eltcopy.elem.final_exp();
209     leave_block("Call to bn128_final_exponentiation");
210     return eltcopy;
211 }
212 } // libff
213