| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659 |
- /*############################################################################
- # Copyright 2016-2017 Intel Corporation
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- ############################################################################*/
- /*!
- * \file
- * \brief Finite field implementation.
- */
- #include "epid/common/math/finitefield.h"
- #include <limits.h>
- #include <stdint.h>
- #include <string.h>
- #include "epid/common/math/src/finitefield-internal.h"
- #include "epid/common/src/memory.h"
- #ifndef MIN
- /// Evaluate to minimum of two values
- #define MIN(a, b) ((a) < (b) ? (a) : (b))
- #endif // MIN
- /// Number of leading zero bits in 32 bit integer x.
- static size_t Nlz32(uint32_t x) {
- size_t nlz = sizeof(x) * 8;
- if (x) {
- nlz = 0;
- if (0 == (x & 0xFFFF0000)) {
- nlz += 16;
- x <<= 16;
- }
- if (0 == (x & 0xFF000000)) {
- nlz += 8;
- x <<= 8;
- }
- if (0 == (x & 0xF0000000)) {
- nlz += 4;
- x <<= 4;
- }
- if (0 == (x & 0xC0000000)) {
- nlz += 2;
- x <<= 2;
- }
- if (0 == (x & 0x80000000)) {
- nlz++;
- }
- }
- return nlz;
- }
- /// Bit size of bit number representated as array of Ipp32u.
- #define BNU_BITSIZE(bnu, len) \
- ((len) * sizeof(Ipp32u) * 8 - Nlz32((bnu)[(len)-1]))
- /// Convert bit size to byte size
- #define BIT2BYTE_SIZE(bits) (((bits) + 7) >> 3)
- EpidStatus NewFiniteField(BigNumStr const* prime, FiniteField** ff) {
- EpidStatus result = kEpidErr;
- IppsGFpState* ipp_finitefield_ctx = NULL;
- FiniteField* finitefield_ptr = NULL;
- BigNum* prime_bn = NULL;
- do {
- EpidStatus status = kEpidErr;
- IppStatus sts = ippStsNoErr;
- Ipp32u bnu[sizeof(BigNumStr) / sizeof(Ipp32u)];
- int bnu_size;
- int bit_size = CHAR_BIT * sizeof(BigNumStr);
- int state_size_in_bytes = 0;
- if (!prime || !ff) {
- result = kEpidBadArgErr;
- break;
- }
- bit_size = (int)OctStrBitSize(prime->data.data, sizeof(prime->data.data));
- bnu_size = OctStr2Bnu(bnu, prime, sizeof(*prime));
- if (bnu_size < 0) {
- result = kEpidMathErr;
- break;
- }
- // skip high order zeros from BNU
- while (bnu_size > 1 && 0 == bnu[bnu_size - 1]) {
- bnu_size--;
- }
- // Determine the memory requirement for finite field context
- sts = ippsGFpGetSize(bit_size, &state_size_in_bytes);
- if (ippStsNoErr != sts) {
- if (ippStsSizeErr == sts) {
- result = kEpidBadArgErr;
- } else {
- result = kEpidMathErr;
- }
- break;
- }
- // Allocate space for ipp bignum context
- ipp_finitefield_ctx = (IppsGFpState*)SAFE_ALLOC(state_size_in_bytes);
- if (!ipp_finitefield_ctx) {
- result = kEpidMemAllocErr;
- break;
- }
- status = NewBigNum(sizeof(BigNumStr), &prime_bn);
- if (kEpidNoErr != status) {
- result = kEpidMathErr;
- break;
- }
- status = ReadBigNum(prime, sizeof(BigNumStr), prime_bn);
- if (kEpidNoErr != status) {
- result = kEpidMathErr;
- break;
- }
- // Initialize ipp finite field context
- sts = ippsGFpInit(prime_bn->ipp_bn, bit_size, ippsGFpMethod_pArb(),
- ipp_finitefield_ctx);
- if (ippStsNoErr != sts) {
- if (ippStsSizeErr == sts) {
- result = kEpidBadArgErr;
- } else {
- result = kEpidMathErr;
- }
- break;
- }
- finitefield_ptr = (FiniteField*)SAFE_ALLOC(sizeof(FiniteField));
- if (!finitefield_ptr) {
- result = kEpidMemAllocErr;
- break;
- }
- finitefield_ptr->element_strlen_required =
- BIT2BYTE_SIZE(BNU_BITSIZE(bnu, bnu_size));
- finitefield_ptr->modulus_0 = prime_bn;
- finitefield_ptr->basic_degree = 1;
- finitefield_ptr->ground_degree = 1;
- finitefield_ptr->element_len = bnu_size;
- finitefield_ptr->ground_ff = NULL;
- finitefield_ptr->ipp_ff = ipp_finitefield_ctx;
- *ff = finitefield_ptr;
- result = kEpidNoErr;
- } while (0);
- if (kEpidNoErr != result) {
- SAFE_FREE(finitefield_ptr);
- SAFE_FREE(prime_bn);
- SAFE_FREE(ipp_finitefield_ctx);
- }
- return result;
- }
- EpidStatus NewFiniteFieldViaBinomalExtension(FiniteField const* ground_field,
- FfElement const* ground_element,
- int degree, FiniteField** ff) {
- EpidStatus result = kEpidErr;
- IppsGFpState* ipp_finitefield_ctx = NULL;
- IppOctStr ff_elem_str = NULL;
- FiniteField* finitefield_ptr = NULL;
- BigNum* modulus_0 = NULL;
- do {
- EpidStatus status = kEpidErr;
- IppStatus sts = ippStsNoErr;
- int state_size_in_bytes = 0;
- if (!ground_field || !ground_element || !ff) {
- result = kEpidBadArgErr;
- break;
- } else if (degree < 2 || !ground_field->ipp_ff ||
- !ground_element->ipp_ff_elem) {
- result = kEpidBadArgErr;
- break;
- }
- // Determine the memory requirement for finite field context
- sts = ippsGFpxGetSize(ground_field->ipp_ff, degree, &state_size_in_bytes);
- if (ippStsNoErr != sts) {
- if (ippStsSizeErr == sts) {
- result = kEpidBadArgErr;
- } else {
- result = kEpidMathErr;
- }
- break;
- }
- // Allocate space for ipp finite field context
- ipp_finitefield_ctx = (IppsGFpState*)SAFE_ALLOC(state_size_in_bytes);
- if (!ipp_finitefield_ctx) {
- result = kEpidMemAllocErr;
- break;
- }
- // Initialize ipp binomial extension finite field context
- sts = ippsGFpxInitBinomial(
- ground_field->ipp_ff, degree, ground_element->ipp_ff_elem,
- 2 == degree
- ? (3 == ground_field->basic_degree ? ippsGFpxMethod_binom2()
- : ippsGFpxMethod_binom2_epid2())
- : ippsGFpxMethod_binom3_epid2(),
- ipp_finitefield_ctx);
- if (ippStsNoErr != sts) {
- if (ippStsSizeErr == sts) {
- result = kEpidBadArgErr;
- } else {
- result = kEpidMathErr;
- }
- break;
- }
- finitefield_ptr = (FiniteField*)SAFE_ALLOC(sizeof(FiniteField));
- if (!finitefield_ptr) {
- result = kEpidMemAllocErr;
- break;
- }
- finitefield_ptr->element_strlen_required =
- ground_field->element_strlen_required * degree;
- ff_elem_str =
- (IppOctStr)SAFE_ALLOC(ground_field->element_len * sizeof(Ipp32u));
- if (!ff_elem_str) {
- result = kEpidMemAllocErr;
- break;
- }
- status = NewBigNum(ground_field->element_len * sizeof(Ipp32u), &modulus_0);
- if (kEpidNoErr != status) {
- break;
- }
- if (kEpidNoErr != status) {
- result = kEpidMathErr;
- break;
- }
- result =
- WriteFfElement((FiniteField*)ground_field, ground_element, ff_elem_str,
- ground_field->element_len * sizeof(Ipp32u));
- if (kEpidNoErr != result) break;
- status = ReadBigNum(ff_elem_str, ground_field->element_len * sizeof(Ipp32u),
- modulus_0);
- if (kEpidNoErr != status) {
- result = kEpidMathErr;
- break;
- }
- finitefield_ptr->basic_degree = ground_field->basic_degree * degree;
- finitefield_ptr->ground_degree = degree;
- finitefield_ptr->element_len = ground_field->element_len * degree;
- finitefield_ptr->modulus_0 = modulus_0;
- // Warning: once assigned ground field must never be modified. this was not
- // made const
- // to allow the FiniteField structure to be used in context when we want to
- // modify the parameters.
- finitefield_ptr->ground_ff = (FiniteField*)ground_field;
- finitefield_ptr->ipp_ff = ipp_finitefield_ctx;
- *ff = finitefield_ptr;
- result = kEpidNoErr;
- } while (0);
- SAFE_FREE(ff_elem_str);
- if (kEpidNoErr != result) {
- SAFE_FREE(finitefield_ptr);
- SAFE_FREE(modulus_0);
- SAFE_FREE(ipp_finitefield_ctx);
- }
- return result;
- }
- EpidStatus NewFiniteFieldViaPolynomialExtension(FiniteField const* ground_field,
- BigNumStr const* irr_polynomial,
- int degree, FiniteField** ff) {
- EpidStatus result = kEpidErr;
- IppsGFpState* ipp_finitefield_ctx = NULL;
- FiniteField* finitefield_ptr = NULL;
- FfElement** ff_elems = NULL;
- IppsGFpElement** ff_elems_state = NULL;
- BigNum* modulus_0 = NULL;
- int i;
- do {
- EpidStatus status = kEpidErr;
- IppStatus sts = ippStsNoErr;
- int state_size_in_bytes = 0;
- if (!ground_field || !irr_polynomial || !ff) {
- result = kEpidBadArgErr;
- break;
- }
- if (degree < 1 || degree > (int)(INT_MAX / sizeof(BigNumStr)) ||
- !ground_field->ipp_ff) {
- result = kEpidBadArgErr;
- break;
- }
- // Determine the memory requirement for finite field context
- sts = ippsGFpxGetSize(ground_field->ipp_ff, degree, &state_size_in_bytes);
- if (ippStsNoErr != sts) {
- if (ippStsSizeErr == sts) {
- result = kEpidBadArgErr;
- } else {
- result = kEpidMathErr;
- }
- break;
- }
- // Allocate space for ipp finite field context
- ipp_finitefield_ctx = (IppsGFpState*)SAFE_ALLOC(state_size_in_bytes);
- if (!ipp_finitefield_ctx) {
- result = kEpidMemAllocErr;
- break;
- }
- ff_elems = (FfElement**)SAFE_ALLOC(sizeof(FfElement*) * degree);
- if (!ff_elems) {
- result = kEpidMemAllocErr;
- break;
- }
- ff_elems_state =
- (IppsGFpElement**)SAFE_ALLOC(sizeof(IppsGFpElement*) * degree);
- if (!ff_elems_state) {
- result = kEpidMemAllocErr;
- break;
- }
- for (i = 0; i < degree; ++i) {
- status = NewFfElement(ground_field, &ff_elems[i]);
- if (kEpidNoErr != status) {
- result = kEpidMathErr;
- break;
- }
- status = ReadFfElement((FiniteField*)ground_field, &irr_polynomial[i],
- sizeof(BigNumStr), ff_elems[i]);
- if (kEpidNoErr != status) {
- result = kEpidMathErr;
- break;
- }
- ff_elems_state[i] = ff_elems[i]->ipp_ff_elem;
- }
- // Initialize ipp binomial extension finite field context
- sts = ippsGFpxInit(ground_field->ipp_ff, degree,
- (const IppsGFpElement* const*)ff_elems_state, degree,
- ippsGFpxMethod_com(), ipp_finitefield_ctx);
- if (ippStsNoErr != sts) {
- if (ippStsSizeErr == sts) {
- result = kEpidBadArgErr;
- } else {
- result = kEpidMathErr;
- }
- break;
- }
- status = NewBigNum(sizeof(irr_polynomial[0]), &modulus_0);
- if (kEpidNoErr != status) {
- break;
- }
- status =
- ReadBigNum(&irr_polynomial[0], sizeof(irr_polynomial[0]), modulus_0);
- if (kEpidNoErr != status) {
- break;
- }
- finitefield_ptr = (FiniteField*)SAFE_ALLOC(sizeof(FiniteField));
- if (!finitefield_ptr) {
- result = kEpidMemAllocErr;
- break;
- }
- finitefield_ptr->element_strlen_required =
- ground_field->element_len * sizeof(Ipp32u) * degree;
- finitefield_ptr->modulus_0 = modulus_0;
- finitefield_ptr->basic_degree = ground_field->basic_degree * degree;
- finitefield_ptr->ground_degree = degree;
- finitefield_ptr->element_len = ground_field->element_len * degree;
- // Warning: once assigned ground field must never be modified. this was not
- // made const
- // to allow the FiniteField structure to be used in context when we want to
- // modify the parameters.
- finitefield_ptr->ground_ff = (FiniteField*)ground_field;
- finitefield_ptr->ipp_ff = ipp_finitefield_ctx;
- *ff = finitefield_ptr;
- result = kEpidNoErr;
- } while (0);
- if (ff_elems != NULL) {
- for (i = 0; i < degree; i++) {
- DeleteFfElement(&ff_elems[i]);
- }
- }
- SAFE_FREE(ff_elems);
- SAFE_FREE(ff_elems_state);
- if (kEpidNoErr != result) {
- SAFE_FREE(finitefield_ptr);
- SAFE_FREE(modulus_0)
- SAFE_FREE(ipp_finitefield_ctx);
- }
- return result;
- }
- void DeleteFiniteField(FiniteField** ff) {
- if (ff) {
- if (*ff) {
- SAFE_FREE((*ff)->ipp_ff);
- DeleteBigNum(&(*ff)->modulus_0);
- }
- SAFE_FREE((*ff));
- }
- }
- EpidStatus NewFfElement(FiniteField const* ff, FfElement** new_ff_elem) {
- EpidStatus result = kEpidErr;
- IppsGFpElement* ipp_ff_elem = NULL;
- FfElement* ff_elem = NULL;
- do {
- IppStatus sts = ippStsNoErr;
- unsigned int ctxsize = 0;
- Ipp32u zero = 0;
- // check parameters
- if (!ff || !new_ff_elem) {
- result = kEpidBadArgErr;
- break;
- } else if (!ff->ipp_ff) {
- result = kEpidBadArgErr;
- break;
- }
- // Determine the memory requirement for finite field element context
- sts = ippsGFpElementGetSize(ff->ipp_ff, (int*)&ctxsize);
- if (ippStsNoErr != sts) {
- result = kEpidMathErr;
- break;
- }
- // Allocate space for ipp bignum context
- ipp_ff_elem = (IppsGFpElement*)SAFE_ALLOC(ctxsize);
- if (!ipp_ff_elem) {
- result = kEpidMemAllocErr;
- break;
- }
- // Initialize ipp bignum context
- // initialize state
- sts = ippsGFpElementInit(&zero, 1, ipp_ff_elem, ff->ipp_ff);
- if (ippStsNoErr != sts) {
- result = kEpidMathErr;
- break;
- }
- ff_elem = (FfElement*)SAFE_ALLOC(sizeof(FfElement));
- if (!ff_elem) {
- result = kEpidMemAllocErr;
- break;
- }
- ff_elem->ipp_ff_elem = ipp_ff_elem;
- ff_elem->element_len = ff->element_len;
- ff_elem->degree = ff->ground_degree;
- *new_ff_elem = ff_elem;
- result = kEpidNoErr;
- } while (0);
- if (kEpidNoErr != result) {
- SAFE_FREE(ipp_ff_elem);
- SAFE_FREE(ff_elem);
- }
- return result;
- }
- void DeleteFfElement(FfElement** ff_elem) {
- if (ff_elem) {
- if (*ff_elem) {
- SAFE_FREE((*ff_elem)->ipp_ff_elem);
- }
- SAFE_FREE(*ff_elem);
- }
- }
- EpidStatus IsValidFfElemOctString(ConstOctStr ff_elem_str, int strlen,
- FiniteField const* ff) {
- int i;
- EpidStatus result = kEpidNoErr;
- IppStatus sts = ippStsNoErr;
- FiniteField const* basic_ff;
- BigNum* pData = NULL;
- int prime_length;
- IppOctStr ff_elem_str_p;
- Ipp32u cmp_res;
- int tmp_strlen = strlen;
- if (!ff || !ff_elem_str) {
- return kEpidBadArgErr;
- }
- basic_ff = ff;
- while (basic_ff->ground_ff != NULL) {
- basic_ff = basic_ff->ground_ff;
- }
- prime_length = basic_ff->element_len * sizeof(Ipp32u);
- ff_elem_str_p = (IppOctStr)ff_elem_str;
- for (i = 0; (i < ff->basic_degree) && (tmp_strlen > 0); i++) {
- int length;
- length = MIN(prime_length, tmp_strlen);
- result = NewBigNum(length, &pData);
- if (kEpidNoErr != result) {
- break;
- }
- result = ReadBigNum(ff_elem_str_p, length, pData);
- if (kEpidNoErr != result) {
- break;
- }
- sts = ippsCmp_BN(basic_ff->modulus_0->ipp_bn, pData->ipp_bn, &cmp_res);
- // check return codes
- if (ippStsNoErr != sts) {
- if (ippStsContextMatchErr == sts)
- result = kEpidBadArgErr;
- else
- result = kEpidMathErr;
- break;
- }
- if (cmp_res != IPP_IS_GT) {
- result = kEpidBadArgErr;
- break;
- }
- DeleteBigNum(&pData);
- tmp_strlen -= length;
- ff_elem_str_p += length;
- }
- DeleteBigNum(&pData);
- return result;
- }
- EpidStatus SetFfElementOctString(ConstOctStr ff_elem_str, int strlen,
- FfElement* ff_elem, FiniteField* ff) {
- EpidStatus result = kEpidErr;
- IppOctStr extended_ff_elem_str = NULL;
- if (!ff || !ff_elem || !ff_elem_str) {
- return kEpidBadArgErr;
- }
- do {
- IppStatus sts;
- // Ipp2017u2 contians a bug in ippsGFpSetElementOctString, does not check
- // whether ff_elem_str < modulus
- result = IsValidFfElemOctString(ff_elem_str, strlen, ff);
- if (kEpidNoErr != result) {
- break;
- }
- // workaround because of bug in ipp2017u2
- if (strlen < (int)(ff->element_len * sizeof(Ipp32u))) {
- int length = ff->element_len * sizeof(Ipp32u);
- extended_ff_elem_str = (IppOctStr)SAFE_ALLOC(length);
- if (!extended_ff_elem_str) {
- result = kEpidMemAllocErr;
- break;
- }
- memset(extended_ff_elem_str, 0, length);
- memcpy_S(extended_ff_elem_str, length, ff_elem_str, strlen);
- strlen = length;
- sts = ippsGFpSetElementOctString(extended_ff_elem_str, strlen,
- ff_elem->ipp_ff_elem, ff->ipp_ff);
- } else {
- sts = ippsGFpSetElementOctString(ff_elem_str, strlen,
- ff_elem->ipp_ff_elem, ff->ipp_ff);
- }
- if (ippStsNoErr != sts) {
- if (ippStsContextMatchErr == sts || ippStsOutOfRangeErr == sts) {
- result = kEpidBadArgErr;
- } else {
- result = kEpidMathErr;
- }
- break;
- }
- } while (0);
- SAFE_FREE(extended_ff_elem_str);
- return result;
- }
- EpidStatus ReadFfElement(FiniteField* ff, ConstOctStr ff_elem_str,
- size_t strlen, FfElement* ff_elem) {
- size_t strlen_required = 0;
- int ipp_str_size = 0;
- EpidStatus result = kEpidNoErr;
- ConstIppOctStr str = (ConstIppOctStr)ff_elem_str;
- if (!ff || !ff_elem_str || !ff_elem) {
- return kEpidBadArgErr;
- }
- if (!ff_elem->ipp_ff_elem || !ff->ipp_ff) {
- return kEpidBadArgErr;
- }
- if (ff->element_len != ff_elem->element_len) {
- return kEpidBadArgErr;
- }
- strlen_required = ff->element_strlen_required;
- // Remove leading zeros when de-serializing finite field of degree 1.
- // This takes care of serialization chunk size adjustments when importing
- // a big numbers.
- if (1 == ff->basic_degree) {
- while (strlen_required < strlen && 0 == *str) {
- str++;
- strlen--;
- }
- }
- // Check if serialized value does not exceed ippsGFpSetElementOctString
- // expected size.
- if (strlen_required < strlen) {
- return kEpidBadArgErr;
- }
- ipp_str_size = (int)strlen;
- if (ipp_str_size <= 0) {
- return kEpidBadArgErr;
- }
- result = SetFfElementOctString(str, ipp_str_size, ff_elem, ff);
- return result;
- }
- /// Gets the prime value of a finite field
- /*!
- This function returns a reference to the bignum containing the field's prime
- value.
- This function only works with non-composite fields.
- \param[in] ff
- The field.
- \param[out] bn
- The target BigNum.
- \returns ::EpidStatus
- */
- EpidStatus GetFiniteFieldPrime(FiniteField* ff, BigNum** bn) {
- if (!ff || !bn) {
- return kEpidBadArgErr;
- }
- if (!ff->ipp_ff) {
- return kEpidBadArgErr;
- }
- if (ff->basic_degree != 1 || ff->ground_degree != 1) {
- return kEpidBadArgErr;
- }
- *bn = ff->modulus_0;
- return kEpidNoErr;
- }
- EpidStatus InitFfElementFromBn(FiniteField* ff, BigNum* bn,
- FfElement* ff_elem) {
- EpidStatus result = kEpidErr;
- BigNum* prime_bn = NULL; // non-owning reference
- BigNum* mod_bn = NULL;
- BNU mod_str = NULL;
- if (!ff || !bn || !ff_elem) {
- return kEpidBadArgErr;
- }
- if (!ff_elem->ipp_ff_elem || !ff->ipp_ff) {
- return kEpidBadArgErr;
- }
- if (ff->basic_degree != 1 || ff->ground_degree != 1) {
- return kEpidBadArgErr;
- }
- if (ff->element_len != ff_elem->element_len) {
- return kEpidBadArgErr;
- }
- do {
- size_t elem_size = ff->element_len * sizeof(Ipp32u);
- result = NewBigNum(elem_size, &mod_bn);
- if (kEpidNoErr != result) {
- break;
- }
- result = GetFiniteFieldPrime(ff, &prime_bn);
- if (kEpidNoErr != result) {
- break;
- }
- result = BigNumMod(bn, prime_bn, mod_bn);
- if (kEpidNoErr != result) {
- break;
- }
- mod_str = (BNU)SAFE_ALLOC(elem_size);
- if (NULL == mod_str) {
- result = kEpidMemAllocErr;
- break;
- }
- result = WriteBigNum(mod_bn, elem_size, mod_str);
- if (kEpidNoErr != result) {
- break;
- }
- result = ReadFfElement(ff, mod_str, elem_size, ff_elem);
- if (kEpidNoErr != result) {
- break;
- }
- result = kEpidNoErr;
- } while (0);
- SAFE_FREE(mod_str);
- prime_bn = NULL;
- DeleteBigNum(&mod_bn);
- return result;
- }
- EpidStatus WriteFfElement(FiniteField* ff, FfElement const* ff_elem,
- OctStr ff_elem_str, size_t strlen) {
- IppStatus sts;
- size_t strlen_required = 0;
- size_t pad = 0;
- IppOctStr str = (IppOctStr)ff_elem_str;
- if (!ff || !ff_elem_str || !ff_elem) {
- return kEpidBadArgErr;
- }
- if (!ff_elem->ipp_ff_elem || !ff->ipp_ff) {
- return kEpidBadArgErr;
- }
- if (INT_MAX < strlen) {
- return kEpidBadArgErr;
- }
- if (ff->element_len != ff_elem->element_len) {
- return kEpidBadArgErr;
- }
- strlen_required = ff->element_strlen_required;
- // add zero padding for extension of a degree 1 (a prime field)
- // so it can be deserialized into big number correctly.
- if (1 == ff->basic_degree && strlen_required < strlen) {
- pad = strlen - strlen_required;
- memset(str, 0, pad);
- strlen -= pad;
- str += pad;
- }
- // Check if output buffer meets ippsGFpGetElementOctString expectations.
- if (strlen_required != strlen) return kEpidBadArgErr;
- // get the data
- sts = ippsGFpGetElementOctString(ff_elem->ipp_ff_elem, str, (int)strlen,
- ff->ipp_ff);
- if (ippStsNoErr != sts) {
- if (ippStsContextMatchErr == sts) {
- return kEpidBadArgErr;
- } else {
- return kEpidMathErr;
- }
- }
- return kEpidNoErr;
- }
- EpidStatus FfNeg(FiniteField* ff, FfElement const* a, FfElement* r) {
- IppStatus sts = ippStsNoErr;
- if (!ff || !a || !r) {
- return kEpidBadArgErr;
- } else if (!ff->ipp_ff || !a->ipp_ff_elem || !r->ipp_ff_elem) {
- return kEpidBadArgErr;
- }
- if (ff->element_len != a->element_len || ff->element_len != r->element_len) {
- return kEpidBadArgErr;
- }
- sts = ippsGFpNeg(a->ipp_ff_elem, r->ipp_ff_elem, ff->ipp_ff);
- if (ippStsNoErr != sts) {
- if (ippStsContextMatchErr == sts) {
- return kEpidBadArgErr;
- } else {
- return kEpidMathErr;
- }
- }
- return kEpidNoErr;
- }
- EpidStatus FfInv(FiniteField* ff, FfElement const* a, FfElement* r) {
- IppStatus sts = ippStsNoErr;
- // Check required parametersWriteFfElement
- if (!ff || !a || !r) {
- return kEpidBadArgErr;
- } else if (!ff->ipp_ff || !a->ipp_ff_elem || !r->ipp_ff_elem) {
- return kEpidBadArgErr;
- }
- if (ff->element_len != a->element_len || ff->element_len != r->element_len) {
- return kEpidBadArgErr;
- }
- // Invert the element
- sts = ippsGFpInv(a->ipp_ff_elem, r->ipp_ff_elem, ff->ipp_ff);
- // Check return codes
- if (ippStsNoErr != sts) {
- if (ippStsContextMatchErr == sts)
- return kEpidBadArgErr;
- else if (ippStsDivByZeroErr == sts)
- return kEpidDivByZeroErr;
- else
- return kEpidMathErr;
- }
- return kEpidNoErr;
- }
- EpidStatus FfAdd(FiniteField* ff, FfElement const* a, FfElement const* b,
- FfElement* r) {
- IppStatus sts = ippStsNoErr;
- if (!ff || !a || !b || !r) {
- return kEpidBadArgErr;
- } else if (!ff->ipp_ff || !a->ipp_ff_elem || !b->ipp_ff_elem ||
- !r->ipp_ff_elem) {
- return kEpidBadArgErr;
- }
- if (ff->element_len != a->element_len || ff->element_len != b->element_len ||
- ff->element_len != r->element_len) {
- return kEpidBadArgErr;
- }
- sts = ippsGFpAdd(a->ipp_ff_elem, b->ipp_ff_elem, r->ipp_ff_elem, ff->ipp_ff);
- if (ippStsContextMatchErr == sts) {
- return kEpidBadArgErr;
- } else if (ippStsNoErr != sts) {
- return kEpidMathErr;
- }
- return kEpidNoErr;
- }
- EpidStatus FfSub(FiniteField* ff, FfElement const* a, FfElement const* b,
- FfElement* r) {
- IppStatus sts = ippStsNoErr;
- if (!ff || !a || !b || !r) {
- return kEpidBadArgErr;
- } else if (!ff->ipp_ff || !a->ipp_ff_elem || !b->ipp_ff_elem ||
- !r->ipp_ff_elem) {
- return kEpidBadArgErr;
- }
- if (ff->element_len != a->element_len || ff->element_len != b->element_len ||
- ff->element_len != r->element_len) {
- return kEpidBadArgErr;
- }
- sts = ippsGFpSub(a->ipp_ff_elem, b->ipp_ff_elem, r->ipp_ff_elem, ff->ipp_ff);
- if (ippStsContextMatchErr == sts) {
- return kEpidBadArgErr;
- } else if (ippStsNoErr != sts) {
- return kEpidMathErr;
- }
- return kEpidNoErr;
- }
- EpidStatus FfMul(FiniteField* ff, FfElement const* a, FfElement const* b,
- FfElement* r) {
- IppStatus sts = ippStsNoErr;
- // Check required parametersWriteFfElement
- if (!ff || !a || !b || !r) {
- return kEpidBadArgErr;
- } else if (!ff->ipp_ff || !a->ipp_ff_elem || !b->ipp_ff_elem ||
- !r->ipp_ff_elem) {
- return kEpidBadArgErr;
- }
- // Multiplies elements
- if (a->element_len != b->element_len &&
- a->element_len == a->degree * b->element_len) {
- sts = ippsGFpMul_PE(a->ipp_ff_elem, b->ipp_ff_elem, r->ipp_ff_elem,
- ff->ipp_ff);
- } else {
- if (ff->element_len != a->element_len ||
- ff->element_len != b->element_len ||
- ff->element_len != r->element_len) {
- return kEpidBadArgErr;
- }
- sts =
- ippsGFpMul(a->ipp_ff_elem, b->ipp_ff_elem, r->ipp_ff_elem, ff->ipp_ff);
- }
- // Check return codes
- if (ippStsNoErr != sts) {
- if (ippStsContextMatchErr == sts)
- return kEpidBadArgErr;
- else
- return kEpidMathErr;
- }
- return kEpidNoErr;
- }
- EpidStatus FfIsZero(FiniteField* ff, FfElement const* a, bool* is_zero) {
- IppStatus sts = ippStsNoErr;
- int ipp_result = IPP_IS_NE;
- // Check required parameters
- if (!ff || !a || !is_zero) {
- return kEpidBadArgErr;
- } else if (!ff->ipp_ff || !a->ipp_ff_elem) {
- return kEpidBadArgErr;
- }
- if (ff->element_len != a->element_len) {
- return kEpidBadArgErr;
- }
- // Check if the element is zero
- sts = ippsGFpIsZeroElement(a->ipp_ff_elem, &ipp_result, ff->ipp_ff);
- // Check return codes
- if (ippStsNoErr != sts) {
- if (ippStsContextMatchErr == sts)
- return kEpidBadArgErr;
- else
- return kEpidMathErr;
- }
- if (IPP_IS_EQ == ipp_result) {
- *is_zero = true;
- } else {
- *is_zero = false;
- }
- return kEpidNoErr;
- }
- EpidStatus FfExp(FiniteField* ff, FfElement const* a, BigNum const* b,
- FfElement* r) {
- EpidStatus result = kEpidErr;
- OctStr scratch_buffer = NULL;
- int exp_bit_size = 0;
- int element_size = 0;
- do {
- IppStatus sts = ippStsNoErr;
- // Check required parameters
- if (!ff || !a || !b || !r) {
- result = kEpidBadArgErr;
- break;
- } else if (!ff->ipp_ff || !a->ipp_ff_elem || !r->ipp_ff_elem) {
- result = kEpidBadArgErr;
- break;
- }
- if (ff->element_len != a->element_len ||
- ff->element_len != r->element_len) {
- return kEpidBadArgErr;
- }
- sts = ippsRef_BN(0, &exp_bit_size, 0, b->ipp_bn);
- if (ippStsNoErr != sts) {
- result = kEpidMathErr;
- break;
- }
- sts = ippsGFpScratchBufferSize(1, exp_bit_size, ff->ipp_ff, &element_size);
- if (ippStsNoErr != sts) {
- result = kEpidMathErr;
- break;
- }
- scratch_buffer = (OctStr)SAFE_ALLOC(element_size);
- if (!scratch_buffer) {
- result = kEpidMemAllocErr;
- break;
- }
- sts = ippsGFpExp(a->ipp_ff_elem, b->ipp_bn, r->ipp_ff_elem, ff->ipp_ff,
- scratch_buffer);
- // Check return codes
- if (ippStsNoErr != sts) {
- if (ippStsContextMatchErr == sts || ippStsRangeErr == sts)
- result = kEpidBadArgErr;
- else
- result = kEpidMathErr;
- break;
- }
- result = kEpidNoErr;
- } while (0);
- SAFE_FREE(scratch_buffer);
- return result;
- }
- EpidStatus FfMultiExp(FiniteField* ff, FfElement const** p, BigNumStr const** b,
- size_t m, FfElement* r) {
- EpidStatus result = kEpidErr;
- IppsGFpElement** ipp_p = NULL;
- IppsBigNumState** ipp_b = NULL;
- BigNum** bignums = NULL;
- OctStr scratch_buffer = NULL;
- int i = 0;
- int ipp_m = 0;
- // Check required parameters
- if (!ff || !p || !b || !r) {
- return kEpidBadArgErr;
- } else if (!ff->ipp_ff || !r->ipp_ff_elem || m <= 0) {
- return kEpidBadArgErr;
- }
- // because we use ipp function with number of items parameter
- // defined as "int" we need to verify that input length
- // do not exceed INT_MAX to avoid overflow
- if (m > INT_MAX) {
- return kEpidBadArgErr;
- }
- ipp_m = (int)m;
- for (i = 0; i < ipp_m; i++) {
- if (!p[i]) {
- return kEpidBadArgErr;
- }
- if (!p[i]->ipp_ff_elem) {
- return kEpidBadArgErr;
- }
- if (ff->element_len != p[i]->element_len) {
- return kEpidBadArgErr;
- }
- }
- if (ff->element_len != r->element_len) {
- return kEpidBadArgErr;
- }
- do {
- IppStatus sts = ippStsNoErr;
- int scratch_buffer_size = 0;
- const int exp_bit_size = CHAR_BIT * sizeof(BigNumStr);
- // Allocate memory for finite field elements for ipp call
- ipp_p = (IppsGFpElement**)SAFE_ALLOC(ipp_m * sizeof(IppsGFpElement*));
- if (!ipp_p) {
- result = kEpidMemAllocErr;
- break;
- }
- for (i = 0; i < ipp_m; i++) {
- ipp_p[i] = p[i]->ipp_ff_elem;
- }
- // Create big number elements for ipp call
- // Allocate memory for finite field elements for ipp call
- bignums = (BigNum**)SAFE_ALLOC(ipp_m * sizeof(BigNum*));
- if (!bignums) {
- result = kEpidMemAllocErr;
- break;
- }
- ipp_b = (IppsBigNumState**)SAFE_ALLOC(ipp_m * sizeof(IppsBigNumState*));
- if (!ipp_b) {
- result = kEpidMemAllocErr;
- break;
- }
- // Initialize BigNum and fill ipp array for ipp call
- for (i = 0; i < ipp_m; i++) {
- result = NewBigNum(sizeof(BigNumStr), &bignums[i]);
- if (kEpidNoErr != result) break;
- result = ReadBigNum(b[i], sizeof(BigNumStr), bignums[i]);
- if (kEpidNoErr != result) break;
- ipp_b[i] = bignums[i]->ipp_bn;
- }
- if (kEpidNoErr != result) break;
- // calculate scratch buffer size
- sts = ippsGFpScratchBufferSize(ipp_m, exp_bit_size, ff->ipp_ff,
- &scratch_buffer_size);
- if (sts != ippStsNoErr) {
- result = kEpidMathErr;
- break;
- }
- // allocate memory for scratch buffer
- scratch_buffer = (OctStr)SAFE_ALLOC(scratch_buffer_size);
- if (!scratch_buffer) {
- result = kEpidMemAllocErr;
- break;
- }
- sts = ippsGFpMultiExp((const IppsGFpElement* const*)ipp_p,
- (const IppsBigNumState* const*)ipp_b, ipp_m,
- r->ipp_ff_elem, ff->ipp_ff, scratch_buffer);
- if (ippStsNoErr != sts) {
- if (ippStsContextMatchErr == sts || ippStsRangeErr == sts)
- result = kEpidBadArgErr;
- else
- result = kEpidMathErr;
- break;
- }
- result = kEpidNoErr;
- } while (0);
- if (NULL != bignums) { // delete big nums only if it was really allocated
- for (i = 0; i < ipp_m; i++) {
- DeleteBigNum(&bignums[i]);
- }
- }
- SAFE_FREE(bignums);
- SAFE_FREE(ipp_p);
- SAFE_FREE(ipp_b);
- SAFE_FREE(scratch_buffer);
- return result;
- }
- EpidStatus FfMultiExpBn(FiniteField* ff, FfElement const** p, BigNum const** b,
- size_t m, FfElement* r) {
- IppStatus sts = ippStsNoErr;
- EpidStatus result = kEpidErr;
- IppsGFpElement** ipp_p = NULL;
- IppsBigNumState** ipp_b = NULL;
- OctStr scratch_buffer = NULL;
- int exp_bit_size = 0;
- size_t i = 0;
- int ipp_m = 0;
- // Check required parameters
- if (!ff || !p || !b || !r) {
- return kEpidBadArgErr;
- } else if (!ff->ipp_ff || !r->ipp_ff_elem || m <= 0) {
- return kEpidBadArgErr;
- } else if (ff->element_len != r->element_len) {
- return kEpidBadArgErr;
- }
- // because we use ipp function with number of items parameter
- // defined as "int" we need to verify that input length
- // do not exceed INT_MAX to avoid overflow
- if (m > INT_MAX) {
- return kEpidBadArgErr;
- }
- ipp_m = (int)m;
- for (i = 0; i < m; i++) {
- int b_size = 0;
- if (!p[i] || !p[i]->ipp_ff_elem || !b[i] || !b[i]->ipp_bn) {
- return kEpidBadArgErr;
- }
- if (ff->element_len != p[i]->element_len) {
- return kEpidBadArgErr;
- }
- sts = ippsGetSize_BN(b[i]->ipp_bn, &b_size);
- if (ippStsNoErr != sts) {
- return kEpidBadArgErr;
- }
- b_size *= (sizeof(Ipp32u) * CHAR_BIT);
- if (b_size > exp_bit_size) {
- exp_bit_size = b_size;
- }
- }
- do {
- int scratch_buffer_size = 0;
- // Allocate memory for finite field elements for ipp call
- ipp_p = (IppsGFpElement**)SAFE_ALLOC(m * sizeof(IppsGFpElement*));
- if (!ipp_p) {
- result = kEpidMemAllocErr;
- break;
- }
- for (i = 0; i < m; i++) {
- ipp_p[i] = p[i]->ipp_ff_elem;
- }
- ipp_b = (IppsBigNumState**)SAFE_ALLOC(m * sizeof(IppsBigNumState*));
- if (!ipp_b) {
- result = kEpidMemAllocErr;
- break;
- }
- // fill ipp array for ipp call
- for (i = 0; i < m; i++) {
- ipp_b[i] = b[i]->ipp_bn;
- }
- // calculate scratch buffer size
- sts = ippsGFpScratchBufferSize(ipp_m, exp_bit_size, ff->ipp_ff,
- &scratch_buffer_size);
- if (sts != ippStsNoErr) {
- result = kEpidMathErr;
- break;
- }
- // allocate memory for scratch buffer
- scratch_buffer = (OctStr)SAFE_ALLOC(scratch_buffer_size);
- if (!scratch_buffer) {
- result = kEpidMemAllocErr;
- break;
- }
- sts = ippsGFpMultiExp((const IppsGFpElement* const*)ipp_p,
- (const IppsBigNumState* const*)ipp_b, ipp_m,
- r->ipp_ff_elem, ff->ipp_ff, scratch_buffer);
- if (ippStsNoErr != sts) {
- if (ippStsContextMatchErr == sts || ippStsRangeErr == sts)
- result = kEpidBadArgErr;
- else
- result = kEpidMathErr;
- break;
- }
- result = kEpidNoErr;
- } while (0);
- SAFE_FREE(scratch_buffer);
- SAFE_FREE(ipp_b);
- SAFE_FREE(ipp_p);
- return result;
- }
- EpidStatus FfSscmMultiExp(FiniteField* ff, FfElement const** p,
- BigNumStr const** b, size_t m, FfElement* r) {
- // call EcMultiExp directly because its implementation is side channel
- // mitigated already
- return FfMultiExp(ff, p, b, m, r);
- }
- EpidStatus FfIsEqual(FiniteField* ff, FfElement const* a, FfElement const* b,
- bool* is_equal) {
- IppStatus sts;
- int result;
- if (!ff || !a || !b || !is_equal) {
- return kEpidBadArgErr;
- }
- if (!ff->ipp_ff || !a->ipp_ff_elem || !b->ipp_ff_elem) {
- return kEpidBadArgErr;
- }
- if (ff->element_len != a->element_len || ff->element_len != b->element_len) {
- return kEpidBadArgErr;
- }
- sts = ippsGFpCmpElement(a->ipp_ff_elem, b->ipp_ff_elem, &result, ff->ipp_ff);
- if (ippStsNoErr != sts) {
- if (ippStsContextMatchErr == sts) {
- return kEpidBadArgErr;
- } else {
- return kEpidMathErr;
- }
- }
- *is_equal = IPP_IS_EQ == result;
- return kEpidNoErr;
- }
- EpidStatus FfHash(FiniteField* ff, ConstOctStr msg, size_t msg_len,
- HashAlg hash_alg, FfElement* r) {
- EpidStatus result = kEpidErr;
- do {
- IppStatus sts = ippStsNoErr;
- IppHashAlgId hash_id;
- int ipp_msg_len = 0;
- if (!ff || !msg || !r) {
- result = kEpidBadArgErr;
- break;
- } else if (!ff->ipp_ff || !r->ipp_ff_elem || msg_len <= 0) {
- result = kEpidBadArgErr;
- break;
- }
- // because we use ipp function with message length parameter
- // defined as "int" we need to verify that input length
- // do not exceed INT_MAX to avoid overflow
- if (msg_len > INT_MAX) {
- result = kEpidBadArgErr;
- break;
- }
- ipp_msg_len = (int)msg_len;
- if (kSha256 == hash_alg) {
- hash_id = ippHashAlg_SHA256;
- } else if (kSha384 == hash_alg) {
- hash_id = ippHashAlg_SHA384;
- } else if (kSha512 == hash_alg) {
- hash_id = ippHashAlg_SHA512;
- } else if (kSha512_256 == hash_alg) {
- hash_id = ippHashAlg_SHA512_256;
- } else {
- result = kEpidHashAlgorithmNotSupported;
- break;
- }
- if (ff->element_len != r->element_len) {
- return kEpidBadArgErr;
- }
- sts = ippsGFpSetElementHash(msg, ipp_msg_len, r->ipp_ff_elem, ff->ipp_ff,
- hash_id);
- if (ippStsNoErr != sts) {
- if (ippStsContextMatchErr == sts || ippStsBadArgErr == sts ||
- ippStsLengthErr == sts) {
- return kEpidBadArgErr;
- } else {
- return kEpidMathErr;
- }
- }
- result = kEpidNoErr;
- } while (0);
- return result;
- }
- /// Number of tries for RNG
- #define RNG_WATCHDOG (10)
- EpidStatus FfGetRandom(FiniteField* ff, BigNumStr const* low_bound,
- BitSupplier rnd_func, void* rnd_param, FfElement* r) {
- EpidStatus result = kEpidErr;
- FfElement* low = NULL;
- do {
- IppStatus sts = ippStsNoErr;
- unsigned int rngloopCount = RNG_WATCHDOG;
- if (!ff || !low_bound || !rnd_func || !r) {
- result = kEpidBadArgErr;
- break;
- }
- if (!ff->ipp_ff || !r->ipp_ff_elem) {
- result = kEpidBadArgErr;
- break;
- }
- if (ff->element_len != r->element_len) {
- return kEpidBadArgErr;
- }
- // create a new FfElement to hold low_bound
- result = NewFfElement(ff, &low);
- if (kEpidNoErr != result) {
- break;
- }
- result = ReadFfElement(ff, low_bound, sizeof(*low_bound), low);
- if (kEpidNoErr != result) {
- break;
- }
- do {
- int cmpResult = IPP_IS_NE;
- sts = ippsGFpSetElementRandom(r->ipp_ff_elem, ff->ipp_ff,
- (IppBitSupplier)rnd_func, rnd_param);
- if (ippStsNoErr != sts) {
- result = kEpidMathErr;
- break;
- }
- sts = ippsGFpCmpElement(r->ipp_ff_elem, low->ipp_ff_elem, &cmpResult,
- ff->ipp_ff);
- if (ippStsNoErr != sts) {
- result = kEpidMathErr;
- break;
- }
- if (IPP_IS_LT != cmpResult) {
- // we have a valid value, proceed
- result = kEpidNoErr;
- break;
- } else {
- result = kEpidRandMaxIterErr;
- continue;
- }
- } while (--rngloopCount);
- } while (0);
- DeleteFfElement(&low);
- return result;
- }
- EpidStatus FfSqrt(FiniteField* ff, FfElement const* a, FfElement* r) {
- EpidStatus result = kEpidErr;
- BigNum* qm1 = NULL;
- BigNum* one = NULL;
- FfElement* qm1_ffe = NULL;
- BigNum* two = NULL;
- BigNum* qm1d2 = NULL;
- BigNum* remainder = NULL;
- FfElement* g = NULL;
- FfElement* gg = NULL;
- BigNum* t = NULL;
- BigNum* e = NULL;
- BigNum* j = NULL;
- BigNum* qm1dj = NULL;
- FfElement* ge = NULL;
- FfElement* h = NULL;
- FfElement* temp = NULL;
- FfElement* one_ffe = NULL;
- BigNum* ed2 = NULL;
- FfElement* ged2 = NULL;
- BigNum* tp1d2 = NULL;
- FfElement* gtp1d2 = NULL;
- FfElement* dd = NULL;
- if (!ff || !a || !r) {
- return kEpidBadArgErr;
- }
- do {
- BigNum* prime = NULL; // non-owning reference
- bool is_equal = false;
- unsigned int s;
- bool is_even = false;
- unsigned int i;
- Ipp8u one_str = 1;
- BigNumStr qm1_str;
- const BigNumStr zero_str = {0};
- result = GetFiniteFieldPrime(ff, &prime);
- if (kEpidNoErr != result) {
- break;
- }
- result = NewBigNum(sizeof(BigNumStr) * CHAR_BIT, &qm1);
- if (kEpidNoErr != result) {
- break;
- }
- result = NewBigNum(sizeof(BigNumStr) * CHAR_BIT, &one);
- if (kEpidNoErr != result) {
- break;
- }
- result = NewFfElement(ff, &qm1_ffe);
- if (kEpidNoErr != result) {
- break;
- }
- result = NewBigNum(sizeof(BigNumStr) * CHAR_BIT, &two);
- if (kEpidNoErr != result) {
- break;
- }
- result = NewBigNum(sizeof(BigNumStr) * CHAR_BIT, &qm1d2);
- if (kEpidNoErr != result) {
- break;
- }
- result = NewBigNum(sizeof(BigNumStr) * CHAR_BIT, &remainder);
- if (kEpidNoErr != result) {
- break;
- }
- result = NewFfElement(ff, &g);
- if (kEpidNoErr != result) {
- break;
- }
- result = NewFfElement(ff, &gg);
- if (kEpidNoErr != result) {
- break;
- }
- result = NewBigNum(sizeof(BigNumStr) * CHAR_BIT, &t);
- if (kEpidNoErr != result) {
- break;
- }
- result = NewBigNum(sizeof(BigNumStr) * CHAR_BIT, &e);
- if (kEpidNoErr != result) {
- break;
- }
- result = NewBigNum(sizeof(BigNumStr) * CHAR_BIT, &j);
- if (kEpidNoErr != result) {
- break;
- }
- result = NewBigNum(sizeof(BigNumStr) * CHAR_BIT, &qm1dj);
- if (kEpidNoErr != result) {
- break;
- }
- result = NewFfElement(ff, &ge);
- if (kEpidNoErr != result) {
- break;
- }
- result = NewFfElement(ff, &h);
- if (kEpidNoErr != result) {
- break;
- }
- result = NewFfElement(ff, &temp);
- if (kEpidNoErr != result) {
- break;
- }
- result = NewFfElement(ff, &one_ffe);
- if (kEpidNoErr != result) {
- break;
- }
- result = NewBigNum(sizeof(BigNumStr) * CHAR_BIT, &ed2);
- if (kEpidNoErr != result) {
- break;
- }
- result = NewFfElement(ff, &ged2);
- if (kEpidNoErr != result) {
- break;
- }
- result = NewBigNum(sizeof(BigNumStr) * CHAR_BIT, &tp1d2);
- if (kEpidNoErr != result) {
- break;
- }
- result = NewFfElement(ff, >p1d2);
- if (kEpidNoErr != result) {
- break;
- }
- result = NewFfElement(ff, &dd);
- if (kEpidNoErr != result) {
- break;
- }
- result = ReadBigNum(&one_str, sizeof(one_str), one);
- if (kEpidNoErr != result) {
- break;
- }
- result = BigNumSub(prime, one, qm1);
- if (kEpidNoErr != result) {
- break;
- }
- result = BigNumAdd(one, one, two);
- if (kEpidNoErr != result) {
- break;
- }
- result = InitFfElementFromBn(ff, one, one_ffe);
- if (kEpidNoErr != result) {
- break;
- }
- result = WriteBigNum(qm1, sizeof(qm1_str), &qm1_str);
- if (kEpidNoErr != result) {
- break;
- }
- result = InitFfElementFromBn(ff, qm1, qm1_ffe);
- if (kEpidNoErr != result) {
- break;
- }
- result = BigNumDiv(qm1, two, qm1d2, remainder);
- if (kEpidNoErr != result) {
- break;
- }
- // 1. Choose an element g in Fq.
- result = ReadFfElement(ff, &one_str, sizeof(one_str), g);
- if (kEpidNoErr != result) {
- break;
- }
- // try small values for g starting from 2 until
- // it meets the requirements from the step 2
- do {
- result = FfAdd(ff, g, one_ffe, g);
- if (kEpidNoErr != result) {
- break;
- }
- // 2. Check whether g^((q-1)/2) mod q = q-1. If not, go to step 1.
- result = FfExp(ff, g, qm1d2, gg);
- if (kEpidNoErr != result) {
- break;
- }
- result = FfIsEqual(ff, gg, qm1_ffe, &is_equal);
- if (kEpidNoErr != result) {
- break;
- }
- } while (!is_equal);
- if (kEpidNoErr != result) {
- break;
- }
- // 3. Set t = q-1, s = 0.
- result = ReadBigNum(&qm1_str, sizeof(qm1_str), t);
- if (kEpidNoErr != result) {
- break;
- }
- s = 0;
- // 4. While (t is even number)
- // t = t/2, s = s+1.
- result = BigNumIsEven(t, &is_even);
- if (kEpidNoErr != result) {
- break;
- }
- while (is_even) {
- result = BigNumDiv(t, two, t, remainder);
- if (kEpidNoErr != result) {
- break;
- }
- s = s + 1;
- result = BigNumIsEven(t, &is_even);
- if (kEpidNoErr != result) {
- break;
- }
- }
- // 5. Note that g, s, t can be pre-computed and used for all
- // future computations.
- // Also note that q-1 = (2^s)*t where t is an odd integer.
- // 6. e = 0.
- result = ReadBigNum(&zero_str, sizeof(zero_str), e);
- if (kEpidNoErr != result) {
- break;
- }
- // 7. For i = 2, ..., s
- // j = 2^i,
- // if (a ? g^(-e))^((q-1)/j) mod q != 1, then set e = e + j/2.
- for (i = 2; i <= s; i++) {
- result = BigNumPow2N(i, j);
- if (kEpidNoErr != result) {
- break;
- }
- result = BigNumDiv(qm1, j, qm1dj, remainder);
- if (kEpidNoErr != result) {
- break;
- }
- result = FfExp(ff, g, e, ge);
- if (kEpidNoErr != result) {
- break;
- }
- // 8. Compute h = (a * g^(-e)) mod q.
- result = FfInv(ff, ge, ge);
- if (kEpidNoErr != result) {
- break;
- }
- result = FfMul(ff, a, ge, h);
- if (kEpidNoErr != result) {
- break;
- }
- result = FfExp(ff, h, qm1dj, temp);
- if (kEpidNoErr != result) {
- break;
- }
- result = FfIsEqual(ff, temp, one_ffe, &is_equal);
- if (!is_equal) {
- result = BigNumDiv(j, two, j, remainder);
- if (kEpidNoErr != result) {
- break;
- }
- result = BigNumAdd(e, j, e);
- if (kEpidNoErr != result) {
- break;
- }
- }
- }
- // 8. Compute h = (a * g^(-e)) mod q.
- result = FfExp(ff, g, e, ge);
- if (kEpidNoErr != result) {
- break;
- }
- result = FfInv(ff, ge, ge);
- if (kEpidNoErr != result) {
- break;
- }
- result = FfMul(ff, a, ge, h);
- if (kEpidNoErr != result) {
- break;
- }
- // 9. Compute r = d = (g^(e/2) * h^((t+1)/2)) mod q.
- result = BigNumDiv(e, two, ed2, remainder);
- if (kEpidNoErr != result) {
- break;
- }
- result = FfExp(ff, g, ed2, ged2);
- if (kEpidNoErr != result) {
- break;
- }
- result = BigNumAdd(t, one, tp1d2);
- if (kEpidNoErr != result) {
- break;
- }
- result = BigNumDiv(tp1d2, two, tp1d2, remainder);
- if (kEpidNoErr != result) {
- break;
- }
- result = FfExp(ff, h, tp1d2, gtp1d2);
- if (kEpidNoErr != result) {
- break;
- }
- result = FfMul(ff, ged2, gtp1d2, r);
- if (kEpidNoErr != result) {
- break;
- }
- // 10. Verify whether a = d^2 mod q. If so, return r, otherwise, return
- // fail.
- result = FfMul(ff, r, r, dd);
- if (kEpidNoErr != result) {
- break;
- }
- result = FfIsEqual(ff, dd, a, &is_equal);
- if (kEpidNoErr != result) {
- break;
- }
- if (!is_equal) {
- result = kEpidMathQuadraticNonResidueError;
- break;
- }
- result = kEpidNoErr;
- prime = NULL;
- } while (0);
- DeleteFfElement(&dd);
- DeleteFfElement(>p1d2);
- DeleteBigNum(&tp1d2);
- DeleteFfElement(&ged2);
- DeleteBigNum(&ed2);
- DeleteFfElement(&one_ffe);
- DeleteFfElement(&temp);
- DeleteFfElement(&h);
- DeleteFfElement(&ge);
- DeleteBigNum(&qm1dj);
- DeleteBigNum(&j);
- DeleteBigNum(&e);
- DeleteBigNum(&t);
- DeleteFfElement(&gg);
- DeleteFfElement(&g);
- DeleteBigNum(&remainder);
- DeleteBigNum(&qm1d2);
- DeleteBigNum(&two);
- DeleteFfElement(&qm1_ffe);
- DeleteBigNum(&one);
- DeleteBigNum(&qm1);
- return result;
- }
|