• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
NewPairingState(EcGroup const * ga,EcGroup const * gb,FiniteField * ff,BigNumStr const * t,bool neg,PairingState ** ps)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 
DeletePairingState(PairingState ** ps)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 
Pairing(PairingState * ps,EcPoint const * a,EcPoint const * b,FfElement * d)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 */
FinalExp(PairingState * ps,FfElement * d,FfElement const * h)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 */
PiOp(PairingState * ps,FfElement * x_out,FfElement * y_out,FfElement const * x,FfElement const * y,const int e)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 */
FrobeniusOp(PairingState * ps,FfElement * d_out,FfElement const * a,const int e)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 */
Line(FiniteField * gt,FfElement * f,FfElement * x_out,FfElement * y_out,FfElement * z_out,FfElement * z2_out,FfElement const * px,FfElement const * py,FfElement const * x,FfElement const * y,FfElement const * z,FfElement const * z2,FfElement const * qx,FfElement const * qy)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 */
Tangent(FiniteField * gt,FfElement * f,FfElement * x_out,FfElement * y_out,FfElement * z_out,FfElement * z2_out,FfElement const * px,FfElement const * py,FfElement const * x,FfElement const * y,FfElement const * z,FfElement const * z2)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 */
Ternary(int * s,int * n,int max_elements,BigNum const * x)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 
Bit(Ipp32u const * num,Ipp32u bit_index)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 */
MulXiFast(FfElement * e,FfElement const * a,PairingState * ps)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 */
MulV(FfElement * e,FfElement * a,PairingState * ps)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 */
Fq6MulGFpE2(FfElement * e,FfElement * a,FfElement * b0,FfElement * b1,PairingState * ps)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 */
MulSpecial(FfElement * e,FfElement const * a,FfElement const * b,PairingState * ps)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 */
SquareForFq4(PairingState * ps,FfElement * e0,FfElement * e1,FfElement const * a0,FfElement const * a1)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 */
SquareCyclotomic(PairingState * ps,FfElement * e_out,FfElement const * a_in)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 */
ExpCyclotomic(PairingState * ps,FfElement * e,FfElement const * a,BigNum const * b)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