/*############################################################################
# Copyright 2017 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
############################################################################*/
/// Implementation of Tate pairing
/*! \file */
#include "epid/member/tiny/math/pairing.h"
#include "epid/member/tiny/math/efq2.h"
#include "epid/member/tiny/math/fq.h"
#include "epid/member/tiny/math/fq12.h"
#include "epid/member/tiny/math/fq2.h"
#include "epid/member/tiny/math/mathtypes.h"
#include "epid/member/tiny/math/vli.h"
static const VeryLargeInt epid_e = {{0xf2788803, 0x7886dcf9, 0x2dc401c0,
0xd77a10ff, 0x27bd9b6f, 0x367ba865,
0xaaaa2822, 0x2aaaaaaa}};
static const VeryLargeInt epid_t = {{0x30B0A801, 0x6882F5C0, 0, 0, 0, 0, 0, 0}};
static const Fq2Elem epid_xi = {
{{{0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000}}},
{{{0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000}}}};
static const int neg = 1;
void PairingInit(PairingState* state) {
int i;
Fq2Exp(&state->g[0][0], &epid_xi, &epid_e);
for (i = 1; i < 5; i++) {
Fq2Mul(&state->g[0][i], &state->g[0][i - 1], &state->g[0][0]);
}
for (i = 0; i < 5; i++) {
FqSquare(&state->g[1][i].x0, &state->g[0][i].x0);
FqSquare(&state->g[1][i].x1, &state->g[0][i].x1);
FqAdd(&state->g[1][i].x0, &state->g[1][i].x0, &state->g[1][i].x1);
FqClear(&state->g[1][i].x1);
Fq2Mul(&state->g[2][i], &state->g[0][i], &state->g[1][i]);
}
}
static void piOp(EccPointFq2* Qout, EccPointFq2 const* Qin, int e,
PairingState const* scratch) {
if (e == 1) {
Fq2Conj(&Qout->x, &Qin->x);
Fq2Conj(&Qout->y, &Qin->y);
} else {
Fq2Cp(&Qout->x, &Qin->x);
Fq2Cp(&Qout->y, &Qin->y);
}
Fq2Mul(&Qout->x, &Qout->x, &scratch->g[e - 1][1]);
Fq2Mul(&Qout->y, &Qout->y, &scratch->g[e - 1][2]);
}
/*
* Computes the Frobenius endomorphism Pout = Pin^(p^e)
*/
static void frob_op(Fq12Elem* Pout, Fq12Elem const* Pin, int e,
PairingState const* state) {
if (e == 1 || e == 3) {
Fq2Conj(&Pout->z0.y0, &Pin->z0.y0);
Fq2Conj(&Pout->z1.y0, &Pin->z1.y0);
Fq2Conj(&Pout->z0.y1, &Pin->z0.y1);
Fq2Conj(&Pout->z1.y1, &Pin->z1.y1);
Fq2Conj(&Pout->z0.y2, &Pin->z0.y2);
Fq2Conj(&Pout->z1.y2, &Pin->z1.y2);
} else {
Fq2Cp(&Pout->z0.y0, &Pin->z0.y0);
Fq2Cp(&Pout->z1.y0, &Pin->z1.y0);
Fq2Cp(&Pout->z0.y1, &Pin->z0.y1);
Fq2Cp(&Pout->z1.y1, &Pin->z1.y1);
Fq2Cp(&Pout->z0.y2, &Pin->z0.y2);
Fq2Cp(&Pout->z1.y2, &Pin->z1.y2);
}
Fq2Mul(&Pout->z1.y0, &Pout->z1.y0, &state->g[e - 1][0]);
Fq2Mul(&Pout->z0.y1, &Pout->z0.y1, &state->g[e - 1][1]);
Fq2Mul(&Pout->z1.y1, &Pout->z1.y1, &state->g[e - 1][2]);
Fq2Mul(&Pout->z0.y2, &Pout->z0.y2, &state->g[e - 1][3]);
Fq2Mul(&Pout->z1.y2, &Pout->z1.y2, &state->g[e - 1][4]);
}
static void finalExp(Fq12Elem* f, PairingState const* state) {
Fq12Elem t3;
Fq12Elem t2;
Fq12Elem t1;
Fq12Elem t0;
Fq12Conj(&t1, f);
Fq12Inv(&t2, f);
Fq12Mul(f, &t1, &t2);
frob_op(&t2, f, 2, state);
Fq12Mul(f, f, &t2);
Fq12ExpCyc(&t1, f, &epid_t);
if (neg) {
Fq12Conj(&t1, &t1);
}
Fq12ExpCyc(&t3, &t1, &epid_t);
if (neg) {
Fq12Conj(&t3, &t3);
}
Fq12ExpCyc(&t0, &t3, &epid_t);
if (neg) {
Fq12Conj(&t0, &t0);
}
frob_op(&t2, &t0, 1, state);
Fq12Mul(&t2, &t2, &t0);
Fq12Conj(&t2, &t2);
Fq12SqCyc(&t0, &t2);
frob_op(&t2, &t3, 1, state);
Fq12Mul(&t2, &t2, &t1);
Fq12Conj(&t2, &t2);
Fq12Mul(&t0, &t0, &t2);
Fq12Conj(&t2, &t3);
Fq12Mul(&t0, &t0, &t2);
frob_op(&t1, &t1, 1, state);
Fq12Conj(&t1, &t1);
Fq12Mul(&t1, &t1, &t2);
Fq12Mul(&t1, &t1, &t0);
frob_op(&t2, &t3, 2, state);
Fq12Mul(&t0, &t0, &t2);
Fq12SqCyc(&t1, &t1);
Fq12Mul(&t1, &t1, &t0);
Fq12SqCyc(&t1, &t1);
Fq12Conj(&t2, f);
Fq12Mul(&t0, &t1, &t2);
frob_op(&t2, f, 1, state);
Fq12Mul(&t1, &t1, &t2);
frob_op(&t2, f, 2, state);
Fq12Mul(&t1, &t1, &t2);
frob_op(&t2, f, 3, state);
Fq12Mul(&t1, &t1, &t2);
Fq12SqCyc(&t0, &t0);
Fq12Mul(f, &t1, &t0);
}
static void pair_tangent(Fq12Elem* f, Fq2Elem* X, Fq2Elem* Y, Fq2Elem* Z,
Fq2Elem* Z2, EccPointFq const* P) {
Fq2Mul(&f->z0.y0, X, X);
Fq2Add(&f->z0.y2, &f->z0.y0, &f->z0.y0);
Fq2Add(&f->z0.y2, &f->z0.y2, &f->z0.y0);
Fq2Add(&f->z1.y1, X, &f->z0.y2);
Fq2Mul(&f->z1.y1, &f->z1.y1, &f->z1.y1);
Fq2Sub(&f->z1.y1, &f->z1.y1, &f->z0.y0);
Fq2Mul(&f->z0.y1, Y, Y);
Fq2Add(&f->z1.y0, &f->z0.y1, X);
Fq2Mul(&f->z1.y0, &f->z1.y0, &f->z1.y0);
Fq2Sub(&f->z1.y0, &f->z1.y0, &f->z0.y0);
Fq2Mul(&f->z0.y0, &f->z0.y1, &f->z0.y1);
Fq2Sub(&f->z1.y0, &f->z1.y0, &f->z0.y0);
Fq2Add(&f->z1.y0, &f->z1.y0, &f->z1.y0);
Fq2Mul(&f->z1.y2, &f->z0.y2, &f->z0.y2);
Fq2Add(Z, Y, Z);
Fq2Mul(Z, Z, Z);
Fq2Sub(Z, Z, &f->z0.y1);
Fq2Sub(Z, Z, Z2);
Fq2Add(&f->z0.y1, &f->z0.y1, &f->z0.y1);
Fq2Add(&f->z0.y1, &f->z0.y1, &f->z0.y1);
Fq2Sub(&f->z1.y1, &f->z1.y1, &f->z1.y2);
Fq2Sub(&f->z1.y1, &f->z1.y1, &f->z0.y1);
Fq2Sub(X, &f->z1.y2, &f->z1.y0);
Fq2Sub(X, X, &f->z1.y0);
Fq2Add(&f->z0.y0, &f->z0.y0, &f->z0.y0);
Fq2Add(&f->z0.y0, &f->z0.y0, &f->z0.y0);
Fq2Add(&f->z0.y0, &f->z0.y0, &f->z0.y0);
Fq2Sub(Y, &f->z1.y0, X);
Fq2Mul(Y, Y, &f->z0.y2);
Fq2Sub(Y, Y, &f->z0.y0);
Fq2Mul(&f->z1.y0, &f->z0.y2, Z2);
Fq2Neg(&f->z1.y0, &f->z1.y0);
Fq2Add(&f->z1.y0, &f->z1.y0, &f->z1.y0);
Fq2MulScalar(&f->z1.y0, &f->z1.y0, &P->x);
Fq2Mul(&f->z0.y0, Z, Z2);
Fq2Add(&f->z0.y0, &f->z0.y0, &f->z0.y0);
Fq2MulScalar(&f->z0.y0, &f->z0.y0, &P->y);
Fq2Mul(Z2, Z, Z);
Fq2Clear(&f->z0.y1);
Fq2Clear(&f->z0.y2);
Fq2Clear(&f->z1.y2);
Fq2Square(Z2, Z);
}
static void pair_line(Fq12Elem* f, Fq2Elem* X, Fq2Elem* Y, Fq2Elem* Z,
Fq2Elem* Z2, EccPointFq const* P, EccPointFq2 const* Q) {
Fq2Mul(&f->z0.y1, &Q->x, Z2);
Fq2Add(&f->z1.y0, &Q->y, Z);
Fq2Mul(&f->z1.y0, &f->z1.y0, &f->z1.y0);
Fq2Square(&f->z0.y0, &Q->y);
Fq2Sub(&f->z1.y0, &f->z1.y0, &f->z0.y0);
Fq2Sub(&f->z1.y0, &f->z1.y0, Z2);
Fq2Mul(&f->z1.y0, &f->z1.y0, Z2);
Fq2Sub(&f->z0.y1, &f->z0.y1, X);
Fq2Mul(&f->z0.y2, &f->z0.y1, &f->z0.y1);
Fq2Add(Z, Z, &f->z0.y1);
Fq2Square(Z, Z);
Fq2Sub(Z, Z, Z2);
Fq2Sub(Z, Z, &f->z0.y2);
Fq2Mul(Z2, Z, Z);
Fq2Add(&f->z1.y2, &Q->y, Z);
Fq2Mul(&f->z1.y2, &f->z1.y2, &f->z1.y2);
Fq2Sub(&f->z1.y2, &f->z1.y2, &f->z0.y0);
Fq2Sub(&f->z1.y2, &f->z1.y2, Z2);
Fq2Sub(&f->z1.y0, &f->z1.y0, Y);
Fq2Sub(&f->z1.y0, &f->z1.y0, Y);
Fq2Mul(&f->z1.y1, &f->z1.y0, &Q->x);
Fq2Add(&f->z1.y1, &f->z1.y1, &f->z1.y1);
Fq2Sub(&f->z1.y1, &f->z1.y1, &f->z1.y2);
Fq2Add(&f->z0.y2, &f->z0.y2, &f->z0.y2);
Fq2Add(&f->z0.y2, &f->z0.y2, &f->z0.y2);
Fq2Mul(&f->z0.y1, &f->z0.y2, &f->z0.y1);
Fq2Mul(&f->z0.y2, X, &f->z0.y2);
Fq2Mul(X, &f->z1.y0, &f->z1.y0);
Fq2Sub(X, X, &f->z0.y1);
Fq2Sub(X, X, &f->z0.y2);
Fq2Sub(X, X, &f->z0.y2);
Fq2Sub(&f->z0.y2, &f->z0.y2, X);
Fq2Mul(&f->z0.y2, &f->z0.y2, &f->z1.y0);
Fq2Mul(&f->z0.y1, Y, &f->z0.y1);
Fq2Add(&f->z0.y1, &f->z0.y1, &f->z0.y1);
Fq2Sub(Y, &f->z0.y2, &f->z0.y1);
Fq2MulScalar(&f->z0.y0, Z, &P->y);
Fq2Add(&f->z0.y0, &f->z0.y0, &f->z0.y0);
Fq2Neg(&f->z1.y0, &f->z1.y0);
Fq2MulScalar(&f->z1.y0, &f->z1.y0, &P->x);
Fq2Add(&f->z1.y0, &f->z1.y0, &f->z1.y0);
Fq2Clear(&f->z0.y1);
Fq2Clear(&f->z0.y2);
Fq2Clear(&f->z1.y2);
}
void PairingCompute(Fq12Elem* d, EccPointFq const* P, EccPointFq2 const* Q,
PairingState const* state) {
Fq2Elem X;
Fq2Elem Y;
Fq2Elem Z;
Fq2Elem Z2;
EccPointFq2 Qp;
Fq12Elem f;
VeryLargeInt s;
const VeryLargeInt two = {{2}};
uint32_t i;
VliAdd(&s, &epid_t, &epid_t); // s = 2*t
VliAdd(&s, &s, &epid_t); // s = 3*t
VliAdd(&s, &s, &s); // s = 6*t
if (neg) {
VliSub(&s, &s, &two);
} else {
VliAdd(&s, &s, &two);
}
Fq2Cp(&X, &Q->x);
Fq2Cp(&Y, &Q->y);
Fq2Set(&Z, 1);
Fq2Set(&Z2, 1);
Fq12Set(d, 1);
Fq12Clear(&f);
// s has 66 bits, 0 through 65, so starting point is bit 64
i = 65;
while (i > 0) {
i -= 1;
pair_tangent(&f, &X, &Y, &Z, &Z2, P);
Fq12Square(d, d);
Fq12MulSpecial(d, d, &f);
if (VliTestBit(&s, i)) {
pair_line(&f, &X, &Y, &Z, &Z2, P, Q);
Fq12MulSpecial(d, d, &f);
}
}
if (neg) {
Fq2Neg(&Y, &Y);
Fq12Conj(d, d);
}
piOp(&Qp, Q, 1, state);
pair_line(&f, &X, &Y, &Z, &Z2, P, &Qp);
Fq12MulSpecial(d, d, &f);
piOp(&Qp, Q, 2, state);
Fq2Neg(&Qp.y, &Qp.y);
pair_line(&f, &X, &Y, &Z, &Z2, P, &Qp);
Fq12MulSpecial(d, d, &f);
finalExp(d, state);
// s doesn't have secret information; no need to clear it.
Fq12Clear(&f);
Fq2Clear(&X);
Fq2Clear(&Y);
Fq2Clear(&Z);
Fq2Clear(&Z2);
Fq2Clear(&Qp.x);
Fq2Clear(&Qp.y);
}