Home | History | Annotate | Download | only in src
      1 /*############################################################################
      2   # Copyright 2016-2017 Intel Corporation
      3   #
      4   # Licensed under the Apache License, Version 2.0 (the "License");
      5   # you may not use this file except in compliance with the License.
      6   # You may obtain a copy of the License at
      7   #
      8   #     http://www.apache.org/licenses/LICENSE-2.0
      9   #
     10   # Unless required by applicable law or agreed to in writing, software
     11   # distributed under the License is distributed on an "AS IS" BASIS,
     12   # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13   # See the License for the specific language governing permissions and
     14   # limitations under the License.
     15   ############################################################################*/
     16 
     17 /*!
     18  * \file
     19  * \brief Pairing implementation.
     20  */
     21 
     22 #include "epid/common/math/pairing.h"
     23 #include <limits.h>
     24 #include "epid/common/math/src/bignum-internal.h"
     25 #include "epid/common/math/src/ecgroup-internal.h"
     26 #include "epid/common/math/src/finitefield-internal.h"
     27 #include "epid/common/math/src/pairing-internal.h"
     28 #include "epid/common/src/memory.h"
     29 #include "ext/ipp/include/ippcp.h"
     30 
     31 /// Handle Ipp Errors with Break
     32 #define BREAK_ON_IPP_ERROR(sts, ret)           \
     33   {                                            \
     34     IppStatus temp_sts = (sts);                \
     35     if (ippStsNoErr != temp_sts) {             \
     36       if (ippStsContextMatchErr == temp_sts) { \
     37         (ret) = kEpidMathErr;                  \
     38       } else {                                 \
     39         (ret) = kEpidBadArgErr;                \
     40       }                                        \
     41       break;                                   \
     42     }                                          \
     43   }
     44 /// Handle Ipp Errors with Return
     45 #define RETURN_ON_IPP_ERROR(sts)               \
     46   {                                            \
     47     IppStatus temp_sts = (sts);                \
     48     if (ippStsNoErr != temp_sts) {             \
     49       if (ippStsContextMatchErr == temp_sts) { \
     50         return kEpidMathErr;                   \
     51       } else {                                 \
     52         return kEpidBadArgErr;                 \
     53       }                                        \
     54     }                                          \
     55   }
     56 /// Handle SDK Error with Break
     57 #define BREAK_ON_EPID_ERROR(ret) \
     58   if (kEpidNoErr != (ret)) {     \
     59     break;                       \
     60   }
     61 
     62 #pragma pack(1)
     63 /// Data for element in Fq
     64 typedef struct FqElemDat {
     65   Ipp32u x[sizeof(FqElemStr) / sizeof(Ipp32u)];  ///< element in Fq
     66 } FqElemDat;
     67 /// Data for element in  Fq2
     68 typedef struct Fq2ElemDat {
     69   FqElemDat x[2];  ///< element in Fq2
     70 } Fq2ElemDat;
     71 /// Data for element in  Fq2^3
     72 typedef struct Fq6ElemDat {
     73   Fq2ElemDat x[3];  ///< element in Fq6
     74 } Fq6ElemDat;
     75 /// Data for element in  Fq2^3^2
     76 typedef struct Fq12ElemDat {
     77   Fq6ElemDat x[2];  ///< element in Fq12
     78 } Fq12ElemDat;
     79 #pragma pack()
     80 
     81 // Forward Declarations
     82 static EpidStatus FinalExp(PairingState* ps, FfElement* d, FfElement const* h);
     83 
     84 static EpidStatus PiOp(PairingState* ps, FfElement* x_out, FfElement* y_out,
     85                        FfElement const* x, FfElement const* y, const int e);
     86 
     87 static EpidStatus FrobeniusOp(PairingState* ps, FfElement* d_out,
     88                               FfElement const* a, const int e);
     89 
     90 static EpidStatus Line(FiniteField* gt, FfElement* f, FfElement* x_out,
     91                        FfElement* y_out, FfElement* z_out, FfElement* z2_out,
     92                        FfElement const* px, FfElement const* py,
     93                        FfElement const* x, FfElement const* y,
     94                        FfElement const* z, FfElement const* z2,
     95                        FfElement const* qx, FfElement const* qy);
     96 
     97 static EpidStatus Tangent(FiniteField* gt, FfElement* f, FfElement* x_out,
     98                           FfElement* y_out, FfElement* z_out, FfElement* z2_out,
     99                           FfElement const* px, FfElement const* py,
    100                           FfElement const* x, FfElement const* y,
    101                           FfElement const* z, FfElement const* z2);
    102 
    103 static EpidStatus Ternary(int* s, int* n, int max_elements, BigNum const* x);
    104 
    105 static int Bit(Ipp32u const* num, Ipp32u bit_index);
    106 
    107 static EpidStatus MulXiFast(FfElement* e, FfElement const* a, PairingState* ps);
    108 
    109 static EpidStatus MulV(FfElement* e, FfElement* a, PairingState* ps);
    110 
    111 static EpidStatus Fq6MulGFpE2(FfElement* e, FfElement* a, FfElement* b0,
    112                               FfElement* b1, PairingState* ps);
    113 
    114 static EpidStatus MulSpecial(FfElement* e, FfElement const* a,
    115                              FfElement const* b, PairingState* ps);
    116 
    117 static EpidStatus SquareCyclotomic(PairingState* ps, FfElement* e_out,
    118                                    FfElement const* a_in);
    119 
    120 static EpidStatus ExpCyclotomic(PairingState* ps, FfElement* e,
    121                                 FfElement const* a, BigNum const* b);
    122 
    123 // Implementation
    124 
    125 EpidStatus NewPairingState(EcGroup const* ga, EcGroup const* gb,
    126                            FiniteField* ff, BigNumStr const* t, bool neg,
    127                            PairingState** ps) {
    128   EpidStatus result = kEpidErr;
    129   FfElement* xi = NULL;
    130   PairingState* pairing_state_ctx = NULL;
    131   BigNum* e = NULL;
    132   BigNum* one = NULL;
    133   BigNum* six = NULL;
    134   OctStr scratch_buffer = NULL;
    135   do {
    136     IppStatus sts = ippStsNoErr;
    137     IppsGFpState* Fq6 = NULL;
    138     IppsGFpState* Fq2 = NULL;
    139     IppsGFpState* Fq = NULL;
    140     FiniteField* Ffq6 = NULL;
    141     FiniteField* Ffq2 = NULL;
    142     FiniteField* Ffq = NULL;
    143     Fq2ElemDat Fq6IrrPolynomial = {0};
    144     uint8_t one_str[] = {1};
    145     uint8_t six_str[] = {6};
    146     int i = 0;
    147     int j = 0;
    148     int bufferSize = 0;
    149     int bitSize = 0;
    150     // validate inputs
    151     if (!ga || !gb || !ff || !t || !ps) {
    152       result = kEpidBadArgErr;
    153       break;
    154     }
    155     if (!ga->ipp_ec || !gb->ipp_ec || !ff->ipp_ff) {
    156       result = kEpidBadArgErr;
    157       break;
    158     }
    159     // get Fq6, Fq2, Fq
    160     Ffq6 = ff->ground_ff;
    161     if (!Ffq6) {
    162       result = kEpidBadArgErr;
    163       break;
    164     }
    165     Fq6 = Ffq6->ipp_ff;
    166     Ffq2 = Ffq6->ground_ff;
    167     if (!Ffq2) {
    168       result = kEpidBadArgErr;
    169       break;
    170     }
    171     Fq2 = Ffq2->ipp_ff;
    172     Ffq = Ffq2->ground_ff;
    173     if (!Ffq) {
    174       result = kEpidBadArgErr;
    175       break;
    176     }
    177     Fq = Ffq->ipp_ff;
    178     // extract xi from Fq6 irr poly
    179     result = NewFfElement(Ffq2, &xi);
    180     BREAK_ON_EPID_ERROR(result);
    181     result = WriteBigNum(Ffq6->modulus_0, sizeof(Fq6IrrPolynomial),
    182                          &Fq6IrrPolynomial);
    183     BREAK_ON_EPID_ERROR(result);
    184     result = SetFfElementOctString(&Fq6IrrPolynomial, sizeof(Fq6IrrPolynomial),
    185                                    xi, Ffq2);
    186     BREAK_ON_EPID_ERROR(result);
    187     // first coefficent is -xi
    188     sts = ippsGFpNeg(xi->ipp_ff_elem, xi->ipp_ff_elem, Fq2);
    189     BREAK_ON_IPP_ERROR(sts, result);
    190 
    191     pairing_state_ctx = (PairingState*)SAFE_ALLOC(sizeof(PairingState));
    192     if (!pairing_state_ctx) {
    193       result = kEpidMemAllocErr;
    194       break;
    195     }
    196 
    197     // 1. Set param(pairing) = (param(G1), param(G2), param(GT), t, neg)
    198     pairing_state_ctx->ga = (EcGroup*)ga;
    199     pairing_state_ctx->gb = (EcGroup*)gb;
    200     pairing_state_ctx->ff = ff;
    201     result = NewBigNum(sizeof(BigNumStr), &pairing_state_ctx->t);
    202     BREAK_ON_EPID_ERROR(result);
    203     result = ReadBigNum(t, sizeof(BigNumStr), pairing_state_ctx->t);
    204     BREAK_ON_EPID_ERROR(result);
    205     pairing_state_ctx->neg = neg;
    206     pairing_state_ctx->Fq6 = Ffq6;
    207     pairing_state_ctx->Fq2 = Ffq2;
    208     pairing_state_ctx->Fq = Ffq;
    209     // 2. Let g[0][0], ..., g[0][4], g[1][0], ..., g[1][4], g[2][0], ...,
    210     // g[2][4] be 15 elements in Fq2.
    211     for (i = 0; i < 3; i++) {
    212       for (j = 0; j < 5; j++) {
    213         result = NewFfElement(Ffq2, &pairing_state_ctx->g[i][j]);
    214         BREAK_ON_EPID_ERROR(result);
    215       }
    216     }
    217     // 3. Compute a big integer e = (q - 1)/6.
    218     result = NewBigNum(sizeof(BigNumStr), &one);
    219     BREAK_ON_EPID_ERROR(result);
    220     result = ReadBigNum(one_str, sizeof(one_str), one);
    221     BREAK_ON_EPID_ERROR(result);
    222     result = NewBigNum(sizeof(BigNumStr), &e);
    223     BREAK_ON_EPID_ERROR(result);
    224     // q - 1
    225     sts = ippsSub_BN(Ffq->modulus_0->ipp_bn, one->ipp_bn, e->ipp_bn);
    226     BREAK_ON_IPP_ERROR(sts, result);
    227     result = NewBigNum(sizeof(BigNumStr), &six);
    228     BREAK_ON_EPID_ERROR(result);
    229     result = ReadBigNum(six_str, sizeof(six_str), six);
    230     BREAK_ON_EPID_ERROR(result);
    231     // e = (q - 1)/6
    232     // reusing one as remainder here
    233     sts = ippsDiv_BN(e->ipp_bn, six->ipp_bn, e->ipp_bn, one->ipp_bn);
    234     BREAK_ON_IPP_ERROR(sts, result);
    235     // 4. Compute g[0][0] = Fq2.exp(xi, e).
    236     sts = ippsRef_BN(0, &bitSize, 0, e->ipp_bn);
    237     BREAK_ON_IPP_ERROR(sts, result);
    238     sts = ippsGFpScratchBufferSize(1, bitSize, Fq2, &bufferSize);
    239     BREAK_ON_IPP_ERROR(sts, result);
    240     scratch_buffer = (OctStr)SAFE_ALLOC(bufferSize);
    241     if (!scratch_buffer) {
    242       result = kEpidMemAllocErr;
    243       break;
    244     }
    245     sts = ippsGFpExp(xi->ipp_ff_elem, e->ipp_bn,
    246                      pairing_state_ctx->g[0][0]->ipp_ff_elem, Fq2,
    247                      scratch_buffer);
    248     BREAK_ON_IPP_ERROR(sts, result);
    249     // 5. For i = 0, ..., 4, compute
    250     for (i = 0; i < 5; i++) {
    251       // a. If i > 0, compute g[0][i] = Fq2.mul(g[0][i-1], g[0][0]).
    252       if (i > 0) {
    253         sts = ippsGFpMul(pairing_state_ctx->g[0][i - 1]->ipp_ff_elem,
    254                          pairing_state_ctx->g[0][0]->ipp_ff_elem,
    255                          pairing_state_ctx->g[0][i]->ipp_ff_elem, Fq2);
    256       }
    257       // b. Compute g[1][i] = Fq2.conjugate(g[0][i]),
    258       sts = ippsGFpConj(pairing_state_ctx->g[0][i]->ipp_ff_elem,
    259                         pairing_state_ctx->g[1][i]->ipp_ff_elem, Fq2);
    260       // c. Compute g[1][i] = Fq2.mul(g[0][i], g[1][i]),
    261       sts = ippsGFpMul(pairing_state_ctx->g[0][i]->ipp_ff_elem,
    262                        pairing_state_ctx->g[1][i]->ipp_ff_elem,
    263                        pairing_state_ctx->g[1][i]->ipp_ff_elem, Fq2);
    264       // d. Compute g[2][i] = Fq2.mul(g[0][i], g[1][i]).
    265       sts = ippsGFpMul(pairing_state_ctx->g[0][i]->ipp_ff_elem,
    266                        pairing_state_ctx->g[1][i]->ipp_ff_elem,
    267                        pairing_state_ctx->g[2][i]->ipp_ff_elem, Fq2);
    268     }
    269     // 6. Save g[0][0], ..., g[0][4], g[1][0], ..., g[1][4], g[2][0], ...,
    270     // g[2][4]
    271     //    for the pairing operations.
    272     *ps = pairing_state_ctx;
    273     result = kEpidNoErr;
    274   } while (0);
    275   SAFE_FREE(scratch_buffer)
    276   DeleteBigNum(&six);
    277   DeleteBigNum(&e);
    278   DeleteBigNum(&one);
    279   DeleteFfElement(&xi);
    280   if (kEpidNoErr != result) {
    281     if (pairing_state_ctx) {
    282       int i = 0;
    283       int j = 0;
    284       for (i = 0; i < 3; i++) {
    285         for (j = 0; j < 5; j++) {
    286           DeleteFfElement(&pairing_state_ctx->g[i][j]);
    287         }
    288       }
    289       DeleteBigNum(&pairing_state_ctx->t);
    290       SAFE_FREE(pairing_state_ctx);
    291     }
    292   }
    293   return result;
    294 }
    295 
    296 void DeletePairingState(PairingState** ps) {
    297   if (!ps) {
    298     return;
    299   }
    300   if (!*ps) {
    301     return;
    302   }
    303   if (ps) {
    304     if (*ps) {
    305       int i = 0;
    306       int j = 0;
    307       for (i = 0; i < 3; i++) {
    308         for (j = 0; j < 5; j++) {
    309           DeleteFfElement(&(*ps)->g[i][j]);
    310         }
    311       }
    312       DeleteBigNum(&(*ps)->t);
    313       (*ps)->ga = NULL;
    314       (*ps)->gb = NULL;
    315       (*ps)->ff = NULL;
    316     }
    317     SAFE_FREE(*ps);
    318   }
    319 }
    320 
    321 EpidStatus Pairing(PairingState* ps, EcPoint const* a, EcPoint const* b,
    322                    FfElement* d) {
    323   EpidStatus result = kEpidErr;
    324   FfElement* ax = NULL;
    325   FfElement* ay = NULL;
    326   FfElement* bx = NULL;
    327   FfElement* by = NULL;
    328   FfElement* x = NULL;
    329   FfElement* y = NULL;
    330   FfElement* z = NULL;
    331   FfElement* z2 = NULL;
    332   FfElement* bx_ = NULL;
    333   FfElement* by_ = NULL;
    334   FfElement* f = NULL;
    335   BigNum* s = NULL;
    336   BigNum* two = NULL;
    337   BigNum* six = NULL;
    338   FfElement* neg_qy = NULL;
    339 
    340   do {
    341     IppStatus sts = ippStsNoErr;
    342     Ipp32u two_dat[] = {2};
    343     Ipp32u six_dat[] = {6};
    344     Ipp32u one_dat[] = {1};
    345     G1ElemStr first_val_str = {0};
    346     G2ElemStr second_val_str = {0};
    347     bool in_group = true;
    348     int s_ternary[sizeof(BigNumStr) * CHAR_BIT] = {0};
    349     int i = 0;
    350     int n = 0;
    351     // check parameters
    352     if (!ps || !d || !a || !b) {
    353       result = kEpidBadArgErr;
    354       break;
    355     }
    356     if (!ps->Fq || !ps->Fq2) {
    357       result = kEpidBadArgErr;
    358       break;
    359     }
    360     if (!d->ipp_ff_elem || !a->ipp_ec_pt || !b->ipp_ec_pt || !ps->ff ||
    361         !ps->ff->ipp_ff || !ps->Fq->ipp_ff || !ps->Fq2->ipp_ff || !ps->t ||
    362         !ps->t->ipp_bn || !ps->ga || !ps->ga->ipp_ec || !ps->gb ||
    363         !ps->gb->ipp_ec) {
    364       result = kEpidBadArgErr;
    365       break;
    366     }
    367     // Let ax, ay be elements in Fq. Let bx, by, x, y, z, z2, bx', by'
    368     // be elements in Fq2. Let f be a variable in GT.
    369     result = NewFfElement(ps->Fq, &ax);
    370     BREAK_ON_EPID_ERROR(result);
    371     result = NewFfElement(ps->Fq, &ay);
    372     BREAK_ON_EPID_ERROR(result);
    373     result = NewFfElement(ps->Fq2, &bx);
    374     BREAK_ON_EPID_ERROR(result);
    375     result = NewFfElement(ps->Fq2, &by);
    376     BREAK_ON_EPID_ERROR(result);
    377     result = NewFfElement(ps->Fq2, &x);
    378     BREAK_ON_EPID_ERROR(result);
    379     result = NewFfElement(ps->Fq2, &y);
    380     BREAK_ON_EPID_ERROR(result);
    381     result = NewFfElement(ps->Fq2, &z);
    382     BREAK_ON_EPID_ERROR(result);
    383     result = NewFfElement(ps->Fq2, &z2);
    384     BREAK_ON_EPID_ERROR(result);
    385     result = NewFfElement(ps->Fq2, &bx_);
    386     BREAK_ON_EPID_ERROR(result);
    387     result = NewFfElement(ps->Fq2, &by_);
    388     BREAK_ON_EPID_ERROR(result);
    389     result = NewFfElement(ps->ff, &f);
    390     BREAK_ON_EPID_ERROR(result);
    391     result = NewFfElement(ps->Fq2, &neg_qy);
    392     BREAK_ON_EPID_ERROR(result);
    393 
    394     // 1. If neg = 0, compute integer s = 6t + 2, otherwise, compute
    395     // s = 6t - 2
    396     result = NewBigNum(sizeof(BigNumStr), &s);
    397     BREAK_ON_EPID_ERROR(result);
    398     result = NewBigNum(sizeof(BigNumStr), &two);
    399     BREAK_ON_EPID_ERROR(result);
    400     sts = ippsSet_BN(IppsBigNumPOS, sizeof(two_dat) / sizeof(Ipp32u), two_dat,
    401                      two->ipp_bn);
    402     BREAK_ON_IPP_ERROR(sts, result);
    403     result = NewBigNum(sizeof(BigNumStr), &six);
    404     BREAK_ON_EPID_ERROR(result);
    405     sts = ippsSet_BN(IppsBigNumPOS, sizeof(six_dat) / sizeof(Ipp32u), six_dat,
    406                      six->ipp_bn);
    407     BREAK_ON_IPP_ERROR(sts, result);
    408     sts = ippsMul_BN(six->ipp_bn, ps->t->ipp_bn, s->ipp_bn);
    409     BREAK_ON_IPP_ERROR(sts, result);
    410     if (ps->neg) {
    411       sts = ippsSub_BN(s->ipp_bn, two->ipp_bn, s->ipp_bn);
    412       BREAK_ON_IPP_ERROR(sts, result);
    413     } else {
    414       sts = ippsAdd_BN(s->ipp_bn, two->ipp_bn, s->ipp_bn);
    415       BREAK_ON_IPP_ERROR(sts, result);
    416     }
    417     // 2. Let sn...s1s0 be the ternary representation of s, that is s =
    418     // s0 + 2*s1 + ... + 2^n*sn, where si is in {-1, 0, 1}.
    419     result =
    420         Ternary(s_ternary, &n, sizeof(s_ternary) / sizeof(s_ternary[0]), s);
    421     BREAK_ON_EPID_ERROR(result);
    422     // 3. Set (ax, ay) = E(Fq).outputPoint(a)
    423     // check if a is in ga that was used to create ps
    424     result = WriteEcPoint(ps->ga, a, &first_val_str, sizeof(first_val_str));
    425     BREAK_ON_EPID_ERROR(result);
    426     result =
    427         EcInGroup(ps->ga, &first_val_str, sizeof(first_val_str), &in_group);
    428     BREAK_ON_EPID_ERROR(result);
    429     if (false == in_group) {
    430       result = kEpidBadArgErr;
    431       break;
    432     }
    433     sts = ippsGFpECGetPoint(a->ipp_ec_pt, ax->ipp_ff_elem, ay->ipp_ff_elem,
    434                             ps->ga->ipp_ec);
    435     BREAK_ON_IPP_ERROR(sts, result);
    436     // 4. Set (bx, by) = E(Fq2).outputPoint(b).
    437     // check if b is in gb that was used to create ps
    438     result = WriteEcPoint(ps->gb, b, &second_val_str, sizeof(second_val_str));
    439     BREAK_ON_EPID_ERROR(result);
    440     result =
    441         EcInGroup(ps->gb, &second_val_str, sizeof(second_val_str), &in_group);
    442     BREAK_ON_EPID_ERROR(result);
    443     if (false == in_group) {
    444       result = kEpidBadArgErr;
    445       break;
    446     }
    447     sts = ippsGFpECGetPoint(b->ipp_ec_pt, bx->ipp_ff_elem, by->ipp_ff_elem,
    448                             ps->gb->ipp_ec);
    449     BREAK_ON_IPP_ERROR(sts, result);
    450     // 5. Set X = bx, Y = by, Z = Z2 = 1.
    451     sts = ippsGFpCpyElement(bx->ipp_ff_elem, x->ipp_ff_elem, ps->Fq2->ipp_ff);
    452     BREAK_ON_IPP_ERROR(sts, result);
    453     sts = ippsGFpCpyElement(by->ipp_ff_elem, y->ipp_ff_elem, ps->Fq2->ipp_ff);
    454     BREAK_ON_IPP_ERROR(sts, result);
    455     sts = ippsGFpSetElement(one_dat, sizeof(one_dat) / sizeof(Ipp32u),
    456                             z->ipp_ff_elem, ps->Fq2->ipp_ff);
    457     BREAK_ON_IPP_ERROR(sts, result);
    458     sts = ippsGFpSetElement(one_dat, sizeof(one_dat) / sizeof(Ipp32u),
    459                             z2->ipp_ff_elem, ps->Fq2->ipp_ff);
    460     BREAK_ON_IPP_ERROR(sts, result);
    461     // 6. Set d = 1.
    462     sts = ippsGFpSetElement(one_dat, sizeof(one_dat) / sizeof(Ipp32u),
    463                             d->ipp_ff_elem, ps->ff->ipp_ff);
    464     BREAK_ON_IPP_ERROR(sts, result);
    465     // 7. For i = n-1, ..., 0, do the following:
    466     for (i = n - 1; i >= 0; i--) {
    467       // a. Set (f, x, y, z, z2) = tangent(ax, ay, x, y, z, z2),
    468       result = Tangent(ps->ff, f, x, y, z, z2, ax, ay, x, y, z, z2);
    469       BREAK_ON_EPID_ERROR(result);
    470       // b. Set d = Fq12.square(d),
    471       sts = ippsGFpMul(d->ipp_ff_elem, d->ipp_ff_elem, d->ipp_ff_elem,
    472                        ps->ff->ipp_ff);
    473       BREAK_ON_IPP_ERROR(sts, result);
    474       // c. Set d = Fq12.mulSpecial(d, f),
    475       result = MulSpecial(d, d, f, ps);
    476       BREAK_ON_EPID_ERROR(result);
    477       // d. If s[i] = -1 then
    478       if (-1 == s_ternary[i]) {
    479         // i. Set (f, x, y, z, z2) = line(ax, ay, x, y, z, z2, bx,
    480         // -by),
    481         BREAK_ON_EPID_ERROR(result);
    482         sts = ippsGFpNeg(by->ipp_ff_elem, neg_qy->ipp_ff_elem, ps->Fq2->ipp_ff);
    483         BREAK_ON_IPP_ERROR(sts, result);
    484         result = Line(ps->ff, f, x, y, z, z2, ax, ay, x, y, z, z2, bx, neg_qy);
    485         BREAK_ON_EPID_ERROR(result);
    486         // ii. Set d = Fq12.mulSpecial(d, f).
    487         result = MulSpecial(d, d, f, ps);
    488         BREAK_ON_EPID_ERROR(result);
    489       }
    490       // e. If s[i] = 1 then
    491       if (1 == s_ternary[i]) {
    492         // i. Set (f, x, y, z, z2) = line(ax, ay, x, y, z, z2, bx,
    493         // by),
    494         result = Line(ps->ff, f, x, y, z, z2, ax, ay, x, y, z, z2, bx, by);
    495         BREAK_ON_EPID_ERROR(result);
    496         // ii. Set d = Fq12.mulSpecial(d, f).
    497         result = MulSpecial(d, d, f, ps);
    498         BREAK_ON_EPID_ERROR(result);
    499       }
    500     }
    501 
    502     // 8. if neg = true,
    503     if (ps->neg) {
    504       // a. Set Y = Fq2.negate(y),
    505       sts = ippsGFpNeg(y->ipp_ff_elem, y->ipp_ff_elem, ps->Fq2->ipp_ff);
    506       BREAK_ON_IPP_ERROR(sts, result);
    507       // b. Set d = Fq12.conjugate(d).
    508       sts = ippsGFpConj(d->ipp_ff_elem, d->ipp_ff_elem, ps->ff->ipp_ff);
    509       BREAK_ON_IPP_ERROR(sts, result);
    510     }
    511     // 9. Set (bx', by') = Pi-op(bx, by, 1).
    512     result = PiOp(ps, bx_, by_, bx, by, 1);
    513     BREAK_ON_EPID_ERROR(result);
    514     // 10. Set (f, x, y, z, z2) = line(ax, ay, x, y, z, z2, bx', by').
    515     result = Line(ps->ff, f, x, y, z, z2, ax, ay, x, y, z, z2, bx_, by_);
    516     BREAK_ON_EPID_ERROR(result);
    517     // 11. Set d = Fq12.mulSpecial(d, f).
    518     result = MulSpecial(d, d, f, ps);
    519     BREAK_ON_EPID_ERROR(result);
    520     // 12. Set (bx', by') = piOp(bx, by, 2).
    521     result = PiOp(ps, bx_, by_, bx, by, 2);
    522     BREAK_ON_EPID_ERROR(result);
    523     // 13. Set by' = Fq2.negate(by').
    524     sts = ippsGFpNeg(by_->ipp_ff_elem, by_->ipp_ff_elem, ps->Fq2->ipp_ff);
    525     BREAK_ON_IPP_ERROR(sts, result);
    526     // 14. Set (f, x, y, z, z2) = line(ax, ay, x, y, z, z2, bx', by').
    527     result = Line(ps->ff, f, x, y, z, z2, ax, ay, x, y, z, z2, bx_, by_);
    528     BREAK_ON_EPID_ERROR(result);
    529     // 15. Set d = Fq12.mulSpecial(d, f).
    530     result = MulSpecial(d, d, f, ps);
    531     BREAK_ON_EPID_ERROR(result);
    532     // 16. Set d = finalExp(d).
    533     result = FinalExp(ps, d, d);
    534     BREAK_ON_EPID_ERROR(result);
    535     // 17. Return d.
    536     result = kEpidNoErr;
    537   } while (0);
    538 
    539   DeleteFfElement(&ax);
    540   DeleteFfElement(&ay);
    541   DeleteFfElement(&bx);
    542   DeleteFfElement(&by);
    543   DeleteFfElement(&x);
    544   DeleteFfElement(&y);
    545   DeleteFfElement(&z);
    546   DeleteFfElement(&z2);
    547   DeleteFfElement(&bx_);
    548   DeleteFfElement(&by_);
    549   DeleteFfElement(&f);
    550   DeleteFfElement(&neg_qy);
    551 
    552   DeleteBigNum(&s);
    553   DeleteBigNum(&two);
    554   DeleteBigNum(&six);
    555 
    556   return result;
    557 }
    558 
    559 /*
    560 d = finalExp(h)
    561 Input: h (an element in GT)
    562 Output: d (an element in GT) where d = GT.exp(h, (q^12-1)/p)
    563 */
    564 static EpidStatus FinalExp(PairingState* ps, FfElement* d, FfElement const* h) {
    565   EpidStatus result = kEpidErr;
    566   FfElement* f = NULL;
    567   FfElement* f1 = NULL;
    568   FfElement* f2 = NULL;
    569   FfElement* f3 = NULL;
    570   FfElement* ft1 = NULL;
    571   FfElement* ft2 = NULL;
    572   FfElement* ft3 = NULL;
    573   FfElement* fp1 = NULL;
    574   FfElement* fp2 = NULL;
    575   FfElement* fp3 = NULL;
    576   FfElement* y0 = NULL;
    577   FfElement* y1 = NULL;
    578   FfElement* y2 = NULL;
    579   FfElement* y3 = NULL;
    580   FfElement* y4 = NULL;
    581   FfElement* y5 = NULL;
    582   FfElement* y6 = NULL;
    583   FfElement* t0 = NULL;
    584   FfElement* t1 = NULL;
    585   do {
    586     IppStatus sts = ippStsNoErr;
    587     // Check parameters
    588     if (!ps || !d || !h) {
    589       result = kEpidBadArgErr;
    590       break;
    591     }
    592     if (!d->ipp_ff_elem || !h->ipp_ff_elem || !ps->ff || !ps->ff->ipp_ff ||
    593         !ps->t || !ps->t->ipp_bn) {
    594       result = kEpidBadArgErr;
    595       break;
    596     }
    597     // Let f, f1, f2, f3, ft1, ft2, ft3, fp1, fp2, fp3, y0, y1, y2,
    598     // y3, y4, y5, y6, t0, t1 be temporary variables in GT. All the
    599     // following operations are computed in Fq12 unless explicitly
    600     // specified.
    601     result = NewFfElement(ps->ff, &f);
    602     BREAK_ON_EPID_ERROR(result);
    603     result = NewFfElement(ps->ff, &f1);
    604     BREAK_ON_EPID_ERROR(result);
    605     result = NewFfElement(ps->ff, &f2);
    606     BREAK_ON_EPID_ERROR(result);
    607     result = NewFfElement(ps->ff, &f3);
    608     BREAK_ON_EPID_ERROR(result);
    609     result = NewFfElement(ps->ff, &ft1);
    610     BREAK_ON_EPID_ERROR(result);
    611     result = NewFfElement(ps->ff, &ft2);
    612     BREAK_ON_EPID_ERROR(result);
    613     result = NewFfElement(ps->ff, &ft3);
    614     BREAK_ON_EPID_ERROR(result);
    615     result = NewFfElement(ps->ff, &fp1);
    616     BREAK_ON_EPID_ERROR(result);
    617     result = NewFfElement(ps->ff, &fp2);
    618     BREAK_ON_EPID_ERROR(result);
    619     result = NewFfElement(ps->ff, &fp3);
    620     BREAK_ON_EPID_ERROR(result);
    621     result = NewFfElement(ps->ff, &y0);
    622     BREAK_ON_EPID_ERROR(result);
    623     result = NewFfElement(ps->ff, &y1);
    624     BREAK_ON_EPID_ERROR(result);
    625     result = NewFfElement(ps->ff, &y2);
    626     BREAK_ON_EPID_ERROR(result);
    627     result = NewFfElement(ps->ff, &y3);
    628     BREAK_ON_EPID_ERROR(result);
    629     result = NewFfElement(ps->ff, &y4);
    630     BREAK_ON_EPID_ERROR(result);
    631     result = NewFfElement(ps->ff, &y5);
    632     BREAK_ON_EPID_ERROR(result);
    633     result = NewFfElement(ps->ff, &y6);
    634     BREAK_ON_EPID_ERROR(result);
    635     result = NewFfElement(ps->ff, &t0);
    636     BREAK_ON_EPID_ERROR(result);
    637     result = NewFfElement(ps->ff, &t1);
    638     BREAK_ON_EPID_ERROR(result);
    639     // 1.  Set f1 = Fq12.conjugate(h).
    640     sts = ippsGFpConj(h->ipp_ff_elem, f1->ipp_ff_elem, ps->ff->ipp_ff);
    641     BREAK_ON_IPP_ERROR(sts, result);
    642     // 2.  Set f2 = Fq12.inverse(h).
    643     sts = ippsGFpInv(h->ipp_ff_elem, f2->ipp_ff_elem, ps->ff->ipp_ff);
    644     BREAK_ON_IPP_ERROR(sts, result);
    645     // 3.  Set f = f1 * f2.
    646     sts = ippsGFpMul(f1->ipp_ff_elem, f2->ipp_ff_elem, f->ipp_ff_elem,
    647                      ps->ff->ipp_ff);
    648     BREAK_ON_IPP_ERROR(sts, result);
    649     // 4.  Set f3 = frobeniusOp(f, 2).
    650     result = FrobeniusOp(ps, f3, f, 2);
    651     BREAK_ON_EPID_ERROR(result);
    652     // 5.  Set f = f3 * f.
    653     sts = ippsGFpMul(f3->ipp_ff_elem, f->ipp_ff_elem, f->ipp_ff_elem,
    654                      ps->ff->ipp_ff);
    655     BREAK_ON_IPP_ERROR(sts, result);
    656     // 6.  Set ft1 = Fq12.expCyclotomic (f, t).
    657     result = ExpCyclotomic(ps, ft1, f, ps->t);
    658     BREAK_ON_EPID_ERROR(result);
    659     // 7.  If neg = true, ft1 = Fq12.conjugate(ft1).
    660     if (ps->neg) {
    661       sts = ippsGFpConj(ft1->ipp_ff_elem, ft1->ipp_ff_elem, ps->ff->ipp_ff);
    662       BREAK_ON_IPP_ERROR(sts, result);
    663     }
    664     // 8.  Set ft2 = Fq12.expCyclotomic (ft1, t).
    665     result = ExpCyclotomic(ps, ft2, ft1, ps->t);
    666     BREAK_ON_EPID_ERROR(result);
    667     // 9.  If neg = true, ft2 = Fq12.conjugate(ft2).
    668     if (ps->neg) {
    669       sts = ippsGFpConj(ft2->ipp_ff_elem, ft2->ipp_ff_elem, ps->ff->ipp_ff);
    670       BREAK_ON_IPP_ERROR(sts, result);
    671     }
    672     // 10. Set ft3 = Fq12.expCyclotomic (ft2, t).
    673     result = ExpCyclotomic(ps, ft3, ft2, ps->t);
    674     BREAK_ON_EPID_ERROR(result);
    675     // 11. If neg = true, ft3 = Fq12.conjugate(ft3).
    676     if (ps->neg) {
    677       sts = ippsGFpConj(ft3->ipp_ff_elem, ft3->ipp_ff_elem, ps->ff->ipp_ff);
    678       BREAK_ON_IPP_ERROR(sts, result);
    679     }
    680     // 12. Set fp1 = frobeniusOp(f, 1).
    681     result = FrobeniusOp(ps, fp1, f, 1);
    682     BREAK_ON_EPID_ERROR(result);
    683     // 13. Set fp2 = frobeniusOp(f, 2).
    684     result = FrobeniusOp(ps, fp2, f, 2);
    685     BREAK_ON_EPID_ERROR(result);
    686     // 14. Set fp3 = frobeniusOp(f, 3).
    687     result = FrobeniusOp(ps, fp3, f, 3);
    688     BREAK_ON_EPID_ERROR(result);
    689     // 15. Set y0 = fp1 * fp2 * fp3.
    690     sts = ippsGFpMul(fp1->ipp_ff_elem, fp2->ipp_ff_elem, y0->ipp_ff_elem,
    691                      ps->ff->ipp_ff);
    692     BREAK_ON_IPP_ERROR(sts, result);
    693     sts = ippsGFpMul(y0->ipp_ff_elem, fp3->ipp_ff_elem, y0->ipp_ff_elem,
    694                      ps->ff->ipp_ff);
    695     BREAK_ON_IPP_ERROR(sts, result);
    696     // 16. Set y1 = Fq12.conjugate(f).
    697     sts = ippsGFpConj(f->ipp_ff_elem, y1->ipp_ff_elem, ps->ff->ipp_ff);
    698     BREAK_ON_IPP_ERROR(sts, result);
    699     // 17. Set y2 = frobeniusOp(ft2, 2).
    700     result = FrobeniusOp(ps, y2, ft2, 2);
    701     BREAK_ON_EPID_ERROR(result);
    702     // 18. Set y3 = frobeniusOp(ft1, 1).
    703     result = FrobeniusOp(ps, y3, ft1, 1);
    704     BREAK_ON_EPID_ERROR(result);
    705     // 19. Set y3 = Fq12.conjugate(y3).
    706     sts = ippsGFpConj(y3->ipp_ff_elem, y3->ipp_ff_elem, ps->ff->ipp_ff);
    707     BREAK_ON_IPP_ERROR(sts, result);
    708     // 20. Set y4 = frobeniusOp(ft2, 1).
    709     result = FrobeniusOp(ps, y4, ft2, 1);
    710     BREAK_ON_EPID_ERROR(result);
    711     // 21. Set y4 = y4 * ft1.
    712     sts = ippsGFpMul(y4->ipp_ff_elem, ft1->ipp_ff_elem, y4->ipp_ff_elem,
    713                      ps->ff->ipp_ff);
    714     BREAK_ON_IPP_ERROR(sts, result);
    715     // 22. Set y4 = Fq12.conjugate(y4).
    716     sts = ippsGFpConj(y4->ipp_ff_elem, y4->ipp_ff_elem, ps->ff->ipp_ff);
    717     BREAK_ON_IPP_ERROR(sts, result);
    718     // 23. Set y5 = Fq12.conjugate(ft2).
    719     sts = ippsGFpConj(ft2->ipp_ff_elem, y5->ipp_ff_elem, ps->ff->ipp_ff);
    720     BREAK_ON_IPP_ERROR(sts, result);
    721     // 24. Set y6 = frobeniusOp(ft3, 1).
    722     result = FrobeniusOp(ps, y6, ft3, 1);
    723     BREAK_ON_EPID_ERROR(result);
    724     // 25. Set y6 = y6 * ft3.
    725     sts = ippsGFpMul(y6->ipp_ff_elem, ft3->ipp_ff_elem, y6->ipp_ff_elem,
    726                      ps->ff->ipp_ff);
    727     BREAK_ON_IPP_ERROR(sts, result);
    728     // 26. Set y6 = Fq12.conjugate(y6).
    729     sts = ippsGFpConj(y6->ipp_ff_elem, y6->ipp_ff_elem, ps->ff->ipp_ff);
    730     BREAK_ON_IPP_ERROR(sts, result);
    731     // 27. Set t0 = Fq12.squareCyclotomic(y6).
    732     result = SquareCyclotomic(ps, t0, y6);
    733     BREAK_ON_EPID_ERROR(result);
    734     // 28. Set t0 = t0 * y4 * y5.
    735     sts = ippsGFpMul(t0->ipp_ff_elem, y4->ipp_ff_elem, t0->ipp_ff_elem,
    736                      ps->ff->ipp_ff);
    737     BREAK_ON_IPP_ERROR(sts, result);
    738     sts = ippsGFpMul(t0->ipp_ff_elem, y5->ipp_ff_elem, t0->ipp_ff_elem,
    739                      ps->ff->ipp_ff);
    740     BREAK_ON_IPP_ERROR(sts, result);
    741     // 29. Set t1 = y3 * y5 * t0.
    742     sts = ippsGFpMul(y3->ipp_ff_elem, y5->ipp_ff_elem, t1->ipp_ff_elem,
    743                      ps->ff->ipp_ff);
    744     BREAK_ON_IPP_ERROR(sts, result);
    745     sts = ippsGFpMul(t1->ipp_ff_elem, t0->ipp_ff_elem, t1->ipp_ff_elem,
    746                      ps->ff->ipp_ff);
    747     BREAK_ON_IPP_ERROR(sts, result);
    748     // 30. Set t0 = t0 * y2.
    749     sts = ippsGFpMul(t0->ipp_ff_elem, y2->ipp_ff_elem, t0->ipp_ff_elem,
    750                      ps->ff->ipp_ff);
    751     BREAK_ON_IPP_ERROR(sts, result);
    752     // 31. Set t1 = Fq12.squareCyclotomic(t1).
    753     result = SquareCyclotomic(ps, t1, t1);
    754     BREAK_ON_EPID_ERROR(result);
    755     // 32. Set t1 = t1 * t0.
    756     sts = ippsGFpMul(t1->ipp_ff_elem, t0->ipp_ff_elem, t1->ipp_ff_elem,
    757                      ps->ff->ipp_ff);
    758     BREAK_ON_IPP_ERROR(sts, result);
    759     // 33. Set t1 = Fq12.squareCyclotomic(t1).
    760     result = SquareCyclotomic(ps, t1, t1);
    761     BREAK_ON_EPID_ERROR(result);
    762     // 34. Set t0 = t1 * y1.
    763     sts = ippsGFpMul(t1->ipp_ff_elem, y1->ipp_ff_elem, t0->ipp_ff_elem,
    764                      ps->ff->ipp_ff);
    765     BREAK_ON_IPP_ERROR(sts, result);
    766     // 35. Set t1 = t1 * y0.
    767     sts = ippsGFpMul(t1->ipp_ff_elem, y0->ipp_ff_elem, t1->ipp_ff_elem,
    768                      ps->ff->ipp_ff);
    769     BREAK_ON_IPP_ERROR(sts, result);
    770     // 36. Set t0 = Fq12.squareCyclotomic(t0).
    771     result = SquareCyclotomic(ps, t0, t0);
    772     BREAK_ON_EPID_ERROR(result);
    773     // 37. Set d = t1 * t0.
    774     sts = ippsGFpMul(t1->ipp_ff_elem, t0->ipp_ff_elem, d->ipp_ff_elem,
    775                      ps->ff->ipp_ff);
    776     BREAK_ON_IPP_ERROR(sts, result);
    777     // 38. Return d.
    778     result = kEpidNoErr;
    779   } while (0);
    780 
    781   DeleteFfElement(&f);
    782   DeleteFfElement(&f1);
    783   DeleteFfElement(&f2);
    784   DeleteFfElement(&f3);
    785   DeleteFfElement(&ft1);
    786   DeleteFfElement(&ft2);
    787   DeleteFfElement(&ft3);
    788   DeleteFfElement(&fp1);
    789   DeleteFfElement(&fp2);
    790   DeleteFfElement(&fp3);
    791   DeleteFfElement(&y0);
    792   DeleteFfElement(&y1);
    793   DeleteFfElement(&y2);
    794   DeleteFfElement(&y3);
    795   DeleteFfElement(&y4);
    796   DeleteFfElement(&y5);
    797   DeleteFfElement(&y6);
    798   DeleteFfElement(&t0);
    799   DeleteFfElement(&t1);
    800 
    801   return result;
    802 }
    803 
    804 /*
    805 (x', y') = piOp(x, y, e)
    806 Input: x, y (elements in Fq2), e (an integer of value 1 or 2)
    807 Output: x', y' (elements in Fq2)
    808 */
    809 static EpidStatus PiOp(PairingState* ps, FfElement* x_out, FfElement* y_out,
    810                        FfElement const* x, FfElement const* y, const int e) {
    811   IppStatus sts = ippStsNoErr;
    812   IppsGFpState* Fq2 = 0;
    813   IppsGFpState* Fq6 = 0;
    814   FiniteField* Ffq12 = 0;
    815   FiniteField* Ffq6 = 0;
    816   FiniteField* Ffq2 = 0;
    817   // check parameters
    818   if (!ps || !x_out || !y_out || !x || !y) {
    819     return kEpidBadArgErr;
    820   }
    821   if (e < 1 || e > 3) {
    822     return kEpidBadArgErr;
    823   }
    824   Ffq12 = ps->ff;
    825   // get Fq6, Fq2
    826   if (!Ffq12) {
    827     return kEpidBadArgErr;
    828   }
    829   Ffq6 = Ffq12->ground_ff;
    830   if (!Ffq6) {
    831     return kEpidBadArgErr;
    832   }
    833   Fq6 = Ffq6->ipp_ff;
    834   Ffq2 = Ffq6->ground_ff;
    835   if (!Ffq2) {
    836     return kEpidBadArgErr;
    837   }
    838   Fq2 = Ffq2->ipp_ff;
    839   // 1. Set x' = x and y' = y.
    840   sts = ippsGFpCpyElement(x->ipp_ff_elem, x_out->ipp_ff_elem, Fq2);
    841   RETURN_ON_IPP_ERROR(sts);
    842   sts = ippsGFpCpyElement(y->ipp_ff_elem, y_out->ipp_ff_elem, Fq2);
    843   RETURN_ON_IPP_ERROR(sts);
    844   if (1 == e) {
    845     // 2. If e = 1,
    846     //   a. Compute x' = Fq2.conjugate(x').
    847     sts = ippsGFpConj(x_out->ipp_ff_elem, x_out->ipp_ff_elem, Fq2);
    848     RETURN_ON_IPP_ERROR(sts);
    849     //   b. Compute y' = Fq2.conjugate(y').
    850     sts = ippsGFpConj(y_out->ipp_ff_elem, y_out->ipp_ff_elem, Fq2);
    851     RETURN_ON_IPP_ERROR(sts);
    852   }
    853   // 3. Compute x' = Fq2.mul(x', g[e-1][1]).
    854   sts = ippsGFpMul(x_out->ipp_ff_elem, ps->g[e - 1][1]->ipp_ff_elem,
    855                    x_out->ipp_ff_elem, Fq2);
    856   RETURN_ON_IPP_ERROR(sts);
    857   // 4. Compute y' = Fq2.mul(y', g[e-1][2]).
    858   sts = ippsGFpMul(y_out->ipp_ff_elem, ps->g[e - 1][2]->ipp_ff_elem,
    859                    y_out->ipp_ff_elem, Fq2);
    860   RETURN_ON_IPP_ERROR(sts);
    861   // 5. Return (x', y').
    862   return kEpidNoErr;
    863 }
    864 
    865 /*
    866 d = frobeniusOp(a, e)
    867 Input: a (an element in GT), e (an integer of value 1, 2, or 3)
    868 Output: d (an element in GT) such that d = GT.exp(a, qe)
    869 
    870 */
    871 static EpidStatus FrobeniusOp(PairingState* ps, FfElement* d_out,
    872                               FfElement const* a, const int e) {
    873   EpidStatus result = kEpidErr;
    874   FfElement* d[6] = {0};
    875   size_t i = 0;
    876   Fq12ElemDat a_dat = {0};
    877   Fq12ElemDat d_dat = {0};
    878   do {
    879     IppStatus sts = ippStsNoErr;
    880     // check parameters
    881     if (!ps || !d_out || !a) {
    882       return kEpidBadArgErr;
    883     }
    884     if (!ps->ff || !ps->Fq2) {
    885       return kEpidBadArgErr;
    886     }
    887     if (e < 1 || e > 3 || !d_out->ipp_ff_elem || !a->ipp_ff_elem ||
    888         !ps->ff->ipp_ff || !ps->Fq2->ipp_ff) {
    889       return kEpidBadArgErr;
    890     }
    891 
    892     for (i = 0; i < sizeof(d) / sizeof(FfElement*); i++) {
    893       result = NewFfElement(ps->Fq2, &d[i]);
    894       BREAK_ON_EPID_ERROR(result);
    895     }
    896 
    897     // 1.  Let a = ((a[0], a[2], a[4]), (a[1], a[3], a[5])).
    898     sts = ippsGFpGetElement(a->ipp_ff_elem, (BNU)&a_dat,
    899                             sizeof(a_dat) / sizeof(Ipp32u), ps->ff->ipp_ff);
    900     BREAK_ON_IPP_ERROR(sts, result);
    901     // 2.  Let d = ((d[0], d[2], d[4]), (d[1], d[3], d[5])).
    902     // 3.  For i = 0, ..., 5,
    903     //   a. set d[i] = a[i].
    904     sts = ippsGFpSetElement((Ipp32u*)&a_dat.x[0].x[0],
    905                             sizeof(a_dat.x[0].x[0]) / sizeof(Ipp32u),
    906                             d[0]->ipp_ff_elem, ps->Fq2->ipp_ff);
    907     BREAK_ON_IPP_ERROR(sts, result);
    908     sts = ippsGFpSetElement((Ipp32u*)&a_dat.x[0].x[1],
    909                             sizeof(a_dat.x[0].x[1]) / sizeof(Ipp32u),
    910                             d[2]->ipp_ff_elem, ps->Fq2->ipp_ff);
    911     BREAK_ON_IPP_ERROR(sts, result);
    912     sts = ippsGFpSetElement((Ipp32u*)&a_dat.x[0].x[2],
    913                             sizeof(a_dat.x[0].x[2]) / sizeof(Ipp32u),
    914                             d[4]->ipp_ff_elem, ps->Fq2->ipp_ff);
    915     BREAK_ON_IPP_ERROR(sts, result);
    916     sts = ippsGFpSetElement((Ipp32u*)&a_dat.x[1].x[0],
    917                             sizeof(a_dat.x[1].x[0]) / sizeof(Ipp32u),
    918                             d[1]->ipp_ff_elem, ps->Fq2->ipp_ff);
    919     BREAK_ON_IPP_ERROR(sts, result);
    920     sts = ippsGFpSetElement((Ipp32u*)&a_dat.x[1].x[1],
    921                             sizeof(a_dat.x[1].x[1]) / sizeof(Ipp32u),
    922                             d[3]->ipp_ff_elem, ps->Fq2->ipp_ff);
    923     BREAK_ON_IPP_ERROR(sts, result);
    924     sts = ippsGFpSetElement((Ipp32u*)&a_dat.x[1].x[2],
    925                             sizeof(a_dat.x[1].x[2]) / sizeof(Ipp32u),
    926                             d[5]->ipp_ff_elem, ps->Fq2->ipp_ff);
    927     BREAK_ON_IPP_ERROR(sts, result);
    928 
    929     // b. If e = 1 or 3, set d[i] = Fq2.conjugate(d[i]).
    930     if (1 == e || 3 == e) {
    931       for (i = 0; i < sizeof(d) / sizeof(FfElement*); i++) {
    932         sts =
    933             ippsGFpConj(d[i]->ipp_ff_elem, d[i]->ipp_ff_elem, ps->Fq2->ipp_ff);
    934         BREAK_ON_IPP_ERROR(sts, result);
    935       }
    936     }
    937     // 4.  For i = 1, ..., 5, compute d[i] = Fq2.mul(d[i], g[e-1][i-1]).
    938     for (i = 1; i < sizeof(d) / sizeof(FfElement*); i++) {
    939       sts = ippsGFpMul(d[i]->ipp_ff_elem, ps->g[e - 1][i - 1]->ipp_ff_elem,
    940                        d[i]->ipp_ff_elem, ps->Fq2->ipp_ff);
    941       BREAK_ON_IPP_ERROR(sts, result);
    942     }
    943     // 5.  Return d.
    944     sts = ippsGFpGetElement(d[0]->ipp_ff_elem, (BNU)&d_dat.x[0].x[0],
    945                             sizeof(d_dat.x[0].x[0]) / sizeof(Ipp32u),
    946                             ps->Fq2->ipp_ff);
    947     BREAK_ON_IPP_ERROR(sts, result);
    948     sts = ippsGFpGetElement(d[2]->ipp_ff_elem, (BNU)&d_dat.x[0].x[1],
    949                             sizeof(d_dat.x[0].x[0]) / sizeof(Ipp32u),
    950                             ps->Fq2->ipp_ff);
    951     BREAK_ON_IPP_ERROR(sts, result);
    952     sts = ippsGFpGetElement(d[4]->ipp_ff_elem, (BNU)&d_dat.x[0].x[2],
    953                             sizeof(d_dat.x[0].x[0]) / sizeof(Ipp32u),
    954                             ps->Fq2->ipp_ff);
    955     BREAK_ON_IPP_ERROR(sts, result);
    956     sts = ippsGFpGetElement(d[1]->ipp_ff_elem, (BNU)&d_dat.x[1].x[0],
    957                             sizeof(d_dat.x[1].x[0]) / sizeof(Ipp32u),
    958                             ps->Fq2->ipp_ff);
    959     BREAK_ON_IPP_ERROR(sts, result);
    960     sts = ippsGFpGetElement(d[3]->ipp_ff_elem, (BNU)&d_dat.x[1].x[1],
    961                             sizeof(d_dat.x[1].x[0]) / sizeof(Ipp32u),
    962                             ps->Fq2->ipp_ff);
    963     BREAK_ON_IPP_ERROR(sts, result);
    964     sts = ippsGFpGetElement(d[5]->ipp_ff_elem, (BNU)&d_dat.x[1].x[2],
    965                             sizeof(d_dat.x[1].x[0]) / sizeof(Ipp32u),
    966                             ps->Fq2->ipp_ff);
    967     BREAK_ON_IPP_ERROR(sts, result);
    968     sts = ippsGFpSetElement((Ipp32u*)&d_dat, sizeof(d_dat) / sizeof(Ipp32u),
    969                             d_out->ipp_ff_elem, ps->ff->ipp_ff);
    970     BREAK_ON_IPP_ERROR(sts, result);
    971     result = kEpidNoErr;
    972   } while (0);
    973 
    974   EpidZeroMemory(&a_dat, sizeof(a_dat));
    975   EpidZeroMemory(&d_dat, sizeof(d_dat));
    976   for (i = 0; i < sizeof(d) / sizeof(FfElement*); i++) {
    977     DeleteFfElement(&d[i]);
    978   }
    979 
    980   return result;
    981 }
    982 
    983 /*
    984 (f, X', Y', Z', Z2') = line(Px, Py, X, Y, Z, Z2, Qx, Qy)
    985 Input: Px, Py (elements in Fq), X, Y, Z, Z2, Qx, Qy (elements in Fq2)
    986 Output: f (an element in GT), X', Y', Z', Z2' (elements in Fq2)
    987 */
    988 static EpidStatus Line(FiniteField* gt, FfElement* f, FfElement* x_out,
    989                        FfElement* y_out, FfElement* z_out, FfElement* z2_out,
    990                        FfElement const* px, FfElement const* py,
    991                        FfElement const* x, FfElement const* y,
    992                        FfElement const* z, FfElement const* z2,
    993                        FfElement const* qx, FfElement const* qy) {
    994   EpidStatus result = kEpidNotImpl;
    995   FfElement* t0 = NULL;
    996   FfElement* t1 = NULL;
    997   FfElement* t2 = NULL;
    998   FfElement* t3 = NULL;
    999   FfElement* t4 = NULL;
   1000   FfElement* t5 = NULL;
   1001   FfElement* t6 = NULL;
   1002   FfElement* t7 = NULL;
   1003   FfElement* t8 = NULL;
   1004   FfElement* t9 = NULL;
   1005   FfElement* t10 = NULL;
   1006   FfElement* t = NULL;
   1007   Fq12ElemDat fDat = {0};
   1008   do {
   1009     IppStatus sts = ippStsNoErr;
   1010     IppsGFpState* Fq2 = 0;
   1011     IppsGFpState* Fq6 = 0;
   1012     FiniteField* Ffq6 = 0;
   1013     FiniteField* Ffq2 = 0;
   1014 
   1015     // check parameters
   1016     if (!f || !x_out || !y_out || !z_out || !z2_out || !px || !py || !x || !y ||
   1017         !z || !z2 || !qx || !qy || !gt) {
   1018       result = kEpidBadArgErr;
   1019       break;
   1020     }
   1021     if (!f->ipp_ff_elem || !x_out->ipp_ff_elem || !y_out->ipp_ff_elem ||
   1022         !z_out->ipp_ff_elem || !z2_out->ipp_ff_elem || !px->ipp_ff_elem ||
   1023         !py->ipp_ff_elem || !x->ipp_ff_elem || !y->ipp_ff_elem ||
   1024         !z->ipp_ff_elem || !z2->ipp_ff_elem || !qx->ipp_ff_elem ||
   1025         !qy->ipp_ff_elem || !gt->ipp_ff) {
   1026       result = kEpidBadArgErr;
   1027       break;
   1028     }
   1029     // get Fq6, Fq2
   1030     Ffq6 = gt->ground_ff;
   1031     if (!Ffq6) {
   1032       return kEpidBadArgErr;
   1033     }
   1034     Fq6 = Ffq6->ipp_ff;
   1035     Ffq2 = Ffq6->ground_ff;
   1036     if (!Ffq2) {
   1037       return kEpidBadArgErr;
   1038     }
   1039     Fq2 = Ffq2->ipp_ff;
   1040     // Let t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10 be temporary
   1041     // elements in Fq2. All the following operations are computed in
   1042     // Fq2 unless explicitly specified.
   1043     result = NewFfElement(Ffq2, &t0);
   1044     if (kEpidNoErr != result) {
   1045       break;
   1046     }
   1047     result = NewFfElement(Ffq2, &t1);
   1048     if (kEpidNoErr != result) {
   1049       break;
   1050     }
   1051     result = NewFfElement(Ffq2, &t2);
   1052     if (kEpidNoErr != result) {
   1053       break;
   1054     }
   1055     result = NewFfElement(Ffq2, &t3);
   1056     if (kEpidNoErr != result) {
   1057       break;
   1058     }
   1059     result = NewFfElement(Ffq2, &t4);
   1060     if (kEpidNoErr != result) {
   1061       break;
   1062     }
   1063     result = NewFfElement(Ffq2, &t5);
   1064     if (kEpidNoErr != result) {
   1065       break;
   1066     }
   1067     result = NewFfElement(Ffq2, &t6);
   1068     if (kEpidNoErr != result) {
   1069       break;
   1070     }
   1071     result = NewFfElement(Ffq2, &t7);
   1072     if (kEpidNoErr != result) {
   1073       break;
   1074     }
   1075     result = NewFfElement(Ffq2, &t8);
   1076     if (kEpidNoErr != result) {
   1077       break;
   1078     }
   1079     result = NewFfElement(Ffq2, &t9);
   1080     if (kEpidNoErr != result) {
   1081       break;
   1082     }
   1083     result = NewFfElement(Ffq2, &t10);
   1084     if (kEpidNoErr != result) {
   1085       break;
   1086     }
   1087     result = NewFfElement(Ffq2, &t);
   1088     if (kEpidNoErr != result) {
   1089       break;
   1090     }
   1091     // 1. Set t0 = Qx * Z2.
   1092     sts =
   1093         ippsGFpMul(qx->ipp_ff_elem, z2_out->ipp_ff_elem, t0->ipp_ff_elem, Fq2);
   1094     BREAK_ON_IPP_ERROR(sts, result);
   1095     // 2. Set t1 = (Qy + Z)^2 - Qy * Qy - Z2.
   1096     sts = ippsGFpAdd(qy->ipp_ff_elem, z->ipp_ff_elem, t1->ipp_ff_elem, Fq2);
   1097     BREAK_ON_IPP_ERROR(sts, result);
   1098     sts = ippsGFpMul(t1->ipp_ff_elem, t1->ipp_ff_elem, t1->ipp_ff_elem, Fq2);
   1099     BREAK_ON_IPP_ERROR(sts, result);
   1100     sts = ippsGFpMul(qy->ipp_ff_elem, qy->ipp_ff_elem, t->ipp_ff_elem, Fq2);
   1101     BREAK_ON_IPP_ERROR(sts, result);
   1102     sts = ippsGFpSub(t1->ipp_ff_elem, t->ipp_ff_elem, t1->ipp_ff_elem, Fq2);
   1103     BREAK_ON_IPP_ERROR(sts, result);
   1104     sts = ippsGFpSub(t1->ipp_ff_elem, z2->ipp_ff_elem, t1->ipp_ff_elem, Fq2);
   1105     BREAK_ON_IPP_ERROR(sts, result);
   1106     // 3. Set t1 = t1 * Z2.
   1107     sts =
   1108         ippsGFpMul(t1->ipp_ff_elem, z2_out->ipp_ff_elem, t1->ipp_ff_elem, Fq2);
   1109     BREAK_ON_IPP_ERROR(sts, result);
   1110     // 4. Set t2 = t0 - X.
   1111     sts = ippsGFpSub(t0->ipp_ff_elem, x->ipp_ff_elem, t2->ipp_ff_elem, Fq2);
   1112     BREAK_ON_IPP_ERROR(sts, result);
   1113     //  5. Set t3 = t2 * t2.
   1114     sts = ippsGFpMul(t2->ipp_ff_elem, t2->ipp_ff_elem, t3->ipp_ff_elem, Fq2);
   1115     BREAK_ON_IPP_ERROR(sts, result);
   1116     // 6. Set t4 = 4 * t3.
   1117     sts = ippsGFpAdd(t3->ipp_ff_elem, t3->ipp_ff_elem, t4->ipp_ff_elem, Fq2);
   1118     BREAK_ON_IPP_ERROR(sts, result);
   1119     sts = ippsGFpAdd(t4->ipp_ff_elem, t4->ipp_ff_elem, t4->ipp_ff_elem, Fq2);
   1120     BREAK_ON_IPP_ERROR(sts, result);
   1121     // 7. Set t5 = t4 * t2.
   1122     sts = ippsGFpMul(t4->ipp_ff_elem, t2->ipp_ff_elem, t5->ipp_ff_elem, Fq2);
   1123     BREAK_ON_IPP_ERROR(sts, result);
   1124     // 8. Set t6 = t1 - Y - Y.
   1125     sts = ippsGFpSub(t1->ipp_ff_elem, y->ipp_ff_elem, t6->ipp_ff_elem, Fq2);
   1126     BREAK_ON_IPP_ERROR(sts, result);
   1127     sts = ippsGFpSub(t6->ipp_ff_elem, y->ipp_ff_elem, t6->ipp_ff_elem, Fq2);
   1128     BREAK_ON_IPP_ERROR(sts, result);
   1129     // 9. Set t9 = t6 * Qx.
   1130     sts = ippsGFpMul(t6->ipp_ff_elem, qx->ipp_ff_elem, t9->ipp_ff_elem, Fq2);
   1131     BREAK_ON_IPP_ERROR(sts, result);
   1132     // 10. Set t7 = X * t4.
   1133     sts = ippsGFpMul(x->ipp_ff_elem, t4->ipp_ff_elem, t7->ipp_ff_elem, Fq2);
   1134     BREAK_ON_IPP_ERROR(sts, result);
   1135     // 11. X' = t6 * t6 - t5 - t7 - t7.
   1136     sts = ippsGFpMul(t6->ipp_ff_elem, t6->ipp_ff_elem, x_out->ipp_ff_elem, Fq2);
   1137     BREAK_ON_IPP_ERROR(sts, result);
   1138     sts = ippsGFpSub(x_out->ipp_ff_elem, t5->ipp_ff_elem, x_out->ipp_ff_elem,
   1139                      Fq2);
   1140     BREAK_ON_IPP_ERROR(sts, result);
   1141     sts = ippsGFpSub(x_out->ipp_ff_elem, t7->ipp_ff_elem, x_out->ipp_ff_elem,
   1142                      Fq2);
   1143     BREAK_ON_IPP_ERROR(sts, result);
   1144     sts = ippsGFpSub(x_out->ipp_ff_elem, t7->ipp_ff_elem, x_out->ipp_ff_elem,
   1145                      Fq2);
   1146     BREAK_ON_IPP_ERROR(sts, result);
   1147     // 12. Set Z' = (Z + t2)^2 - Z2 - t3.
   1148     sts = ippsGFpAdd(z->ipp_ff_elem, t2->ipp_ff_elem, z_out->ipp_ff_elem, Fq2);
   1149     BREAK_ON_IPP_ERROR(sts, result);
   1150     sts = ippsGFpMul(z_out->ipp_ff_elem, z_out->ipp_ff_elem, z_out->ipp_ff_elem,
   1151                      Fq2);
   1152     BREAK_ON_IPP_ERROR(sts, result);
   1153     sts = ippsGFpSub(z_out->ipp_ff_elem, z2->ipp_ff_elem, z_out->ipp_ff_elem,
   1154                      Fq2);
   1155     BREAK_ON_IPP_ERROR(sts, result);
   1156     sts = ippsGFpSub(z_out->ipp_ff_elem, t3->ipp_ff_elem, z_out->ipp_ff_elem,
   1157                      Fq2);
   1158     BREAK_ON_IPP_ERROR(sts, result);
   1159     // 13. Set t10 = Qy + Z'.
   1160     sts =
   1161         ippsGFpAdd(qy->ipp_ff_elem, z_out->ipp_ff_elem, t10->ipp_ff_elem, Fq2);
   1162     BREAK_ON_IPP_ERROR(sts, result);
   1163     // 14. Set t8 = (t7 - X') * t6.
   1164     sts = ippsGFpSub(t7->ipp_ff_elem, x_out->ipp_ff_elem, t8->ipp_ff_elem, Fq2);
   1165     BREAK_ON_IPP_ERROR(sts, result);
   1166     sts = ippsGFpMul(t8->ipp_ff_elem, t6->ipp_ff_elem, t8->ipp_ff_elem, Fq2);
   1167     BREAK_ON_IPP_ERROR(sts, result);
   1168     // 15. Set t0 = 2 * Y * t5.
   1169     sts = ippsGFpMul(y->ipp_ff_elem, t5->ipp_ff_elem, t0->ipp_ff_elem, Fq2);
   1170     BREAK_ON_IPP_ERROR(sts, result);
   1171     sts = ippsGFpAdd(t0->ipp_ff_elem, t0->ipp_ff_elem, t0->ipp_ff_elem, Fq2);
   1172     BREAK_ON_IPP_ERROR(sts, result);
   1173     // 16. Set Y' = t8 - t0.
   1174     sts = ippsGFpSub(t8->ipp_ff_elem, t0->ipp_ff_elem, y_out->ipp_ff_elem, Fq2);
   1175     BREAK_ON_IPP_ERROR(sts, result);
   1176     // 17. Set Z2' = Z' * Z'.
   1177     sts = ippsGFpMul(z_out->ipp_ff_elem, z_out->ipp_ff_elem,
   1178                      z2_out->ipp_ff_elem, Fq2);
   1179     BREAK_ON_IPP_ERROR(sts, result);
   1180     // 18. Set t10 = t10 * t10 - Qy * Qy - Z2'.
   1181     sts = ippsGFpMul(t10->ipp_ff_elem, t10->ipp_ff_elem, t10->ipp_ff_elem, Fq2);
   1182     BREAK_ON_IPP_ERROR(sts, result);
   1183     sts = ippsGFpSub(t10->ipp_ff_elem, t->ipp_ff_elem, t10->ipp_ff_elem,
   1184                      Fq2);  // t still Qy*Qy
   1185     BREAK_ON_IPP_ERROR(sts, result);
   1186     sts = ippsGFpSub(t10->ipp_ff_elem, z2_out->ipp_ff_elem, t10->ipp_ff_elem,
   1187                      Fq2);
   1188     BREAK_ON_IPP_ERROR(sts, result);
   1189     // 19. Set t9 = t9 + t9 - t10.
   1190     sts = ippsGFpAdd(t9->ipp_ff_elem, t9->ipp_ff_elem, t9->ipp_ff_elem, Fq2);
   1191     BREAK_ON_IPP_ERROR(sts, result);
   1192     sts = ippsGFpSub(t9->ipp_ff_elem, t10->ipp_ff_elem, t9->ipp_ff_elem, Fq2);
   1193     BREAK_ON_IPP_ERROR(sts, result);
   1194     // 20. Set t10 = Fq2.mul(Z', Py).
   1195     sts = ippsGFpMul_PE(z_out->ipp_ff_elem, py->ipp_ff_elem, t10->ipp_ff_elem,
   1196                         Fq2);
   1197     BREAK_ON_IPP_ERROR(sts, result);
   1198     // 21. Set t10 = t10 + t10.
   1199     sts = ippsGFpAdd(t10->ipp_ff_elem, t10->ipp_ff_elem, t10->ipp_ff_elem, Fq2);
   1200     BREAK_ON_IPP_ERROR(sts, result);
   1201     // 22. Set t6 = -t6.
   1202     sts = ippsGFpNeg(t6->ipp_ff_elem, t6->ipp_ff_elem, Fq2);
   1203     BREAK_ON_IPP_ERROR(sts, result);
   1204     // 23. Set t1 = Fq2.mul(t6, Px).
   1205     sts = ippsGFpMul_PE(t6->ipp_ff_elem, px->ipp_ff_elem, t1->ipp_ff_elem, Fq2);
   1206     BREAK_ON_IPP_ERROR(sts, result);
   1207     // 24. Set t1 = t1 + t1.
   1208     sts = ippsGFpAdd(t1->ipp_ff_elem, t1->ipp_ff_elem, t1->ipp_ff_elem, Fq2);
   1209     BREAK_ON_IPP_ERROR(sts, result);
   1210     // 25. Set f = ((t10, 0, 0), (t1, t9, 0)).
   1211     sts = ippsGFpGetElement(t10->ipp_ff_elem, (BNU)&fDat.x[0].x[0],
   1212                             sizeof(fDat.x[0].x[0]) / sizeof(Ipp32u), Fq2);
   1213     BREAK_ON_IPP_ERROR(sts, result);
   1214     sts = ippsGFpGetElement(t1->ipp_ff_elem, (BNU)&fDat.x[1].x[0],
   1215                             sizeof(fDat.x[1].x[0]) / sizeof(Ipp32u), Fq2);
   1216     BREAK_ON_IPP_ERROR(sts, result);
   1217     sts = ippsGFpGetElement(t9->ipp_ff_elem, (BNU)&fDat.x[1].x[1],
   1218                             sizeof(fDat.x[1].x[1]) / sizeof(Ipp32u), Fq2);
   1219     BREAK_ON_IPP_ERROR(sts, result);
   1220     sts = ippsGFpSetElement((Ipp32u*)&fDat, sizeof(fDat) / sizeof(Ipp32u),
   1221                             f->ipp_ff_elem, gt->ipp_ff);
   1222     BREAK_ON_IPP_ERROR(sts, result);
   1223     // 26. Return (f, X', Y', Z', Z2').
   1224   } while (0);
   1225   EpidZeroMemory(&fDat, sizeof(fDat));
   1226   DeleteFfElement(&t);
   1227   DeleteFfElement(&t10);
   1228   DeleteFfElement(&t9);
   1229   DeleteFfElement(&t8);
   1230   DeleteFfElement(&t7);
   1231   DeleteFfElement(&t6);
   1232   DeleteFfElement(&t5);
   1233   DeleteFfElement(&t4);
   1234   DeleteFfElement(&t3);
   1235   DeleteFfElement(&t2);
   1236   DeleteFfElement(&t1);
   1237   DeleteFfElement(&t0);
   1238 
   1239   return (result);
   1240 }
   1241 
   1242 /*
   1243 (f, X', Y', Z', Z2') = tangent(Px, Py, X, Y, Z, Z2)
   1244 Input: Px, Py (elements in Fq), X, Y, Z, Z2 (elements in Fq2)
   1245 Output: f (an element in GT), X', Y', Z', Z2' (elements in Fq2)
   1246 Steps:
   1247 */
   1248 static EpidStatus Tangent(FiniteField* gt, FfElement* f, FfElement* x_out,
   1249                           FfElement* y_out, FfElement* z_out, FfElement* z2_out,
   1250                           FfElement const* px, FfElement const* py,
   1251                           FfElement const* x, FfElement const* y,
   1252                           FfElement const* z, FfElement const* z2) {
   1253   EpidStatus result = kEpidErr;
   1254   FfElement* t0 = NULL;
   1255   FfElement* t1 = NULL;
   1256   FfElement* t2 = NULL;
   1257   FfElement* t3 = NULL;
   1258   FfElement* t4 = NULL;
   1259   FfElement* t5 = NULL;
   1260   FfElement* t6 = NULL;
   1261   Fq12ElemDat fDat = {0};
   1262   do {
   1263     IppStatus sts = ippStsNoErr;
   1264     IppsGFpState* Fq2 = NULL;
   1265     IppsGFpState* Fq6 = NULL;
   1266     FiniteField* Ffq2 = NULL;
   1267     FiniteField* Ffq6 = NULL;
   1268 
   1269     int i = 0;
   1270     // validate input
   1271     if (!gt || !f || !x_out || !y_out || !z_out || !z2_out || !px || !py ||
   1272         !x || !y || !z || !z2) {
   1273       result = kEpidBadArgErr;
   1274       break;
   1275     }
   1276     if (!gt->ipp_ff || !f->ipp_ff_elem || !x_out->ipp_ff_elem ||
   1277         !y_out->ipp_ff_elem || !z_out->ipp_ff_elem || !z2_out->ipp_ff_elem ||
   1278         !px->ipp_ff_elem || !py->ipp_ff_elem || !x->ipp_ff_elem ||
   1279         !y->ipp_ff_elem || !z->ipp_ff_elem || !z2->ipp_ff_elem) {
   1280       result = kEpidBadArgErr;
   1281       break;
   1282     }
   1283     // get Fq2, Fq6
   1284     Ffq6 = gt->ground_ff;
   1285     if (!Ffq6) {
   1286       result = kEpidBadArgErr;
   1287       break;
   1288     }
   1289     Fq6 = Ffq6->ipp_ff;
   1290     Ffq2 = Ffq6->ground_ff;
   1291     if (!Ffq2) {
   1292       result = kEpidBadArgErr;
   1293       break;
   1294     }
   1295     Fq2 = Ffq2->ipp_ff;
   1296     // Let t0, t1, t2, t3, t4, t5, t6 be elements in Fq2. All the following
   1297     // operations are computed in Fq2 unless explicitly specified.
   1298     // 1. Set t0 = X * X.
   1299     result = NewFfElement(Ffq2, &t0);
   1300     BREAK_ON_EPID_ERROR(result);
   1301     sts = ippsGFpMul(x->ipp_ff_elem, x->ipp_ff_elem, t0->ipp_ff_elem, Fq2);
   1302     BREAK_ON_IPP_ERROR(sts, result);
   1303     // 2. Set t1 = Y * Y.
   1304     result = NewFfElement(Ffq2, &t1);
   1305     BREAK_ON_EPID_ERROR(result);
   1306     sts = ippsGFpMul(y->ipp_ff_elem, y->ipp_ff_elem, t1->ipp_ff_elem, Fq2);
   1307     BREAK_ON_IPP_ERROR(sts, result);
   1308     // 3. Set t2 = t1 * t1.
   1309     result = NewFfElement(Ffq2, &t2);
   1310     BREAK_ON_EPID_ERROR(result);
   1311     sts = ippsGFpMul(t1->ipp_ff_elem, t1->ipp_ff_elem, t2->ipp_ff_elem, Fq2);
   1312     BREAK_ON_IPP_ERROR(sts, result);
   1313     // 4. Set t3 = (t1 + X)^2 - t0 - t2.
   1314     result = NewFfElement(Ffq2, &t3);
   1315     BREAK_ON_EPID_ERROR(result);
   1316     sts = ippsGFpAdd(t1->ipp_ff_elem, x->ipp_ff_elem, t3->ipp_ff_elem, Fq2);
   1317     BREAK_ON_IPP_ERROR(sts, result);
   1318     sts = ippsGFpMul(t3->ipp_ff_elem, t3->ipp_ff_elem, t3->ipp_ff_elem, Fq2);
   1319     BREAK_ON_IPP_ERROR(sts, result);
   1320     sts = ippsGFpSub(t3->ipp_ff_elem, t0->ipp_ff_elem, t3->ipp_ff_elem, Fq2);
   1321     BREAK_ON_IPP_ERROR(sts, result);
   1322     sts = ippsGFpSub(t3->ipp_ff_elem, t2->ipp_ff_elem, t3->ipp_ff_elem, Fq2);
   1323     BREAK_ON_IPP_ERROR(sts, result);
   1324     // 5. Set t3 = t3 + t3.
   1325     sts = ippsGFpAdd(t3->ipp_ff_elem, t3->ipp_ff_elem, t3->ipp_ff_elem, Fq2);
   1326     BREAK_ON_IPP_ERROR(sts, result);
   1327     // 6. Set t4 = 3 * t0.
   1328     result = NewFfElement(Ffq2, &t4);
   1329     BREAK_ON_EPID_ERROR(result);
   1330     sts = ippsGFpAdd(t0->ipp_ff_elem, t0->ipp_ff_elem, t4->ipp_ff_elem, Fq2);
   1331     BREAK_ON_IPP_ERROR(sts, result);
   1332     sts = ippsGFpAdd(t4->ipp_ff_elem, t0->ipp_ff_elem, t4->ipp_ff_elem, Fq2);
   1333     BREAK_ON_IPP_ERROR(sts, result);
   1334     // 7. Set t6 = X + t4.
   1335     result = NewFfElement(Ffq2, &t6);
   1336     BREAK_ON_EPID_ERROR(result);
   1337     sts = ippsGFpAdd(x->ipp_ff_elem, t4->ipp_ff_elem, t6->ipp_ff_elem, Fq2);
   1338     BREAK_ON_IPP_ERROR(sts, result);
   1339     // 8. Set t5 = t4 * t4.
   1340     result = NewFfElement(Ffq2, &t5);
   1341     BREAK_ON_EPID_ERROR(result);
   1342     sts = ippsGFpMul(t4->ipp_ff_elem, t4->ipp_ff_elem, t5->ipp_ff_elem, Fq2);
   1343     BREAK_ON_IPP_ERROR(sts, result);
   1344     // 9. Set X' = t5 - t3 - t3.
   1345     sts = ippsGFpSub(t5->ipp_ff_elem, t3->ipp_ff_elem, x_out->ipp_ff_elem, Fq2);
   1346     BREAK_ON_IPP_ERROR(sts, result);
   1347     sts = ippsGFpSub(x_out->ipp_ff_elem, t3->ipp_ff_elem, x_out->ipp_ff_elem,
   1348                      Fq2);
   1349     BREAK_ON_IPP_ERROR(sts, result);
   1350     // 10.Set Z' = (Y + Z)^2 - t1 - Z2.
   1351     sts = ippsGFpAdd(y->ipp_ff_elem, z->ipp_ff_elem, z_out->ipp_ff_elem, Fq2);
   1352     BREAK_ON_IPP_ERROR(sts, result);
   1353     sts = ippsGFpMul(z_out->ipp_ff_elem, z_out->ipp_ff_elem, z_out->ipp_ff_elem,
   1354                      Fq2);
   1355     BREAK_ON_IPP_ERROR(sts, result);
   1356     sts = ippsGFpSub(z_out->ipp_ff_elem, t1->ipp_ff_elem, z_out->ipp_ff_elem,
   1357                      Fq2);
   1358     BREAK_ON_IPP_ERROR(sts, result);
   1359     sts = ippsGFpSub(z_out->ipp_ff_elem, z2->ipp_ff_elem, z_out->ipp_ff_elem,
   1360                      Fq2);
   1361     BREAK_ON_IPP_ERROR(sts, result);
   1362     // 11.Set Y' = (t3 - X') * t4 - 8 * t2.
   1363     sts = ippsGFpSub(t3->ipp_ff_elem, x_out->ipp_ff_elem, y_out->ipp_ff_elem,
   1364                      Fq2);
   1365     BREAK_ON_IPP_ERROR(sts, result);
   1366     sts = ippsGFpMul(y_out->ipp_ff_elem, t4->ipp_ff_elem, y_out->ipp_ff_elem,
   1367                      Fq2);
   1368     BREAK_ON_IPP_ERROR(sts, result);
   1369     for (i = 0; i < 8; i++) {
   1370       sts = ippsGFpSub(y_out->ipp_ff_elem, t2->ipp_ff_elem, y_out->ipp_ff_elem,
   1371                        Fq2);
   1372       BREAK_ON_IPP_ERROR(sts, result);
   1373     }
   1374     // 12.Set t3 = -2 * (t4 * Z2).
   1375     sts = ippsGFpMul(t4->ipp_ff_elem, z2->ipp_ff_elem, t3->ipp_ff_elem, Fq2);
   1376     BREAK_ON_IPP_ERROR(sts, result);
   1377     sts = ippsGFpAdd(t3->ipp_ff_elem, t3->ipp_ff_elem, t3->ipp_ff_elem, Fq2);
   1378     BREAK_ON_IPP_ERROR(sts, result);
   1379     sts = ippsGFpNeg(t3->ipp_ff_elem, t3->ipp_ff_elem, Fq2);
   1380     BREAK_ON_IPP_ERROR(sts, result);
   1381     // 13.Set t3 = Fq2.mul(t3, Px).
   1382     sts = ippsGFpMul_PE(t3->ipp_ff_elem, px->ipp_ff_elem, t3->ipp_ff_elem, Fq2);
   1383     BREAK_ON_IPP_ERROR(sts, result);
   1384     // 14.Set t6 = t6 * t6 - t0 - t5 - 4 * t1.
   1385     sts = ippsGFpMul(t6->ipp_ff_elem, t6->ipp_ff_elem, t6->ipp_ff_elem, Fq2);
   1386     BREAK_ON_IPP_ERROR(sts, result);
   1387     sts = ippsGFpSub(t6->ipp_ff_elem, t0->ipp_ff_elem, t6->ipp_ff_elem, Fq2);
   1388     BREAK_ON_IPP_ERROR(sts, result);
   1389     sts = ippsGFpSub(t6->ipp_ff_elem, t5->ipp_ff_elem, t6->ipp_ff_elem, Fq2);
   1390     BREAK_ON_IPP_ERROR(sts, result);
   1391     for (i = 0; i < 4; i++) {
   1392       sts = ippsGFpSub(t6->ipp_ff_elem, t1->ipp_ff_elem, t6->ipp_ff_elem, Fq2);
   1393       BREAK_ON_IPP_ERROR(sts, result);
   1394     }
   1395     // 15.Set t0 = 2 * (Z' * Z2).
   1396     sts = ippsGFpMul(z_out->ipp_ff_elem, z2->ipp_ff_elem, t0->ipp_ff_elem, Fq2);
   1397     BREAK_ON_IPP_ERROR(sts, result);
   1398     sts = ippsGFpAdd(t0->ipp_ff_elem, t0->ipp_ff_elem, t0->ipp_ff_elem, Fq2);
   1399     BREAK_ON_IPP_ERROR(sts, result);
   1400     // 16.Set t0 = Fq2.mul(t0, Py).
   1401     sts = ippsGFpMul_PE(t0->ipp_ff_elem, py->ipp_ff_elem, t0->ipp_ff_elem, Fq2);
   1402     BREAK_ON_IPP_ERROR(sts, result);
   1403     // 17.Set f = ((t0, 0, 0), (t3, t6, 0)).
   1404     sts = ippsGFpGetElement(t0->ipp_ff_elem, (BNU)&fDat.x[0].x[0],
   1405                             sizeof(fDat.x[0].x[0]) / sizeof(Ipp32u), Fq2);
   1406     BREAK_ON_IPP_ERROR(sts, result);
   1407     sts = ippsGFpGetElement(t3->ipp_ff_elem, (BNU)&fDat.x[1].x[0],
   1408                             sizeof(fDat.x[1].x[0]) / sizeof(Ipp32u), Fq2);
   1409     BREAK_ON_IPP_ERROR(sts, result);
   1410     sts = ippsGFpGetElement(t6->ipp_ff_elem, (BNU)&fDat.x[1].x[1],
   1411                             sizeof(fDat.x[1].x[1]) / sizeof(Ipp32u), Fq2);
   1412     BREAK_ON_IPP_ERROR(sts, result);
   1413     sts = ippsGFpSetElement((Ipp32u*)&fDat, sizeof(fDat) / sizeof(Ipp32u),
   1414                             f->ipp_ff_elem, gt->ipp_ff);
   1415     BREAK_ON_IPP_ERROR(sts, result);
   1416     // 18.Set Z2' = Z' * Z'.
   1417     sts = ippsGFpMul(z_out->ipp_ff_elem, z_out->ipp_ff_elem,
   1418                      z2_out->ipp_ff_elem, Fq2);
   1419     BREAK_ON_IPP_ERROR(sts, result);
   1420     // 19.Return (f, X', Y', Z', Z2').
   1421   } while (0);
   1422   EpidZeroMemory(&fDat, sizeof(fDat));
   1423   DeleteFfElement(&t6);
   1424   DeleteFfElement(&t5);
   1425   DeleteFfElement(&t4);
   1426   DeleteFfElement(&t3);
   1427   DeleteFfElement(&t2);
   1428   DeleteFfElement(&t1);
   1429   DeleteFfElement(&t0);
   1430   return result;
   1431 }
   1432 
   1433 /*
   1434 (sn...s1s0) = ternary(s)
   1435 Input: s (big integer)
   1436 Output: sn...s1s0 (ternary representation of s)
   1437 */
   1438 static EpidStatus Ternary(int* s, int* n, int max_elements, BigNum const* x) {
   1439   /*
   1440   Let xn...x1x0 be binary representation of s.
   1441   Let flag be a Boolean variable.
   1442   1. Set flag = false.
   1443   2. For i = 0, ..., n, do the following:
   1444   a. If xi = 1
   1445   i. If flag = true, set si = 0,
   1446   ii. Else
   1447   1. If xi+1 = 1, set si = -1 and set flag = true,
   1448   2. Else si = 1.
   1449   b. Else
   1450   i. If flag = true, set si = 1 and set flag = false,
   1451   ii. Else set si = 0.
   1452   3. If flag is true
   1453   a. Set n = n+1,
   1454   b. Set sn = 1.
   1455   4. Return sn...s1s0.
   1456   */
   1457   EpidStatus result = kEpidErr;
   1458 
   1459   do {
   1460     IppStatus sts = ippStsNoErr;
   1461     int flag = 0;
   1462     int i = 0;
   1463     int num_bits = 0;
   1464     IppBNU data = 0;
   1465 
   1466     // check parameters
   1467     if (!s || !n || !x || !x->ipp_bn) {
   1468       result = kEpidBadArgErr;
   1469       break;
   1470     }
   1471 
   1472     sts = ippsRef_BN(0, &num_bits, &data, x->ipp_bn);
   1473     if (ippStsNoErr != sts) {
   1474       result = kEpidMathErr;
   1475       break;
   1476     }
   1477 
   1478     if (num_bits + 1 > max_elements) {
   1479       // not enough room for ternary representation
   1480       result = kEpidBadArgErr;
   1481       break;
   1482     }
   1483 
   1484     // Let xn...x1x0 be binary representation of s. Let flag be a
   1485     // Boolean variable.
   1486     *n = num_bits - 1;
   1487     // 1.  Set flag = false.
   1488     flag = 0;
   1489     // 2.  For i = 0, ..., n, do the following:
   1490     for (i = 0; i < num_bits; i++) {
   1491       if (1 == Bit(data, i)) {
   1492         // a.  If x[i] = 1
   1493         if (flag) {
   1494           // i.  If flag = true, set si = 0,
   1495           s[i] = 0;
   1496         } else {
   1497           // ii. Else
   1498           if ((i < num_bits - 2) && Bit(data, i + 1)) {
   1499             // 1.  If  x[i+1] = 1, set s[i] = -1 and set flag = true,
   1500             s[i] = -1;
   1501             flag = 1;
   1502           } else {
   1503             // 2.  Else s[i] = 1.
   1504             s[i] = 1;
   1505           }
   1506         }
   1507       } else {
   1508         // b.  Else
   1509         if (flag) {
   1510           // i.  If flag = true, set s[i] = 1 and set flag = false,
   1511           s[i] = 1;
   1512           flag = 0;
   1513         } else {
   1514           // ii. Else set s[i] = 0.
   1515           s[i] = 0;
   1516         }
   1517       }
   1518     }
   1519     // 3.  If flag is true
   1520     if (flag) {
   1521       // a.  Set n = n+1,
   1522       *n = *n + 1;
   1523       // b.  Set s[n] = 1.
   1524       s[*n] = 1;
   1525     }
   1526     // 4.  Return sn...s1s0.
   1527     result = kEpidNoErr;
   1528   } while (0);
   1529 
   1530   return (result);
   1531 }
   1532 
   1533 static int Bit(Ipp32u const* num, Ipp32u bit_index) {
   1534   return 0 != (num[bit_index >> 5] & (1 << (bit_index & 0x1F)));
   1535 }
   1536 
   1537 /*
   1538 e = Fq2.mulXi(a)
   1539 Input: a (an element in Fq2)
   1540 Output: e (an element in Fq2) where e = a * xi
   1541 
   1542 \note THIS IMPLEMENTATION ASSUMES xi[0] = 2, xi[1] = 1, beta = -1
   1543 
   1544 \note only should work with Fq2
   1545 
   1546 */
   1547 static EpidStatus MulXiFast(FfElement* e, FfElement const* a,
   1548                             PairingState* ps) {
   1549   EpidStatus retvalue = kEpidNotImpl;
   1550   FfElement* a0 = NULL;
   1551   FfElement* a1 = NULL;
   1552   FfElement* e0 = NULL;
   1553   FfElement* e1 = NULL;
   1554   Fq2ElemDat a_dat = {0};
   1555   Fq2ElemDat e_dat = {0};
   1556 
   1557   do {
   1558     IppStatus sts = ippStsNoErr;
   1559     // check parameters
   1560     if (!e || !a || !ps) {
   1561       retvalue = kEpidBadArgErr;
   1562       BREAK_ON_EPID_ERROR(retvalue);
   1563     }
   1564     if (!ps->Fq || !ps->Fq2) {
   1565       retvalue = kEpidBadArgErr;
   1566       BREAK_ON_EPID_ERROR(retvalue);
   1567     }
   1568     if (!e->ipp_ff_elem || !a->ipp_ff_elem || !ps->Fq->ipp_ff ||
   1569         !ps->Fq2->ipp_ff) {
   1570       retvalue = kEpidBadArgErr;
   1571       BREAK_ON_EPID_ERROR(retvalue);
   1572     }
   1573     // All the following arithmetic operations are in ps->Fq.
   1574     // 1. Let a = (a[0], a[1]), xi = (xi[0], xi[1]), and e = (e[0], e[1]).
   1575     retvalue = NewFfElement(ps->Fq, &a0);
   1576     BREAK_ON_EPID_ERROR(retvalue);
   1577     retvalue = NewFfElement(ps->Fq, &a1);
   1578     BREAK_ON_EPID_ERROR(retvalue);
   1579     retvalue = NewFfElement(ps->Fq, &e0);
   1580     BREAK_ON_EPID_ERROR(retvalue);
   1581     retvalue = NewFfElement(ps->Fq, &e1);
   1582     BREAK_ON_EPID_ERROR(retvalue);
   1583 
   1584     sts = ippsGFpGetElement(a->ipp_ff_elem, (BNU)&a_dat,
   1585                             sizeof(a_dat) / sizeof(Ipp32u), ps->Fq2->ipp_ff);
   1586     BREAK_ON_IPP_ERROR(sts, retvalue);
   1587     sts = ippsGFpSetElement((Ipp32u*)&a_dat.x[0],
   1588                             sizeof(a_dat.x[0]) / sizeof(Ipp32u),
   1589                             a0->ipp_ff_elem, ps->Fq->ipp_ff);
   1590     BREAK_ON_IPP_ERROR(sts, retvalue);
   1591     sts = ippsGFpSetElement((Ipp32u*)&a_dat.x[1],
   1592                             sizeof(a_dat.x[1]) / sizeof(Ipp32u),
   1593                             a1->ipp_ff_elem, ps->Fq->ipp_ff);
   1594     BREAK_ON_IPP_ERROR(sts, retvalue);
   1595 
   1596     // 4. If xi[0] = 2, xi[1] = 1, beta = -1, then e[0] and e[1] can
   1597     //    be computed as
   1598     //   a. e[0] = a[0] + a[0] - a[1].
   1599     sts = ippsGFpAdd(a0->ipp_ff_elem, a0->ipp_ff_elem, e0->ipp_ff_elem,
   1600                      ps->Fq->ipp_ff);
   1601     BREAK_ON_IPP_ERROR(sts, retvalue);
   1602     sts = ippsGFpSub(e0->ipp_ff_elem, a1->ipp_ff_elem, e0->ipp_ff_elem,
   1603                      ps->Fq->ipp_ff);
   1604     BREAK_ON_IPP_ERROR(sts, retvalue);
   1605     //   b. e[1] = a[0] + a[1] + a[1].
   1606     sts = ippsGFpAdd(a0->ipp_ff_elem, a1->ipp_ff_elem, e1->ipp_ff_elem,
   1607                      ps->Fq->ipp_ff);
   1608     BREAK_ON_IPP_ERROR(sts, retvalue);
   1609     sts = ippsGFpAdd(e1->ipp_ff_elem, a1->ipp_ff_elem, e1->ipp_ff_elem,
   1610                      ps->Fq->ipp_ff);
   1611     BREAK_ON_IPP_ERROR(sts, retvalue);
   1612     // 5. Return e = (e[0], e[1]).
   1613     sts =
   1614         ippsGFpGetElement(e0->ipp_ff_elem, (BNU)&e_dat.x[0],
   1615                           sizeof(e_dat.x[0]) / sizeof(Ipp32u), ps->Fq->ipp_ff);
   1616     BREAK_ON_IPP_ERROR(sts, retvalue);
   1617     sts =
   1618         ippsGFpGetElement(e1->ipp_ff_elem, (BNU)&e_dat.x[1],
   1619                           sizeof(e_dat.x[1]) / sizeof(Ipp32u), ps->Fq->ipp_ff);
   1620     BREAK_ON_IPP_ERROR(sts, retvalue);
   1621     sts = ippsGFpSetElement((Ipp32u*)&e_dat, sizeof(e_dat) / sizeof(Ipp32u),
   1622                             e->ipp_ff_elem, ps->Fq2->ipp_ff);
   1623     BREAK_ON_IPP_ERROR(sts, retvalue);
   1624     retvalue = kEpidNoErr;
   1625   } while (0);
   1626 
   1627   EpidZeroMemory(&a_dat, sizeof(a_dat));
   1628   EpidZeroMemory(&e_dat, sizeof(e_dat));
   1629   DeleteFfElement(&a0);
   1630   DeleteFfElement(&a1);
   1631   DeleteFfElement(&e0);
   1632   DeleteFfElement(&e1);
   1633 
   1634   return (retvalue);
   1635 }
   1636 
   1637 /*
   1638 e = Fq6.MulV(a)
   1639 Input: a (element in Fq6)
   1640 Output: e (an element in Fq6) where e = a * V, where V = 0 * v2 + 1 * v + 0
   1641 
   1642 \note only should work with Fq6
   1643 */
   1644 static EpidStatus MulV(FfElement* e, FfElement* a, PairingState* ps) {
   1645   EpidStatus retvalue = kEpidNotImpl;
   1646   FfElement* a2 = NULL;
   1647   FfElement* e0 = NULL;
   1648   FfElement* e1 = NULL;
   1649   FfElement* e2 = NULL;
   1650   Fq6ElemDat a_dat = {0};
   1651   Fq6ElemDat e_dat = {0};
   1652   do {
   1653     IppStatus sts = ippStsNoErr;
   1654     // check parameters
   1655     if (!e || !a || !ps) {
   1656       retvalue = kEpidBadArgErr;
   1657       BREAK_ON_EPID_ERROR(retvalue);
   1658     }
   1659     if (!ps->Fq2 || !ps->Fq6) {
   1660       retvalue = kEpidBadArgErr;
   1661       BREAK_ON_EPID_ERROR(retvalue);
   1662     }
   1663     if (!e->ipp_ff_elem || !a->ipp_ff_elem || !ps->Fq2->ipp_ff ||
   1664         !ps->Fq6->ipp_ff) {
   1665       retvalue = kEpidBadArgErr;
   1666       BREAK_ON_EPID_ERROR(retvalue);
   1667     }
   1668     // 1. Let a = (a[0], a[1], a[2]) and e = (e[0], e[1], e[2]).
   1669     retvalue = NewFfElement(ps->Fq2, &a2);
   1670     BREAK_ON_EPID_ERROR(retvalue);
   1671     retvalue = NewFfElement(ps->Fq2, &e0);
   1672     BREAK_ON_EPID_ERROR(retvalue);
   1673     retvalue = NewFfElement(ps->Fq2, &e1);
   1674     BREAK_ON_EPID_ERROR(retvalue);
   1675     retvalue = NewFfElement(ps->Fq2, &e2);
   1676     BREAK_ON_EPID_ERROR(retvalue);
   1677 
   1678     sts = ippsGFpGetElement(a->ipp_ff_elem, (BNU)&a_dat,
   1679                             sizeof(a_dat) / sizeof(Ipp32u), ps->Fq6->ipp_ff);
   1680     BREAK_ON_IPP_ERROR(sts, retvalue);
   1681     sts = ippsGFpSetElement((Ipp32u*)&a_dat.x[2],
   1682                             sizeof(a_dat.x[2]) / sizeof(Ipp32u),
   1683                             a2->ipp_ff_elem, ps->Fq2->ipp_ff);
   1684     BREAK_ON_IPP_ERROR(sts, retvalue);
   1685     // 2. e[0] = Fq2.mulXi(a[2]).
   1686     retvalue = MulXiFast(e0, a2, ps);
   1687     BREAK_ON_EPID_ERROR(retvalue);
   1688     // 3. e[1] = a[0].
   1689     e_dat.x[1] = a_dat.x[0];
   1690     // 4. e[2] = a[1].
   1691     e_dat.x[2] = a_dat.x[1];
   1692 
   1693     sts =
   1694         ippsGFpGetElement(e0->ipp_ff_elem, (BNU)&e_dat.x[0],
   1695                           sizeof(e_dat.x[0]) / sizeof(Ipp32u), ps->Fq2->ipp_ff);
   1696     BREAK_ON_IPP_ERROR(sts, retvalue);
   1697     sts = ippsGFpSetElement((Ipp32u*)&e_dat, sizeof(e_dat) / sizeof(Ipp32u),
   1698                             e->ipp_ff_elem, ps->Fq6->ipp_ff);
   1699     BREAK_ON_IPP_ERROR(sts, retvalue);
   1700     retvalue = kEpidNoErr;
   1701   } while (0);
   1702 
   1703   EpidZeroMemory(&a_dat, sizeof(a_dat));
   1704   EpidZeroMemory(&e_dat, sizeof(e_dat));
   1705   DeleteFfElement(&a2);
   1706   DeleteFfElement(&e0);
   1707   DeleteFfElement(&e1);
   1708   DeleteFfElement(&e2);
   1709 
   1710   return (retvalue);
   1711 }
   1712 
   1713 /*
   1714 helper for MulSpecial, special args form of Fq6Mul
   1715 
   1716 special args form of Fq6.mul(a,b[0],b[1])
   1717 Input: a (elements in Fq6), b[0], b[1] (elements in Fq2)
   1718 Output: e (an element in Fq6) where e = a * b, and b = b[1] * v + b[0]
   1719 
   1720 \note assumes a,e are Fq6 elements and b0,b1 are fq2 elements
   1721 */
   1722 static EpidStatus Fq6MulGFpE2(FfElement* e, FfElement* a, FfElement* b0,
   1723                               FfElement* b1, PairingState* ps) {
   1724   EpidStatus retvalue = kEpidNotImpl;
   1725   FfElement* t0 = NULL;
   1726   FfElement* t1 = NULL;
   1727   FfElement* t2 = NULL;
   1728   FfElement* t3 = NULL;
   1729   FfElement* t4 = NULL;
   1730   FfElement* a0 = NULL;
   1731   FfElement* a1 = NULL;
   1732   FfElement* a2 = NULL;
   1733   FfElement* e0 = NULL;
   1734   FfElement* e1 = NULL;
   1735   FfElement* e2 = NULL;
   1736   Fq6ElemDat a_dat = {0};
   1737   Fq6ElemDat e_dat = {0};
   1738   do {
   1739     IppStatus sts = ippStsNoErr;
   1740     // check parameters
   1741     if (!e || !a || !b0 || !b1 || !ps) {
   1742       retvalue = kEpidBadArgErr;
   1743       BREAK_ON_EPID_ERROR(retvalue);
   1744     }
   1745     if (!ps->Fq2 || !ps->Fq6) {
   1746       retvalue = kEpidBadArgErr;
   1747       BREAK_ON_EPID_ERROR(retvalue);
   1748     }
   1749     if (!e->ipp_ff_elem || !a->ipp_ff_elem || !b0->ipp_ff_elem ||
   1750         !b1->ipp_ff_elem || !ps->Fq2->ipp_ff || !ps->Fq6->ipp_ff) {
   1751       retvalue = kEpidBadArgErr;
   1752       BREAK_ON_EPID_ERROR(retvalue);
   1753     }
   1754 
   1755     // Let t0, t1, t3, t4 be temporary variables in Fq2. All the
   1756     // following arithmetic operations are in Fq2.
   1757     retvalue = NewFfElement(ps->Fq2, &t0);
   1758     BREAK_ON_EPID_ERROR(retvalue);
   1759     retvalue = NewFfElement(ps->Fq2, &t1);
   1760     BREAK_ON_EPID_ERROR(retvalue);
   1761     retvalue = NewFfElement(ps->Fq2, &t2);
   1762     BREAK_ON_EPID_ERROR(retvalue);
   1763     retvalue = NewFfElement(ps->Fq2, &t3);
   1764     BREAK_ON_EPID_ERROR(retvalue);
   1765     retvalue = NewFfElement(ps->Fq2, &t4);
   1766     BREAK_ON_EPID_ERROR(retvalue);
   1767     // 1. Let a = (a[0], a[1], a[2]) and e = (e[0], e[1], e[2]).
   1768     retvalue = NewFfElement(ps->Fq2, &a0);
   1769     BREAK_ON_EPID_ERROR(retvalue);
   1770     retvalue = NewFfElement(ps->Fq2, &a1);
   1771     BREAK_ON_EPID_ERROR(retvalue);
   1772     retvalue = NewFfElement(ps->Fq2, &a2);
   1773     BREAK_ON_EPID_ERROR(retvalue);
   1774     retvalue = NewFfElement(ps->Fq2, &e0);
   1775     BREAK_ON_EPID_ERROR(retvalue);
   1776     retvalue = NewFfElement(ps->Fq2, &e1);
   1777     BREAK_ON_EPID_ERROR(retvalue);
   1778     retvalue = NewFfElement(ps->Fq2, &e2);
   1779     BREAK_ON_EPID_ERROR(retvalue);
   1780 
   1781     sts = ippsGFpGetElement(a->ipp_ff_elem, (BNU)&a_dat,
   1782                             sizeof(a_dat) / sizeof(Ipp32u), ps->Fq6->ipp_ff);
   1783     BREAK_ON_IPP_ERROR(sts, retvalue);
   1784     sts = ippsGFpSetElement((Ipp32u*)&a_dat.x[0],
   1785                             sizeof(a_dat.x[0]) / sizeof(Ipp32u),
   1786                             a0->ipp_ff_elem, ps->Fq2->ipp_ff);
   1787     BREAK_ON_IPP_ERROR(sts, retvalue);
   1788     sts = ippsGFpSetElement((Ipp32u*)&a_dat.x[1],
   1789                             sizeof(a_dat.x[1]) / sizeof(Ipp32u),
   1790                             a1->ipp_ff_elem, ps->Fq2->ipp_ff);
   1791     BREAK_ON_IPP_ERROR(sts, retvalue);
   1792     sts = ippsGFpSetElement((Ipp32u*)&a_dat.x[2],
   1793                             sizeof(a_dat.x[2]) / sizeof(Ipp32u),
   1794                             a2->ipp_ff_elem, ps->Fq2->ipp_ff);
   1795     BREAK_ON_IPP_ERROR(sts, retvalue);
   1796     // 2. t0 = a[0] * b[0].
   1797     sts = ippsGFpMul(a0->ipp_ff_elem, b0->ipp_ff_elem, t0->ipp_ff_elem,
   1798                      ps->Fq2->ipp_ff);
   1799     BREAK_ON_IPP_ERROR(sts, retvalue);
   1800     // 3. t1 = a[1] * b[1].
   1801     sts = ippsGFpMul(a1->ipp_ff_elem, b1->ipp_ff_elem, t1->ipp_ff_elem,
   1802                      ps->Fq2->ipp_ff);
   1803     BREAK_ON_IPP_ERROR(sts, retvalue);
   1804     // 4. t3 = a[1] + a[2].
   1805     sts = ippsGFpAdd(a1->ipp_ff_elem, a2->ipp_ff_elem, t3->ipp_ff_elem,
   1806                      ps->Fq2->ipp_ff);
   1807     BREAK_ON_IPP_ERROR(sts, retvalue);
   1808     // 5. t3 = t3 * b[1].
   1809     sts = ippsGFpMul(t3->ipp_ff_elem, b1->ipp_ff_elem, t3->ipp_ff_elem,
   1810                      ps->Fq2->ipp_ff);
   1811     BREAK_ON_IPP_ERROR(sts, retvalue);
   1812     // 6. t3 = t3 - t1.
   1813     sts = ippsGFpSub(t3->ipp_ff_elem, t1->ipp_ff_elem, t3->ipp_ff_elem,
   1814                      ps->Fq2->ipp_ff);
   1815     BREAK_ON_IPP_ERROR(sts, retvalue);
   1816     // 7. e[0] = Fq2.mulXi(t3) + t0.
   1817     retvalue = MulXiFast(e0, t3, ps);
   1818     BREAK_ON_EPID_ERROR(retvalue);
   1819     sts = ippsGFpAdd(e0->ipp_ff_elem, t0->ipp_ff_elem, e0->ipp_ff_elem,
   1820                      ps->Fq2->ipp_ff);
   1821     BREAK_ON_IPP_ERROR(sts, retvalue);
   1822     // 8. t3 = a[0] + a[1].
   1823     sts = ippsGFpAdd(a0->ipp_ff_elem, a1->ipp_ff_elem, t3->ipp_ff_elem,
   1824                      ps->Fq2->ipp_ff);
   1825     BREAK_ON_IPP_ERROR(sts, retvalue);
   1826     // 9. t4 = b[0] + b[1].
   1827     sts = ippsGFpAdd(b0->ipp_ff_elem, b1->ipp_ff_elem, t4->ipp_ff_elem,
   1828                      ps->Fq2->ipp_ff);
   1829     BREAK_ON_IPP_ERROR(sts, retvalue);
   1830     // 10. t3 = t3 * t4.
   1831     sts = ippsGFpMul(t3->ipp_ff_elem, t4->ipp_ff_elem, t3->ipp_ff_elem,
   1832                      ps->Fq2->ipp_ff);
   1833     BREAK_ON_IPP_ERROR(sts, retvalue);
   1834     // 11. e[1] = t3 - t0 - t1.
   1835     sts = ippsGFpSub(t3->ipp_ff_elem, t0->ipp_ff_elem, e1->ipp_ff_elem,
   1836                      ps->Fq2->ipp_ff);
   1837     BREAK_ON_IPP_ERROR(sts, retvalue);
   1838     sts = ippsGFpSub(e1->ipp_ff_elem, t1->ipp_ff_elem, e1->ipp_ff_elem,
   1839                      ps->Fq2->ipp_ff);
   1840     BREAK_ON_IPP_ERROR(sts, retvalue);
   1841     // 12. t3 = a[2] * b[0].
   1842     sts = ippsGFpMul(a2->ipp_ff_elem, b0->ipp_ff_elem, t3->ipp_ff_elem,
   1843                      ps->Fq2->ipp_ff);
   1844     BREAK_ON_IPP_ERROR(sts, retvalue);
   1845     // 13. e[2] = t3 + t1.
   1846     sts = ippsGFpAdd(t3->ipp_ff_elem, t1->ipp_ff_elem, e2->ipp_ff_elem,
   1847                      ps->Fq2->ipp_ff);
   1848     BREAK_ON_IPP_ERROR(sts, retvalue);
   1849     // 14. Return e.
   1850     sts =
   1851         ippsGFpGetElement(e0->ipp_ff_elem, (BNU)&e_dat.x[0],
   1852                           sizeof(e_dat.x[0]) / sizeof(Ipp32u), ps->Fq2->ipp_ff);
   1853     BREAK_ON_IPP_ERROR(sts, retvalue);
   1854     sts =
   1855         ippsGFpGetElement(e1->ipp_ff_elem, (BNU)&e_dat.x[1],
   1856                           sizeof(e_dat.x[1]) / sizeof(Ipp32u), ps->Fq2->ipp_ff);
   1857     BREAK_ON_IPP_ERROR(sts, retvalue);
   1858     sts =
   1859         ippsGFpGetElement(e2->ipp_ff_elem, (BNU)&e_dat.x[2],
   1860                           sizeof(e_dat.x[2]) / sizeof(Ipp32u), ps->Fq2->ipp_ff);
   1861     BREAK_ON_IPP_ERROR(sts, retvalue);
   1862     sts = ippsGFpSetElement((Ipp32u*)&e_dat, sizeof(e_dat) / sizeof(Ipp32u),
   1863                             e->ipp_ff_elem, ps->Fq6->ipp_ff);
   1864     BREAK_ON_IPP_ERROR(sts, retvalue);
   1865     retvalue = kEpidNoErr;
   1866   } while (0);
   1867 
   1868   EpidZeroMemory(&a_dat, sizeof(a_dat));
   1869   EpidZeroMemory(&e_dat, sizeof(e_dat));
   1870   DeleteFfElement(&t0);
   1871   DeleteFfElement(&t1);
   1872   DeleteFfElement(&t2);
   1873   DeleteFfElement(&t3);
   1874   DeleteFfElement(&t4);
   1875   DeleteFfElement(&a0);
   1876   DeleteFfElement(&a1);
   1877   DeleteFfElement(&a2);
   1878   DeleteFfElement(&e0);
   1879   DeleteFfElement(&e1);
   1880   DeleteFfElement(&e2);
   1881 
   1882   return (retvalue);
   1883 }
   1884 
   1885 /*
   1886 e = Fq12.MulSpecial(a, b)
   1887 Input: a, b (elements in Fq12) where b = ((b[0], b[2], b[4]), (b[1], b[3],
   1888 b[5])) and b[2] = b[4] = b[5] = 0
   1889 Output: e (an element in Fq12) where e = a * b
   1890 */
   1891 static EpidStatus MulSpecial(FfElement* e, FfElement const* a,
   1892                              FfElement const* b, PairingState* ps) {
   1893   EpidStatus retvalue = kEpidNotImpl;
   1894   FfElement* t0 = NULL;
   1895   FfElement* t1 = NULL;
   1896   FfElement* t2 = NULL;
   1897   FfElement* a0 = NULL;
   1898   FfElement* a1 = NULL;
   1899   FfElement* b0 = NULL;
   1900   FfElement* b1 = NULL;
   1901   FfElement* b3 = NULL;
   1902   FfElement* e0 = NULL;
   1903   FfElement* e1 = NULL;
   1904   FfElement* b0plusb1 = NULL;
   1905   Fq12ElemDat a_dat = {0};
   1906   Fq12ElemDat b_dat = {0};
   1907   Fq12ElemDat e_dat = {0};
   1908   do {
   1909     IppStatus sts = ippStsNoErr;
   1910 
   1911     // check parameters
   1912     if (!e || !a || !b || !ps) {
   1913       retvalue = kEpidBadArgErr;
   1914       BREAK_ON_EPID_ERROR(retvalue);
   1915     }
   1916     if (!ps->Fq2 || !ps->Fq6) {
   1917       retvalue = kEpidBadArgErr;
   1918       BREAK_ON_EPID_ERROR(retvalue);
   1919     }
   1920     if (!e->ipp_ff_elem || !a->ipp_ff_elem || !b->ipp_ff_elem ||
   1921         !ps->Fq2->ipp_ff || !ps->Fq6->ipp_ff || !ps->ff || !ps->ff->ipp_ff) {
   1922       retvalue = kEpidBadArgErr;
   1923       BREAK_ON_EPID_ERROR(retvalue);
   1924     }
   1925 
   1926     // Let t0, t1, t2 be temporary variables in ps->Fq6.
   1927     retvalue = NewFfElement(ps->Fq6, &t0);
   1928     BREAK_ON_EPID_ERROR(retvalue);
   1929     retvalue = NewFfElement(ps->Fq6, &t1);
   1930     BREAK_ON_EPID_ERROR(retvalue);
   1931     retvalue = NewFfElement(ps->Fq6, &t2);
   1932     BREAK_ON_EPID_ERROR(retvalue);
   1933     retvalue = NewFfElement(ps->Fq2, &b0plusb1);
   1934     BREAK_ON_EPID_ERROR(retvalue);
   1935 
   1936     // 1.  Let a = (a[0], a[1]) and e = (e[0], e[1]).
   1937     retvalue = NewFfElement(ps->Fq6, &a0);
   1938     BREAK_ON_EPID_ERROR(retvalue);
   1939     retvalue = NewFfElement(ps->Fq6, &a1);
   1940     BREAK_ON_EPID_ERROR(retvalue);
   1941     retvalue = NewFfElement(ps->Fq6, &e0);
   1942     BREAK_ON_EPID_ERROR(retvalue);
   1943     retvalue = NewFfElement(ps->Fq6, &e1);
   1944     BREAK_ON_EPID_ERROR(retvalue);
   1945 
   1946     sts = ippsGFpGetElement(a->ipp_ff_elem, (BNU)&a_dat,
   1947                             sizeof(a_dat) / sizeof(Ipp32u), ps->ff->ipp_ff);
   1948     BREAK_ON_IPP_ERROR(sts, retvalue);
   1949     sts = ippsGFpSetElement((Ipp32u*)&a_dat.x[0],
   1950                             sizeof(a_dat.x[0]) / sizeof(Ipp32u),
   1951                             a0->ipp_ff_elem, ps->Fq6->ipp_ff);
   1952     BREAK_ON_IPP_ERROR(sts, retvalue);
   1953     sts = ippsGFpSetElement((Ipp32u*)&a_dat.x[1],
   1954                             sizeof(a_dat.x[1]) / sizeof(Ipp32u),
   1955                             a1->ipp_ff_elem, ps->Fq6->ipp_ff);
   1956     BREAK_ON_IPP_ERROR(sts, retvalue);
   1957 
   1958     // 2.  Let b = ((b[0], b[2], b[4]), (b[1], b[3], b[5])) where
   1959     //     b[0], ..., b[5] are elements in ps->Fq2 and b[2] = b[4] = b[5]
   1960     //     = 0.
   1961     retvalue = NewFfElement(ps->Fq2, &b0);
   1962     BREAK_ON_EPID_ERROR(retvalue);
   1963     retvalue = NewFfElement(ps->Fq2, &b1);
   1964     BREAK_ON_EPID_ERROR(retvalue);
   1965     retvalue = NewFfElement(ps->Fq2, &b3);
   1966     BREAK_ON_EPID_ERROR(retvalue);
   1967 
   1968     sts = ippsGFpGetElement(b->ipp_ff_elem, (BNU)&b_dat,
   1969                             sizeof(b_dat) / sizeof(Ipp32u), ps->ff->ipp_ff);
   1970     BREAK_ON_IPP_ERROR(sts, retvalue);
   1971     sts = ippsGFpSetElement((Ipp32u*)&b_dat.x[0].x[0],
   1972                             sizeof(a_dat.x[0].x[0]) / sizeof(Ipp32u),
   1973                             b0->ipp_ff_elem, ps->Fq2->ipp_ff);
   1974     BREAK_ON_IPP_ERROR(sts, retvalue);
   1975     sts = ippsGFpSetElement((Ipp32u*)&b_dat.x[1].x[0],
   1976                             sizeof(a_dat.x[1].x[0]) / sizeof(Ipp32u),
   1977                             b1->ipp_ff_elem, ps->Fq2->ipp_ff);
   1978     BREAK_ON_IPP_ERROR(sts, retvalue);
   1979     sts = ippsGFpSetElement((Ipp32u*)&b_dat.x[1].x[1],
   1980                             sizeof(a_dat.x[1].x[1]) / sizeof(Ipp32u),
   1981                             b3->ipp_ff_elem, ps->Fq2->ipp_ff);
   1982     BREAK_ON_IPP_ERROR(sts, retvalue);
   1983 
   1984     // 3.  t0 = ps->Fq6.mul(a[0], b[0]).
   1985 
   1986     sts = ippsGFpMul_PE(a0->ipp_ff_elem, b0->ipp_ff_elem, t0->ipp_ff_elem,
   1987                         ps->Fq6->ipp_ff);
   1988     BREAK_ON_IPP_ERROR(sts, retvalue);
   1989     // 4.  t1 = ps->Fq6.mul(a[1], b[1], b[3]).
   1990     retvalue = Fq6MulGFpE2(t1, a1, b1, b3, ps);
   1991     BREAK_ON_EPID_ERROR(retvalue);
   1992     // 5.  e[0] = ps->Fq6.MulV(t1).
   1993     retvalue = MulV(e0, t1, ps);
   1994     BREAK_ON_EPID_ERROR(retvalue);
   1995     // 6.  e[0] = ps->Fq6.add(t0, e[0]).
   1996     sts = ippsGFpAdd(t0->ipp_ff_elem, e0->ipp_ff_elem, e0->ipp_ff_elem,
   1997                      ps->Fq6->ipp_ff);
   1998     BREAK_ON_IPP_ERROR(sts, retvalue);
   1999     // 7.  t2 = ps->Fq6.add(a[0], a[1]).
   2000     sts = ippsGFpAdd(a0->ipp_ff_elem, a1->ipp_ff_elem, t2->ipp_ff_elem,
   2001                      ps->Fq6->ipp_ff);
   2002     BREAK_ON_IPP_ERROR(sts, retvalue);
   2003     // 8.  e[1] = ps->Fq6.mul(t2, b[0] + b[1], b[3]).
   2004     sts = ippsGFpAdd(b0->ipp_ff_elem, b1->ipp_ff_elem, b0plusb1->ipp_ff_elem,
   2005                      ps->Fq2->ipp_ff);
   2006     BREAK_ON_IPP_ERROR(sts, retvalue);
   2007     retvalue = Fq6MulGFpE2(e1, t2, b0plusb1, b3, ps);
   2008     BREAK_ON_EPID_ERROR(retvalue);
   2009     // 9.  e[1] = ps->Fq6.subtract(e[1], t0).
   2010     sts = ippsGFpSub(e1->ipp_ff_elem, t0->ipp_ff_elem, e1->ipp_ff_elem,
   2011                      ps->Fq6->ipp_ff);
   2012     BREAK_ON_IPP_ERROR(sts, retvalue);
   2013     // 10. e[1] = ps->Fq6.subtract(e[1], t1).
   2014     sts = ippsGFpSub(e1->ipp_ff_elem, t1->ipp_ff_elem, e1->ipp_ff_elem,
   2015                      ps->Fq6->ipp_ff);
   2016     BREAK_ON_IPP_ERROR(sts, retvalue);
   2017     // 11. Return e.
   2018     sts =
   2019         ippsGFpGetElement(e0->ipp_ff_elem, (BNU)&e_dat.x[0],
   2020                           sizeof(e_dat.x[0]) / sizeof(Ipp32u), ps->Fq6->ipp_ff);
   2021     BREAK_ON_IPP_ERROR(sts, retvalue);
   2022     sts =
   2023         ippsGFpGetElement(e1->ipp_ff_elem, (BNU)&e_dat.x[1],
   2024                           sizeof(e_dat.x[1]) / sizeof(Ipp32u), ps->Fq6->ipp_ff);
   2025     BREAK_ON_IPP_ERROR(sts, retvalue);
   2026     sts = ippsGFpSetElement((Ipp32u*)&e_dat, sizeof(e_dat) / sizeof(Ipp32u),
   2027                             e->ipp_ff_elem, ps->ff->ipp_ff);
   2028     BREAK_ON_IPP_ERROR(sts, retvalue);
   2029     retvalue = kEpidNoErr;
   2030   } while (0);
   2031   EpidZeroMemory(&a_dat, sizeof(a_dat));
   2032   EpidZeroMemory(&b_dat, sizeof(b_dat));
   2033   EpidZeroMemory(&e_dat, sizeof(e_dat));
   2034   DeleteFfElement(&t0);
   2035   DeleteFfElement(&t1);
   2036   DeleteFfElement(&t2);
   2037   DeleteFfElement(&a0);
   2038   DeleteFfElement(&a1);
   2039   DeleteFfElement(&b0);
   2040   DeleteFfElement(&b1);
   2041   DeleteFfElement(&b3);
   2042   DeleteFfElement(&e0);
   2043   DeleteFfElement(&e1);
   2044   DeleteFfElement(&b0plusb1);
   2045 
   2046   return (retvalue);
   2047 }
   2048 
   2049 /*
   2050   (e0, e1) = Fq12.SquareForFq4(a0, a1)
   2051   Input: a0, a1 (elements in Fq2)
   2052   Output: e0, e1 (elements in Fq2) where e = a * a in Fq4
   2053 */
   2054 static EpidStatus SquareForFq4(PairingState* ps, FfElement* e0, FfElement* e1,
   2055                                FfElement const* a0, FfElement const* a1) {
   2056   EpidStatus result = kEpidErr;
   2057   FfElement* t0 = NULL;
   2058   FfElement* t1 = NULL;
   2059   FfElement* xi = NULL;
   2060   Fq2ElemStr Fq6IrrPolynomial = {0};
   2061 
   2062   // check parameters
   2063   if (!e0 || !e1 || !a0 || !a1 || !ps) return kEpidBadArgErr;
   2064   if (!ps->Fq2 || !ps->Fq6) {
   2065     return kEpidBadArgErr;
   2066   }
   2067   if (!e0->ipp_ff_elem || !e1->ipp_ff_elem || !a0->ipp_ff_elem ||
   2068       !a1->ipp_ff_elem || !ps->ff || !ps->ff->ipp_ff || !ps->Fq2->ipp_ff ||
   2069       !ps->Fq6->ipp_ff)
   2070     return kEpidBadArgErr;
   2071 
   2072   do {
   2073     IppStatus sts = ippStsNoErr;
   2074 
   2075     // extract xi from Fq6 irr poly
   2076     result = NewFfElement(ps->Fq2, &xi);
   2077     BREAK_ON_EPID_ERROR(result);
   2078     result = WriteBigNum(ps->Fq6->modulus_0, sizeof(Fq6IrrPolynomial),
   2079                          &Fq6IrrPolynomial);
   2080     BREAK_ON_EPID_ERROR(result);
   2081     result = SetFfElementOctString(&Fq6IrrPolynomial, sizeof(Fq6IrrPolynomial),
   2082                                    xi, ps->Fq2);
   2083     BREAK_ON_EPID_ERROR(result);
   2084     // first coefficent is -xi
   2085     sts = ippsGFpNeg(xi->ipp_ff_elem, xi->ipp_ff_elem, ps->Fq2->ipp_ff);
   2086     BREAK_ON_IPP_ERROR(sts, result);
   2087 
   2088     // Let t0, t1 be temporary variables in Fq2. All the following
   2089     // operations are computed in Fq2.
   2090     result = NewFfElement(ps->Fq2, &t0);
   2091     BREAK_ON_EPID_ERROR(result);
   2092     result = NewFfElement(ps->Fq2, &t1);
   2093     BREAK_ON_EPID_ERROR(result);
   2094 
   2095     // 1. Set t0 = a0 * a0.
   2096     sts = ippsGFpMul(a0->ipp_ff_elem, a0->ipp_ff_elem, t0->ipp_ff_elem,
   2097                      ps->Fq2->ipp_ff);
   2098     BREAK_ON_IPP_ERROR(sts, result);
   2099     // 2. Set t1 = a1 * a1.
   2100     sts = ippsGFpMul(a1->ipp_ff_elem, a1->ipp_ff_elem, t1->ipp_ff_elem,
   2101                      ps->Fq2->ipp_ff);
   2102     BREAK_ON_IPP_ERROR(sts, result);
   2103     // 3. Set e0 = t1 * xi.
   2104     sts = ippsGFpMul(t1->ipp_ff_elem, xi->ipp_ff_elem, e0->ipp_ff_elem,
   2105                      ps->Fq2->ipp_ff);
   2106     BREAK_ON_IPP_ERROR(sts, result);
   2107     // 4. Set e0 = e0 + t0.
   2108     sts = ippsGFpAdd(e0->ipp_ff_elem, t0->ipp_ff_elem, e0->ipp_ff_elem,
   2109                      ps->Fq2->ipp_ff);
   2110     BREAK_ON_IPP_ERROR(sts, result);
   2111     // 5. Set e1 = a0 + a1.
   2112     sts = ippsGFpAdd(a0->ipp_ff_elem, a1->ipp_ff_elem, e1->ipp_ff_elem,
   2113                      ps->Fq2->ipp_ff);
   2114     BREAK_ON_IPP_ERROR(sts, result);
   2115     // 6. Set e1 = e1 * e1 - t0 - t1.
   2116     sts = ippsGFpMul(e1->ipp_ff_elem, e1->ipp_ff_elem, e1->ipp_ff_elem,
   2117                      ps->Fq2->ipp_ff);
   2118     BREAK_ON_IPP_ERROR(sts, result);
   2119     sts = ippsGFpSub(e1->ipp_ff_elem, t0->ipp_ff_elem, e1->ipp_ff_elem,
   2120                      ps->Fq2->ipp_ff);
   2121     BREAK_ON_IPP_ERROR(sts, result);
   2122     sts = ippsGFpSub(e1->ipp_ff_elem, t1->ipp_ff_elem, e1->ipp_ff_elem,
   2123                      ps->Fq2->ipp_ff);
   2124     BREAK_ON_IPP_ERROR(sts, result);
   2125     // 7. Return (e0, e1).
   2126     result = kEpidNoErr;
   2127   } while (0);
   2128 
   2129   EpidZeroMemory(&Fq6IrrPolynomial, sizeof(Fq6IrrPolynomial));
   2130   DeleteFfElement(&t0);
   2131   DeleteFfElement(&t1);
   2132   DeleteFfElement(&xi);
   2133 
   2134   return (result);
   2135 }
   2136 
   2137 /*
   2138   e = Fq12.squareCyclotomic(a)
   2139   Input: a (an element in Fq12)
   2140   Output: e (an element in Fq12) where e = a * a
   2141 */
   2142 static EpidStatus SquareCyclotomic(PairingState* ps, FfElement* e_out,
   2143                                    FfElement const* a_in) {
   2144   EpidStatus result = kEpidErr;
   2145   FfElement* t00 = NULL;
   2146   FfElement* t01 = NULL;
   2147   FfElement* t02 = NULL;
   2148   FfElement* t10 = NULL;
   2149   FfElement* t11 = NULL;
   2150   FfElement* t12 = NULL;
   2151 
   2152   FfElement* a[6] = {0};
   2153   FfElement* e[6] = {0};
   2154 
   2155   FfElement* xi = NULL;
   2156   int i = 0;
   2157   Fq12ElemStr a_str = {0};
   2158   Fq12ElemStr e_str = {0};
   2159   Fq2ElemStr Fq6IrrPolynomial = {0};
   2160 
   2161   // check parameters
   2162   if (!e_out || !a_in || !ps) return kEpidBadArgErr;
   2163   if (!ps->Fq || !ps->Fq2 || !ps->Fq6) {
   2164     return kEpidBadArgErr;
   2165   }
   2166   if (!e_out->ipp_ff_elem || !a_in->ipp_ff_elem || !ps->ff || !ps->ff->ipp_ff ||
   2167       !ps->Fq->ipp_ff || !ps->Fq2->ipp_ff || !ps->Fq6->ipp_ff)
   2168     return kEpidBadArgErr;
   2169 
   2170   do {
   2171     IppStatus sts = ippStsNoErr;
   2172 
   2173     // extract xi from Fq6 irr poly
   2174     result = NewFfElement(ps->Fq2, &xi);
   2175     BREAK_ON_EPID_ERROR(result);
   2176     result = WriteBigNum(ps->Fq6->modulus_0, sizeof(Fq6IrrPolynomial),
   2177                          &Fq6IrrPolynomial);
   2178     BREAK_ON_EPID_ERROR(result);
   2179     result = SetFfElementOctString(&Fq6IrrPolynomial, sizeof(Fq6IrrPolynomial),
   2180                                    xi, ps->Fq2);
   2181     BREAK_ON_EPID_ERROR(result);
   2182     // first coefficent is -xi
   2183     sts = ippsGFpNeg(xi->ipp_ff_elem, xi->ipp_ff_elem, ps->Fq2->ipp_ff);
   2184     BREAK_ON_IPP_ERROR(sts, result);
   2185 
   2186     // Let t00, t01, t02, t10, t11, t12 be temporary variables in
   2187     // Fq2. All the following operations are computed in Fq2 unless
   2188     // specified otherwise.
   2189     result = NewFfElement(ps->Fq2, &t00);
   2190     BREAK_ON_EPID_ERROR(result);
   2191     result = NewFfElement(ps->Fq2, &t01);
   2192     BREAK_ON_EPID_ERROR(result);
   2193     result = NewFfElement(ps->Fq2, &t02);
   2194     BREAK_ON_EPID_ERROR(result);
   2195     result = NewFfElement(ps->Fq2, &t10);
   2196     BREAK_ON_EPID_ERROR(result);
   2197     result = NewFfElement(ps->Fq2, &t11);
   2198     BREAK_ON_EPID_ERROR(result);
   2199     result = NewFfElement(ps->Fq2, &t12);
   2200     BREAK_ON_EPID_ERROR(result);
   2201     for (i = 0; i < 6; i++) {
   2202       result = NewFfElement(ps->Fq2, &a[i]);
   2203       BREAK_ON_EPID_ERROR(result);
   2204       result = NewFfElement(ps->Fq2, &e[i]);
   2205       BREAK_ON_EPID_ERROR(result);
   2206     }
   2207     BREAK_ON_EPID_ERROR(result);
   2208     // 1.  Let a = ((a[0], a[2], a[4]), (a[1], a[3], a[5])).
   2209     sts = ippsGFpGetElement(a_in->ipp_ff_elem, (BNU)&a_str,
   2210                             sizeof(a_str) / sizeof(Ipp32u), ps->ff->ipp_ff);
   2211     BREAK_ON_IPP_ERROR(sts, result);
   2212     sts = ippsGFpSetElement((Ipp32u*)&a_str.a[0].a[0],
   2213                             sizeof(a_str.a[0].a[0]) / sizeof(Ipp32u),
   2214                             a[0]->ipp_ff_elem, ps->Fq2->ipp_ff);
   2215     BREAK_ON_IPP_ERROR(sts, result);
   2216     sts = ippsGFpSetElement((Ipp32u*)&a_str.a[0].a[1],
   2217                             sizeof(a_str.a[0].a[1]) / sizeof(Ipp32u),
   2218                             a[2]->ipp_ff_elem, ps->Fq2->ipp_ff);
   2219     BREAK_ON_IPP_ERROR(sts, result);
   2220     sts = ippsGFpSetElement((Ipp32u*)&a_str.a[0].a[2],
   2221                             sizeof(a_str.a[0].a[2]) / sizeof(Ipp32u),
   2222                             a[4]->ipp_ff_elem, ps->Fq2->ipp_ff);
   2223     BREAK_ON_IPP_ERROR(sts, result);
   2224     sts = ippsGFpSetElement((Ipp32u*)&a_str.a[1].a[0],
   2225                             sizeof(a_str.a[1].a[0]) / sizeof(Ipp32u),
   2226                             a[1]->ipp_ff_elem, ps->Fq2->ipp_ff);
   2227     BREAK_ON_IPP_ERROR(sts, result);
   2228     sts = ippsGFpSetElement((Ipp32u*)&a_str.a[1].a[1],
   2229                             sizeof(a_str.a[1].a[1]) / sizeof(Ipp32u),
   2230                             a[3]->ipp_ff_elem, ps->Fq2->ipp_ff);
   2231     BREAK_ON_IPP_ERROR(sts, result);
   2232     sts = ippsGFpSetElement((Ipp32u*)&a_str.a[1].a[2],
   2233                             sizeof(a_str.a[1].a[2]) / sizeof(Ipp32u),
   2234                             a[5]->ipp_ff_elem, ps->Fq2->ipp_ff);
   2235     BREAK_ON_IPP_ERROR(sts, result);
   2236     // 2.  Let e = ((e[0], e[2], e[4]), (e[1], e[3], e[5])).
   2237 
   2238     // 3.  (t00, t11) = Fq12.SquareForFq4(a[0], a[3]).
   2239     result = SquareForFq4(ps, t00, t11, a[0], a[3]);
   2240     BREAK_ON_EPID_ERROR(result);
   2241     // 4.  (t01, t12) = Fq12.SquareForFq4(a[1], a[4]).
   2242     result = SquareForFq4(ps, t01, t12, a[1], a[4]);
   2243     BREAK_ON_EPID_ERROR(result);
   2244     // 5.  (t02, t10) = Fq12.SquareForFq4(a[2], a[5]).
   2245     result = SquareForFq4(ps, t02, t10, a[2], a[5]);
   2246     BREAK_ON_EPID_ERROR(result);
   2247     // 6.  Set t10 = t10 * xi.
   2248     sts = ippsGFpMul(t10->ipp_ff_elem, xi->ipp_ff_elem, t10->ipp_ff_elem,
   2249                      ps->Fq2->ipp_ff);
   2250     BREAK_ON_IPP_ERROR(sts, result);
   2251     // 7.  Set e[0] = 3 * t00 - 2 * a[0].
   2252     sts = ippsGFpAdd(t00->ipp_ff_elem, t00->ipp_ff_elem, e[0]->ipp_ff_elem,
   2253                      ps->Fq2->ipp_ff);
   2254     BREAK_ON_IPP_ERROR(sts, result);
   2255     sts = ippsGFpAdd(e[0]->ipp_ff_elem, t00->ipp_ff_elem, e[0]->ipp_ff_elem,
   2256                      ps->Fq2->ipp_ff);
   2257     BREAK_ON_IPP_ERROR(sts, result);
   2258     sts = ippsGFpSub(e[0]->ipp_ff_elem, a[0]->ipp_ff_elem, e[0]->ipp_ff_elem,
   2259                      ps->Fq2->ipp_ff);
   2260     BREAK_ON_IPP_ERROR(sts, result);
   2261     sts = ippsGFpSub(e[0]->ipp_ff_elem, a[0]->ipp_ff_elem, e[0]->ipp_ff_elem,
   2262                      ps->Fq2->ipp_ff);
   2263     BREAK_ON_IPP_ERROR(sts, result);
   2264     // 8.  Set e[2] = 3 * t01 - 2 * a[2].
   2265     sts = ippsGFpAdd(t01->ipp_ff_elem, t01->ipp_ff_elem, e[2]->ipp_ff_elem,
   2266                      ps->Fq2->ipp_ff);
   2267     BREAK_ON_IPP_ERROR(sts, result);
   2268     sts = ippsGFpAdd(e[2]->ipp_ff_elem, t01->ipp_ff_elem, e[2]->ipp_ff_elem,
   2269                      ps->Fq2->ipp_ff);
   2270     BREAK_ON_IPP_ERROR(sts, result);
   2271     sts = ippsGFpSub(e[2]->ipp_ff_elem, a[2]->ipp_ff_elem, e[2]->ipp_ff_elem,
   2272                      ps->Fq2->ipp_ff);
   2273     BREAK_ON_IPP_ERROR(sts, result);
   2274     sts = ippsGFpSub(e[2]->ipp_ff_elem, a[2]->ipp_ff_elem, e[2]->ipp_ff_elem,
   2275                      ps->Fq2->ipp_ff);
   2276     BREAK_ON_IPP_ERROR(sts, result);
   2277     // 9.  Set e[4] = 3 * t02 - 2 * a[4].
   2278     sts = ippsGFpAdd(t02->ipp_ff_elem, t02->ipp_ff_elem, e[4]->ipp_ff_elem,
   2279                      ps->Fq2->ipp_ff);
   2280     BREAK_ON_IPP_ERROR(sts, result);
   2281     sts = ippsGFpAdd(e[4]->ipp_ff_elem, t02->ipp_ff_elem, e[4]->ipp_ff_elem,
   2282                      ps->Fq2->ipp_ff);
   2283     BREAK_ON_IPP_ERROR(sts, result);
   2284     sts = ippsGFpSub(e[4]->ipp_ff_elem, a[4]->ipp_ff_elem, e[4]->ipp_ff_elem,
   2285                      ps->Fq2->ipp_ff);
   2286     BREAK_ON_IPP_ERROR(sts, result);
   2287     sts = ippsGFpSub(e[4]->ipp_ff_elem, a[4]->ipp_ff_elem, e[4]->ipp_ff_elem,
   2288                      ps->Fq2->ipp_ff);
   2289     BREAK_ON_IPP_ERROR(sts, result);
   2290     // 10. Set e[1] = 3 * t10 + 2 * a[1].
   2291     sts = ippsGFpAdd(t10->ipp_ff_elem, t10->ipp_ff_elem, e[1]->ipp_ff_elem,
   2292                      ps->Fq2->ipp_ff);
   2293     BREAK_ON_IPP_ERROR(sts, result);
   2294     sts = ippsGFpAdd(e[1]->ipp_ff_elem, t10->ipp_ff_elem, e[1]->ipp_ff_elem,
   2295                      ps->Fq2->ipp_ff);
   2296     BREAK_ON_IPP_ERROR(sts, result);
   2297     sts = ippsGFpAdd(e[1]->ipp_ff_elem, a[1]->ipp_ff_elem, e[1]->ipp_ff_elem,
   2298                      ps->Fq2->ipp_ff);
   2299     BREAK_ON_IPP_ERROR(sts, result);
   2300     sts = ippsGFpAdd(e[1]->ipp_ff_elem, a[1]->ipp_ff_elem, e[1]->ipp_ff_elem,
   2301                      ps->Fq2->ipp_ff);
   2302     BREAK_ON_IPP_ERROR(sts, result);
   2303     // 11. Set e[3] = 3 * t11 + 2 * a[3].
   2304     sts = ippsGFpAdd(t11->ipp_ff_elem, t11->ipp_ff_elem, e[3]->ipp_ff_elem,
   2305                      ps->Fq2->ipp_ff);
   2306     BREAK_ON_IPP_ERROR(sts, result);
   2307     sts = ippsGFpAdd(e[3]->ipp_ff_elem, t11->ipp_ff_elem, e[3]->ipp_ff_elem,
   2308                      ps->Fq2->ipp_ff);
   2309     BREAK_ON_IPP_ERROR(sts, result);
   2310     sts = ippsGFpAdd(e[3]->ipp_ff_elem, a[3]->ipp_ff_elem, e[3]->ipp_ff_elem,
   2311                      ps->Fq2->ipp_ff);
   2312     BREAK_ON_IPP_ERROR(sts, result);
   2313     sts = ippsGFpAdd(e[3]->ipp_ff_elem, a[3]->ipp_ff_elem, e[3]->ipp_ff_elem,
   2314                      ps->Fq2->ipp_ff);
   2315     BREAK_ON_IPP_ERROR(sts, result);
   2316     // 12. Set e[5] = 3 * t12 + 2 * a[5].
   2317     sts = ippsGFpAdd(t12->ipp_ff_elem, t12->ipp_ff_elem, e[5]->ipp_ff_elem,
   2318                      ps->Fq2->ipp_ff);
   2319     BREAK_ON_IPP_ERROR(sts, result);
   2320     sts = ippsGFpAdd(e[5]->ipp_ff_elem, t12->ipp_ff_elem, e[5]->ipp_ff_elem,
   2321                      ps->Fq2->ipp_ff);
   2322     BREAK_ON_IPP_ERROR(sts, result);
   2323     sts = ippsGFpAdd(e[5]->ipp_ff_elem, a[5]->ipp_ff_elem, e[5]->ipp_ff_elem,
   2324                      ps->Fq2->ipp_ff);
   2325     BREAK_ON_IPP_ERROR(sts, result);
   2326     sts = ippsGFpAdd(e[5]->ipp_ff_elem, a[5]->ipp_ff_elem, e[5]->ipp_ff_elem,
   2327                      ps->Fq2->ipp_ff);
   2328     BREAK_ON_IPP_ERROR(sts, result);
   2329     // 13. Return e.
   2330     sts = ippsGFpGetElement(e[0]->ipp_ff_elem, (BNU)&e_str.a[0].a[0],
   2331                             sizeof(e_str.a[0].a[0]) / sizeof(Ipp32u),
   2332                             ps->Fq2->ipp_ff);
   2333     BREAK_ON_IPP_ERROR(sts, result);
   2334     sts = ippsGFpGetElement(e[2]->ipp_ff_elem, (BNU)&e_str.a[0].a[1],
   2335                             sizeof(e_str.a[0].a[0]) / sizeof(Ipp32u),
   2336                             ps->Fq2->ipp_ff);
   2337     BREAK_ON_IPP_ERROR(sts, result);
   2338     sts = ippsGFpGetElement(e[4]->ipp_ff_elem, (BNU)&e_str.a[0].a[2],
   2339                             sizeof(e_str.a[0].a[0]) / sizeof(Ipp32u),
   2340                             ps->Fq2->ipp_ff);
   2341     BREAK_ON_IPP_ERROR(sts, result);
   2342     sts = ippsGFpGetElement(e[1]->ipp_ff_elem, (BNU)&e_str.a[1].a[0],
   2343                             sizeof(e_str.a[0].a[0]) / sizeof(Ipp32u),
   2344                             ps->Fq2->ipp_ff);
   2345     BREAK_ON_IPP_ERROR(sts, result);
   2346     sts = ippsGFpGetElement(e[3]->ipp_ff_elem, (BNU)&e_str.a[1].a[1],
   2347                             sizeof(e_str.a[0].a[0]) / sizeof(Ipp32u),
   2348                             ps->Fq2->ipp_ff);
   2349     BREAK_ON_IPP_ERROR(sts, result);
   2350     sts = ippsGFpGetElement(e[5]->ipp_ff_elem, (BNU)&e_str.a[1].a[2],
   2351                             sizeof(e_str.a[0].a[0]) / sizeof(Ipp32u),
   2352                             ps->Fq2->ipp_ff);
   2353     BREAK_ON_IPP_ERROR(sts, result);
   2354     sts = ippsGFpSetElement((Ipp32u*)&e_str, sizeof(e_str) / sizeof(Ipp32u),
   2355                             e_out->ipp_ff_elem, ps->ff->ipp_ff);
   2356     BREAK_ON_IPP_ERROR(sts, result);
   2357     result = kEpidNoErr;
   2358   } while (0);
   2359 
   2360   EpidZeroMemory(&a_str, sizeof(a_str));
   2361   EpidZeroMemory(&e_str, sizeof(e_str));
   2362   EpidZeroMemory(&Fq6IrrPolynomial, sizeof(Fq6IrrPolynomial));
   2363   DeleteFfElement(&t00);
   2364   DeleteFfElement(&t01);
   2365   DeleteFfElement(&t02);
   2366   DeleteFfElement(&t10);
   2367   DeleteFfElement(&t11);
   2368   DeleteFfElement(&t12);
   2369 
   2370   for (i = 0; i < 6; i++) {
   2371     DeleteFfElement(&a[i]);
   2372     DeleteFfElement(&e[i]);
   2373   }
   2374 
   2375   DeleteFfElement(&xi);
   2376 
   2377   return (result);
   2378 }
   2379 
   2380 /*
   2381   e = Fq12.expCyclotomic(a, b)
   2382   Input: a (an element in Fq12), b (a non-negative integer)
   2383   Output: e (an element in Fq12) where e = a^b
   2384   Steps:
   2385 
   2386   2.  Set e = a.
   2387   3.  For i = n-1, ..., 0, do the following:
   2388   e = Fq12.squareCyclotomic(e, e),
   2389   If bi = 1, compute e = Fq12.mul(e, a).
   2390   4.  Return e.
   2391 */
   2392 static EpidStatus ExpCyclotomic(PairingState* ps, FfElement* e,
   2393                                 FfElement const* a, BigNum const* b) {
   2394   EpidStatus result = kEpidErr;
   2395 
   2396   // check parameters
   2397   if (!e || !a || !b || !ps) return kEpidBadArgErr;
   2398   if (!ps->Fq || !ps->Fq2) {
   2399     return kEpidBadArgErr;
   2400   }
   2401   if (!e->ipp_ff_elem || !a->ipp_ff_elem || !ps->Fq->ipp_ff ||
   2402       !ps->Fq2->ipp_ff || !b->ipp_bn)
   2403     return kEpidBadArgErr;
   2404 
   2405   do {
   2406     IppStatus sts = ippStsNoErr;
   2407     int num_bits = 0;
   2408     IppBNU b_str = 0;
   2409     int i = 0;
   2410 
   2411     // 1.  Let bn...b1b0 be the binary representation of b.
   2412     sts = ippsRef_BN(0, &num_bits, &b_str, b->ipp_bn);
   2413     BREAK_ON_IPP_ERROR(sts, result);
   2414     // 2.  Set e = a.
   2415     sts = ippsGFpCpyElement(a->ipp_ff_elem, e->ipp_ff_elem, ps->ff->ipp_ff);
   2416     BREAK_ON_IPP_ERROR(sts, result);
   2417     // 3.  For i = n-1, ..., 0, do the following:
   2418     for (i = num_bits - 2; i >= 0; i--) {
   2419       //       e = Fq12.squareCyclotomic(e, e),
   2420       result = SquareCyclotomic(ps, e, e);
   2421       BREAK_ON_EPID_ERROR(result);
   2422       //       If bi = 1, compute e = Fq12.mul(e, a).
   2423       if (1 == Bit(b_str, i)) {
   2424         sts = ippsGFpMul(e->ipp_ff_elem, a->ipp_ff_elem, e->ipp_ff_elem,
   2425                          ps->ff->ipp_ff);
   2426         BREAK_ON_IPP_ERROR(sts, result);
   2427       }
   2428       // 4.  Return e.
   2429     }
   2430     result = kEpidNoErr;
   2431   } while (0);
   2432 
   2433   return (result);
   2434 }
   2435