in src/compression/pairing.c [156:287]
void Tate2_pairings(const point_t P, const point_t Q, point_full_proj_t *Qj, f2elm_t* f)
{
felm_t *x, *y, *x_, *y_, *l1;
f2elm_t finv[2*t_points], one = {0};
f2elm_t *x_first, *y_first, l1_first, t0, t1, g, h;
fpcopy((digit_t*)&Montgomery_one, one[0]);
for (int j = 0; j < t_points; j++) {
fp2copy(one, f[j]);
fp2copy(one, f[j+t_points]);
}
// Pairings with P
x_first = (f2elm_t*)P->x;
y_first = (f2elm_t*)P->y;
x_ = (felm_t*)T_tate2_firststep_P + 0;
y_ = (felm_t*)T_tate2_firststep_P + 1;
fpcopy((digit_t*)T_tate2_firststep_P + 2*NWORDS_FIELD, l1_first[0]);
fpcopy((digit_t*)T_tate2_firststep_P + 3*NWORDS_FIELD, l1_first[1]);
for (int j = 0; j < t_points; j++) {
fp2sub(Qj[j]->X, *x_first, t0);
fp2sub(Qj[j]->Y, *y_first, t1);
fp2mul_mont(l1_first, t0, t0);
fp2sub(t0, t1, g);
fpsub(Qj[j]->X[0], *x_, h[0]);
fpcopy(Qj[j]->X[1], h[1]);
fpneg(h[1]);
fp2mul_mont(g, h, g);
fp2sqr_mont(f[j], f[j]);
fp2mul_mont(f[j], g, f[j]);
}
x = x_;
y = y_;
for (int k = 0; k < OALICE_BITS - 2; k++) {
x_ = (felm_t*)T_tate2_P + 3 * k + 0;
y_ = (felm_t*)T_tate2_P + 3 * k + 1;
l1 = (felm_t*)T_tate2_P + 3 * k + 2;
for (int j = 0; j < t_points; j++) {
fpsub(*x, Qj[j]->X[0], t0[1]);
fpmul_mont(*l1, t0[1], t0[1]);
fpmul_mont(*l1, Qj[j]->X[1], t0[0]);
fpsub(Qj[j]->Y[1], *y, t1[1]);
fpsub(t0[1], t1[1], g[1]);
fpsub(t0[0], Qj[j]->Y[0], g[0]);
fpsub(Qj[j]->X[0], *x_, h[0]);
fpcopy(Qj[j]->X[1], h[1]);
fpneg(h[1]);
fp2mul_mont(g, h, g);
fp2sqr_mont(f[j], f[j]);
fp2mul_mont(f[j], g, f[j]);
}
x = x_;
y = y_;
}
for (int j = 0; j < t_points; j++) {
fpsub(Qj[j]->X[0], *x, g[0]);
fpcopy(Qj[j]->X[1], g[1]);
fp2sqr_mont(f[j], f[j]);
fp2mul_mont(f[j], g, f[j]);
}
// Pairings with Q
x_first = (f2elm_t*)Q->x;
y_first = (f2elm_t*)Q->y;
x_ = (felm_t*)T_tate2_firststep_Q + 0;
y_ = (felm_t*)T_tate2_firststep_Q + 1;
fpcopy(((felm_t*)T_tate2_firststep_Q)[2], l1_first[0]);
fpcopy(((felm_t*)T_tate2_firststep_Q)[3], l1_first[1]);
for (int j = 0; j < t_points; j++) {
fp2sub(Qj[j]->X, *x_first, t0);
fp2sub(Qj[j]->Y, *y_first, t1);
fp2mul_mont(l1_first, t0, t0);
fp2sub(t0, t1, g);
fpsub(Qj[j]->X[0], *x_, h[0]);
fpcopy(Qj[j]->X[1], h[1]);
fpneg(h[1]);
fp2mul_mont(g, h, g);
fp2sqr_mont(f[j+t_points], f[j+t_points]);
fp2mul_mont(f[j+t_points], g, f[j+t_points]);
}
x = x_;
y = y_;
for (int k = 0; k < OALICE_BITS - 2; k++) {
x_ = (felm_t*)T_tate2_Q + 3*k + 0;
y_ = (felm_t*)T_tate2_Q + 3*k + 1;
l1 = (felm_t*)T_tate2_Q + 3*k + 2;
for (int j = 0; j < t_points; j++) {
fpsub(Qj[j]->X[0], *x, t0[0]);
fpmul_mont(*l1, t0[0], t0[0]);
fpmul_mont(*l1, Qj[j]->X[1], t0[1]);
fpsub(Qj[j]->Y[0], *y, t1[0]);
fpsub(t0[0], t1[0], g[0]);
fpsub(t0[1], Qj[j]->Y[1], g[1]);
fpsub(Qj[j]->X[0], *x_, h[0]);
fpcopy(Qj[j]->X[1], h[1]);
fpneg(h[1]);
fp2mul_mont(g, h, g);
fp2sqr_mont(f[j+t_points], f[j+t_points]);
fp2mul_mont(f[j+t_points], g, f[j+t_points]);
}
x = x_;
y = y_;
}
// Last iteration
for (int j = 0; j < t_points; j++) {
fpsub(Qj[j]->X[0], *x, g[0]);
fpcopy(Qj[j]->X[1], g[1]);
fp2sqr_mont(f[j+t_points], f[j+t_points]);
fp2mul_mont(f[j+t_points], g, f[j+t_points]);
}
// Final exponentiation:
mont_n_way_inv(f, 2*t_points, finv);
for (int j = 0; j < 2*t_points; j++) {
final_exponentiation_2_torsion(f[j], finv[j], f[j]);
}
}