blob: 0173d21d099fbc963169f4dbae5b5007bf7069fd [file] [log] [blame]
/*############################################################################
# Copyright 2002-2018 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.
############################################################################*/
/*
// Intel(R) Integrated Performance Primitives
// Cryptographic Primitives (ippcp)
//
// Contents:
// ippsBigNumGetSize()
// ippsBigNumInit()
//
// ippsSet_BN()
// ippsGet_BN()
// ippsGetSize_BN()
// ippsExtGet_BN()
// ippsRef_BN()
//
// ippsCmpZero_BN()
// ippsCmp_BN()
//
// ippsAdd_BN()
// ippsSub_BN()
// ippsMul_BN()
// ippsMAC_BN_I()
// ippsDiv_BN()
// ippsMod_BN()
// ippsGcd_BN()
// ippsModInv_BN()
//
// cpPackBigNumCtx(), cpUnpackBigNumCtx()
//
//
*/
#include "owndefs.h"
#include "owncp.h"
#include "pcpbn.h"
#include "pcptool.h"
/* BN(1) and reference */
static IppsBigNumStateChunk cpChunk_BN1 = {
{
idCtxBigNum,
ippBigNumPOS,
1,1,
&cpChunk_BN1.value,&cpChunk_BN1.temporary
},
1,0
};
#define cpBN_OneRef OWNAPI(cpBN_OneRef)
IppsBigNumState* cpBN_OneRef(void)
{ return &cpChunk_BN1.bn; };
/* BN(2) and reference */
static IppsBigNumStateChunk cpChunk_BN2 = {
{
idCtxBigNum,
ippBigNumPOS,
1,1,
&cpChunk_BN2.value,&cpChunk_BN2.temporary
},
2,0
};
#define cpBN_TwoRef OWNAPI(cpBN_TwoRef)
IppsBigNumState* cpBN_TwoRef(void)
{ return &cpChunk_BN2.bn; };
/* BN(3) and reference */
static IppsBigNumStateChunk cpChunk_BN3 = {
{
idCtxBigNum,
ippBigNumPOS,
1,1,
&cpChunk_BN3.value,&cpChunk_BN3.temporary
},
3,0
};
#define cpBN_ThreeRef OWNAPI(cpBN_ThreeRef)
IppsBigNumState* cpBN_ThreeRef(void)
{ return &cpChunk_BN3.bn; };
/*F*
// Name: ippsBigNumGetSize
//
// Purpose: Returns size of BigNum ctx (bytes).
//
// Returns: Reason:
// ippStsNullPtrErr pCtxSize == NULL
// ippStsLengthErr len32 < 1
// len32 > BITS2WORD32_SIZE(BN_MAXBITSIZE)
// ippStsNoErr no errors
//
// Parameters:
// pCtxSize pointer BigNum ctx size
//
*F*/
IPPFUN(IppStatus, ippsBigNumGetSize, (cpSize len32, cpSize *pCtxSize))
{
IPP_BAD_PTR1_RET(pCtxSize);
IPP_BADARG_RET(len32<1 || len32>BITS2WORD32_SIZE(BN_MAXBITSIZE), ippStsLengthErr);
{
/* convert length to the number of BNU_CHUNK_T */
cpSize len = INTERNAL_BNU_LENGTH(len32);
/* reserve one BNU_CHUNK_T more for cpDiv_BNU,
mul, mont exp operations */
len++;
*pCtxSize = sizeof(IppsBigNumState)
+ len*sizeof(BNU_CHUNK_T)
+ len*sizeof(BNU_CHUNK_T)
+ BN_ALIGNMENT-1;
return ippStsNoErr;
}
}
/*F*
// Name: ippsBigNumInit
//
// Purpose: Init BigNum spec for future usage.
//
// Returns: Reason:
// ippStsNullPtrErr pBN == NULL
// ippStsLengthErr len32<1
// len32 > BITS2WORD32_SIZE(BN_MAXBITSIZE)
// ippStsNoErr no errors
//
// Parameters:
// len32 max BN length (32-bits segments)
// pBN BigNum ctx
//
*F*/
IPPFUN(IppStatus, ippsBigNumInit, (cpSize len32, IppsBigNumState* pBN))
{
IPP_BADARG_RET(len32<1 || len32>BITS2WORD32_SIZE(BN_MAXBITSIZE), ippStsLengthErr);
IPP_BAD_PTR1_RET(pBN);
pBN = (IppsBigNumState*)( IPP_ALIGNED_PTR(pBN, BN_ALIGNMENT) );
{
Ipp8u* ptr = (Ipp8u*)pBN;
/* convert length to the number of BNU_CHUNK_T */
cpSize len = INTERNAL_BNU_LENGTH(len32);
BN_ID(pBN) = idCtxUnknown;
BN_SIGN(pBN) = ippBigNumPOS;
BN_SIZE(pBN) = 1; /* initial valie is zero */
BN_ROOM(pBN) = len; /* close to what has been passed by user */
/* reserve one BNU_CHUNK_T more for cpDiv_BNU,
mul, mont exp operations */
len++;
/* allocate buffers */
BN_NUMBER(pBN) = (BNU_CHUNK_T*)(ptr += sizeof(IppsBigNumState));
BN_BUFFER(pBN) = (BNU_CHUNK_T*)(ptr += len*sizeof(BNU_CHUNK_T)); /* use expanded length here */
/* set BN value and buffer to zero */
ZEXPAND_BNU(BN_NUMBER(pBN), 0, len);
ZEXPAND_BNU(BN_BUFFER(pBN), 0, len);
BN_ID(pBN) = idCtxBigNum;
return ippStsNoErr;
}
}
/*
// Serialize / Deserialize bigNum context
*/
void cpPackBigNumCtx(const IppsBigNumState* pBN, Ipp8u* pBuffer)
{
IppsBigNumState* pAlignedBuffer = (IppsBigNumState*)(IPP_ALIGNED_PTR((pBuffer), BN_ALIGNMENT));
CopyBlock(pBN, pAlignedBuffer, sizeof(IppsBigNumState));
BN_NUMBER(pAlignedBuffer) = (BNU_CHUNK_T*)((Ipp8u*)NULL + IPP_UINT_PTR(BN_NUMBER(pBN))-IPP_UINT_PTR(pBN));
BN_BUFFER(pAlignedBuffer) = (BNU_CHUNK_T*)((Ipp8u*)NULL + IPP_UINT_PTR(BN_BUFFER(pBN))-IPP_UINT_PTR(pBN));
CopyBlock(BN_NUMBER(pBN), (Ipp8u*)pAlignedBuffer+IPP_UINT_PTR(BN_NUMBER(pAlignedBuffer)), BN_ROOM(pBN)*sizeof(BNU_CHUNK_T));
CopyBlock(BN_BUFFER(pBN), (Ipp8u*)pAlignedBuffer+IPP_UINT_PTR(BN_BUFFER(pAlignedBuffer)), BN_ROOM(pBN)*sizeof(BNU_CHUNK_T));
}
void cpUnpackBigNumCtx(const Ipp8u* pBuffer, IppsBigNumState* pBN)
{
IppsBigNumState* pAlignedBuffer = (IppsBigNumState*)(IPP_ALIGNED_PTR((pBuffer), BN_ALIGNMENT));
CopyBlock(pBuffer, pBN, sizeof(IppsBigNumState));
BN_NUMBER(pBN) = (BNU_CHUNK_T*)((Ipp8u*)pBN + IPP_UINT_PTR(BN_NUMBER(pAlignedBuffer)));
BN_BUFFER(pBN) = (BNU_CHUNK_T*)((Ipp8u*)pBN + IPP_UINT_PTR(BN_BUFFER(pAlignedBuffer)));
CopyBlock((Ipp8u*)pAlignedBuffer+IPP_UINT_PTR(BN_NUMBER(pAlignedBuffer)), BN_NUMBER(pBN), BN_ROOM(pBN)*sizeof(BNU_CHUNK_T));
CopyBlock((Ipp8u*)pAlignedBuffer+IPP_UINT_PTR(BN_BUFFER(pAlignedBuffer)), BN_BUFFER(pBN), BN_ROOM(pBN)*sizeof(BNU_CHUNK_T));
}
/*F*
// Name: ippsCmpZero_BN
//
// Purpose: Test BigNum value.
//
// Returns: Reason:
// ippStsNullPtrErr pBN == NULL
// pResult == NULL
// ippStsContextMatchErr BN_VALID_ID()
// ippStsNoErr no errors
//
// Parameters:
// pBN BigNum ctx
// pResult result of comparison
//
*F*/
IPPFUN(IppStatus, ippsCmpZero_BN, (const IppsBigNumState* pBN, Ipp32u* pResult))
{
IPP_BAD_PTR2_RET(pBN, pResult);
pBN = (IppsBigNumState*)( IPP_ALIGNED_PTR(pBN, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pBN), ippStsContextMatchErr);
if(BN_SIZE(pBN)==1 && BN_NUMBER(pBN)[0]==0)
*pResult = IS_ZERO;
else if (BN_SIGN(pBN)==ippBigNumPOS)
*pResult = GREATER_THAN_ZERO;
else if (BN_SIGN(pBN)==ippBigNumNEG)
*pResult = LESS_THAN_ZERO;
return ippStsNoErr;
}
/*F*
// Name: ippsCmp_BN
//
// Purpose: Compare two BigNums.
//
// Returns: Reason:
// ippStsNullPtrErr pA == NULL
// pB == NULL
// pResult == NULL
// ippStsContextMatchErr BN_VALID_ID(pA)
// BN_VALID_ID(pB)
// ippStsNoErr no errors
//
// Parameters:
// pA BigNum ctx
// pB BigNum ctx
// pResult result of comparison
//
*F*/
IPPFUN(IppStatus, ippsCmp_BN,(const IppsBigNumState* pA, const IppsBigNumState* pB, Ipp32u *pResult))
{
IPP_BAD_PTR3_RET(pA, pB, pResult);
pA = (IppsBigNumState*)( IPP_ALIGNED_PTR(pA, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pA), ippStsContextMatchErr);
pB = (IppsBigNumState*)( IPP_ALIGNED_PTR(pB, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pB), ippStsContextMatchErr);
{
int res;
if(BN_SIGN(pA)==BN_SIGN(pB)) {
res = cpCmp_BNU(BN_NUMBER(pA), BN_SIZE(pA), BN_NUMBER(pB), BN_SIZE(pB));
if(ippBigNumNEG==BN_SIGN(pA))
res = -res;
}
else
res = (ippBigNumPOS==BN_SIGN(pA))? 1 :-1;
*pResult = (1==res)? IPP_IS_GT : (-1==res)? IPP_IS_LT : IPP_IS_EQ;
return ippStsNoErr;
}
}
/*F*
// Name: ippsGetSize_BN
//
// Purpose: Returns BigNum room.
//
// Returns: Reason:
// ippStsNullPtrErr pBN == NULL
// pSize == NULL
// ippStsContextMatchErr BN_VALID_ID(pBN)
// ippStsNoErr no errors
//
// Parameters:
// pBN BigNum ctx
// pSize max BigNum length (in Ipp32u chunks)
//
*F*/
IPPFUN(IppStatus, ippsGetSize_BN, (const IppsBigNumState* pBN, cpSize* pSize))
{
IPP_BAD_PTR2_RET(pBN, pSize);
pBN = (IppsBigNumState*)( IPP_ALIGNED_PTR(pBN, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pBN), ippStsContextMatchErr);
*pSize = BN_ROOM(pBN)*sizeof(BNU_CHUNK_T)/sizeof(Ipp32u);
return ippStsNoErr;
}
/*F*
// Name: ippsSet_BN
//
// Purpose: Set BigNum.
//
// Returns: Reason:
// ippStsNullPtrErr pBN == NULL
// pData == NULL
// ippStsContextMatchErr BN_VALID_ID(pBN)
// ippStsLengthErr len32 < 1
// ippStsOutOfRangeErr len32 > BN_ROOM()
// ippStsNoErr no errors
//
// Parameters:
// sgn sign
// len32 data size (in Ipp32u chunks)
// pData source data pointer
// pBn BigNum ctx
//
*F*/
IPPFUN(IppStatus, ippsSet_BN, (IppsBigNumSGN sgn, cpSize len32, const Ipp32u* pData,
IppsBigNumState* pBN))
{
IPP_BAD_PTR2_RET(pData, pBN);
pBN = (IppsBigNumState*)( IPP_ALIGNED_PTR(pBN, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pBN), ippStsContextMatchErr);
IPP_BADARG_RET(len32<1, ippStsLengthErr);
/* compute real size */
FIX_BNU(pData, len32);
{
cpSize len = INTERNAL_BNU_LENGTH(len32);
IPP_BADARG_RET(len > BN_ROOM(pBN), ippStsOutOfRangeErr);
ZEXPAND_COPY_BNU((Ipp32u*)BN_NUMBER(pBN), BN_ROOM(pBN)*(int)(sizeof(BNU_CHUNK_T)/sizeof(Ipp32u)), pData, len32);
BN_SIZE(pBN) = len;
if(len32==1 && pData[0] == 0)
sgn = ippBigNumPOS; /* consider zero value as positive */
BN_SIGN(pBN) = sgn;
return ippStsNoErr;
}
}
/*F*
// Name: ippsGet_BN
//
// Purpose: Get BigNum.
//
// Returns: Reason:
// ippStsNullPtrErr pBN == NULL
// pData == NULL
// pSgn == NULL
// pLen32 ==NULL
// ippStsContextMatchErr !BN_VALID_ID(pBN)
// ippStsNoErr no errors
//
// Parameters:
// pSgn pointer to the sign
// pLen32 pointer to the data size (in Ipp32u chunks)
// pData pointer to the data buffer
// pBN BigNum ctx
//
*F*/
IPPFUN(IppStatus, ippsGet_BN, (IppsBigNumSGN* pSgn, cpSize* pLen32, Ipp32u* pData,
const IppsBigNumState* pBN))
{
IPP_BAD_PTR4_RET(pSgn, pLen32, pData, pBN);
pBN = (IppsBigNumState*)( IPP_ALIGNED_PTR(pBN, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pBN), ippStsContextMatchErr);
{
cpSize len32 = BN_SIZE(pBN)*sizeof(BNU_CHUNK_T)/sizeof(Ipp32u);
Ipp32u* bnData = (Ipp32u*)BN_NUMBER(pBN);
FIX_BNU(bnData, len32);
COPY_BNU(pData, bnData, len32);
*pSgn = BN_SIGN(pBN);
*pLen32 = len32;
return ippStsNoErr;
}
}
/*F*
// Name: ippsRef_BN
//
// Purpose: Get BigNum info.
//
// Returns: Reason:
// ippStsNullPtrErr pBN == NULL
// ippStsContextMatchErr BN_VALID_ID(pBN)
// ippStsNoErr no errors
//
// Parameters:
// pSgn pointer to the sign
// pBitSize pointer to the data size (in bits)
// ppData pointer to the data buffer
// pBN BigNum ctx
//
*F*/
IPPFUN(IppStatus, ippsRef_BN, (IppsBigNumSGN* pSgn, cpSize* pBitSize, Ipp32u** const ppData,
const IppsBigNumState *pBN))
{
IPP_BAD_PTR1_RET(pBN);
pBN = (IppsBigNumState*)( IPP_ALIGNED_PTR(pBN, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pBN), ippStsContextMatchErr);
if(pSgn)
*pSgn = BN_SIGN(pBN);
if(pBitSize) {
cpSize bitLen = BITSIZE_BNU(BN_NUMBER(pBN), BN_SIZE(pBN));
*pBitSize = bitLen? bitLen : 1;
}
if(ppData)
*ppData = (Ipp32u*)BN_NUMBER(pBN);
return ippStsNoErr;
}
IPPFUN(IppStatus, ippsExtGet_BN, (IppsBigNumSGN* pSgn, cpSize* pBitSize, Ipp32u* pData,
const IppsBigNumState* pBN))
{
IPP_BAD_PTR1_RET(pBN);
pBN = (IppsBigNumState*)( IPP_ALIGNED_PTR(pBN, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pBN), ippStsContextMatchErr);
{
cpSize bitSize = BITSIZE_BNU(BN_NUMBER(pBN), BN_SIZE(pBN));
if(0==bitSize)
bitSize = 1;
if(pData)
COPY_BNU(pData, (Ipp32u*)BN_NUMBER(pBN), BITS2WORD32_SIZE(bitSize));
if(pSgn)
*pSgn = BN_SIGN(pBN);
if(pBitSize)
*pBitSize = bitSize;
return ippStsNoErr;
}
}
/*F*
// Name: ippsAdd_BN
//
// Purpose: Add BigNum.
//
// Returns: Reason:
// ippStsNullPtrErr pA == NULL
// pB == NULL
// pR == NULL
// ippStsContextMatchErr BN_VALID_ID(pA)
// BN_VALID_ID(pB)
// BN_VALID_ID(pR)
// ippStsOutOfRangeErr pR can not hold result
// ippStsNoErr no errors
//
// Parameters:
// pA source BigNum
// pB source BigNum
// pR resultant BigNum
//
*F*/
IPPFUN(IppStatus, ippsAdd_BN, (IppsBigNumState* pA, IppsBigNumState* pB, IppsBigNumState* pR))
{
IPP_BAD_PTR3_RET(pA, pB, pR);
pA = (IppsBigNumState*)( IPP_ALIGNED_PTR(pA, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pA), ippStsContextMatchErr);
pB = (IppsBigNumState*)( IPP_ALIGNED_PTR(pB, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pB), ippStsContextMatchErr);
pR = (IppsBigNumState*)( IPP_ALIGNED_PTR(pR, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pR), ippStsContextMatchErr);
{
cpSize nsA = BN_SIZE(pA);
cpSize nsB = BN_SIZE(pB);
cpSize nsR = BN_ROOM(pR);
IPP_BADARG_RET(nsR < IPP_MAX(nsA, nsB), ippStsOutOfRangeErr);
{
BNU_CHUNK_T* pDataR = BN_NUMBER(pR);
IppsBigNumSGN sgnA = BN_SIGN(pA);
IppsBigNumSGN sgnB = BN_SIGN(pB);
BNU_CHUNK_T* pDataA = BN_NUMBER(pA);
BNU_CHUNK_T* pDataB = BN_NUMBER(pB);
BNU_CHUNK_T carry;
if(sgnA==sgnB) {
if(nsA < nsB) {
SWAP(nsA, nsB);
SWAP_PTR(BNU_CHUNK_T, pDataA, pDataB);
}
carry = cpAdd_BNU(pDataR, pDataA, pDataB, nsB);
if(nsA>nsB)
carry = cpInc_BNU(pDataR+nsB, pDataA+nsB, nsA-nsB, carry);
if(carry) {
if(nsR>nsA)
pDataR[nsA++] = carry;
else
IPP_ERROR_RET(ippStsOutOfRangeErr);
}
BN_SIGN(pR) = sgnA;
}
else {
int cmpRes = cpCmp_BNU(pDataA, nsA, pDataB, nsB);
if(0==cmpRes) {
pDataR[0] = 0;
BN_SIZE(pR) = 1;
BN_SIGN(pR) = ippBigNumPOS;
return ippStsNoErr;
}
if(0>cmpRes) {
SWAP(nsA, nsB);
SWAP_PTR(BNU_CHUNK_T, pDataA, pDataB);
}
carry = cpSub_BNU(pDataR, pDataA, pDataB, nsB);
if(nsA>nsB)
cpDec_BNU(pDataR+nsB, pDataA+nsB, nsA-nsB, carry);
BN_SIGN(pR) = cmpRes>0? sgnA : INVERSE_SIGN(sgnA);
}
FIX_BNU(pDataR, nsA);
BN_SIZE(pR) = nsA;
return ippStsNoErr;
}
}
}
/*F*
// Name: ippsSub_BN
//
// Purpose: Subtcrac BigNum.
//
// Returns: Reason:
// ippStsNullPtrErr pA == NULL
// pB == NULL
// pR == NULL
// ippStsContextMatchErr BN_VALID_ID(pA)
// BN_VALID_ID(pB)
// BN_VALID_ID(pR)
// ippStsOutOfRangeErr pR can not hold result
// ippStsNoErr no errors
//
// Parameters:
// pA source BigNum
// pB source BigNum
// pR resultant BigNum
//
*F*/
IPPFUN(IppStatus, ippsSub_BN, (IppsBigNumState* pA, IppsBigNumState* pB, IppsBigNumState* pR))
{
IPP_BAD_PTR3_RET(pA, pB, pR);
pA = (IppsBigNumState*)( IPP_ALIGNED_PTR(pA, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pA), ippStsContextMatchErr);
pB = (IppsBigNumState*)( IPP_ALIGNED_PTR(pB, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pB), ippStsContextMatchErr);
pR = (IppsBigNumState*)( IPP_ALIGNED_PTR(pR, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pR), ippStsContextMatchErr);
{
cpSize nsA = BN_SIZE(pA);
cpSize nsB = BN_SIZE(pB);
cpSize nsR = BN_ROOM(pR);
IPP_BADARG_RET(nsR < IPP_MAX(nsA, nsB), ippStsOutOfRangeErr);
{
BNU_CHUNK_T* pDataR = BN_NUMBER(pR);
IppsBigNumSGN sgnA = BN_SIGN(pA);
IppsBigNumSGN sgnB = BN_SIGN(pB);
BNU_CHUNK_T* pDataA = BN_NUMBER(pA);
BNU_CHUNK_T* pDataB = BN_NUMBER(pB);
BNU_CHUNK_T carry;
if(sgnA!=sgnB) {
if(nsA < nsB) {
SWAP(nsA, nsB);
SWAP_PTR(BNU_CHUNK_T, pDataA, pDataB);
}
carry = cpAdd_BNU(pDataR, pDataA, pDataB, nsB);
if(nsA>nsB)
carry = cpInc_BNU(pDataR+nsB, pDataA+nsB, nsA-nsB, carry);
if(carry) {
if(nsR > nsA)
pDataR[nsA++] = carry;
else
IPP_ERROR_RET(ippStsOutOfRangeErr);
}
BN_SIGN(pR) = sgnA;
}
else {
int cmpRes= cpCmp_BNU(pDataA, nsA, pDataB, nsB);
if(0==cmpRes) {
ZEXPAND_BNU(pDataR,0, nsR);
BN_SIZE(pR) = 1;
BN_SIGN(pR) = ippBigNumPOS;
return ippStsNoErr;
}
if(0>cmpRes) {
SWAP(nsA, nsB);
SWAP_PTR(BNU_CHUNK_T, pDataA, pDataB);
}
carry = cpSub_BNU(pDataR, pDataA, pDataB, nsB);
if(nsA>nsB)
cpDec_BNU(pDataR+nsB, pDataA+nsB, nsA-nsB, carry);
BN_SIGN(pR) = cmpRes>0? sgnA : INVERSE_SIGN(sgnA);
}
FIX_BNU(pDataR, nsA);
BN_SIZE(pR) = nsA;
return ippStsNoErr;
}
}
}
/*F*
// Name: ippsMul_BN
//
// Purpose: Multiply BigNum.
//
// Returns: Reason:
// ippStsNullPtrErr pA == NULL
// pB == NULL
// pR == NULL
// ippStsContextMatchErr BN_VALID_ID(pA)
// BN_VALID_ID(pB)
// BN_VALID_ID(pR)
// ippStsOutOfRangeErr pR can not hold result
// ippStsNoErr no errors
//
// Parameters:
// pA source BigNum
// pB source BigNum
// pR resultant BigNum
//
*F*/
IPPFUN(IppStatus, ippsMul_BN, (IppsBigNumState* pA, IppsBigNumState* pB, IppsBigNumState* pR))
{
IPP_BAD_PTR3_RET(pA, pB, pR);
pA = (IppsBigNumState*)( IPP_ALIGNED_PTR(pA, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pA), ippStsContextMatchErr);
pB = (IppsBigNumState*)( IPP_ALIGNED_PTR(pB, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pB), ippStsContextMatchErr);
pR = (IppsBigNumState*)( IPP_ALIGNED_PTR(pR, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pR), ippStsContextMatchErr);
{
BNU_CHUNK_T* pDataA = BN_NUMBER(pA);
BNU_CHUNK_T* pDataB = BN_NUMBER(pB);
BNU_CHUNK_T* pDataR = BN_NUMBER(pR);
cpSize nsA = BN_SIZE(pA);
cpSize nsB = BN_SIZE(pB);
cpSize nsR = BN_ROOM(pR);
cpSize bitSizeA = BITSIZE_BNU(pDataA, nsA);
cpSize bitSizeB = BITSIZE_BNU(pDataB, nsB);
/* test if multiplicant/multiplier is zero */
if(!bitSizeA || !bitSizeB) {
BN_SIZE(pR) = 1;
BN_SIGN(pR) = IppsBigNumPOS;
pDataR[0] = 0;
return ippStsNoErr;
}
/* test if even low estimation of product A*B exceeded */
IPP_BADARG_RET(nsR*BNU_CHUNK_BITS < (bitSizeA+bitSizeB-1), ippStsOutOfRangeErr);
{
BNU_CHUNK_T* aData = pDataA;
BNU_CHUNK_T* bData = pDataB;
if(pA == pR) {
aData = BN_BUFFER(pR);
COPY_BNU(aData, pDataA, nsA);
}
if((pB == pR) && (pA != pB)) {
bData = BN_BUFFER(pR);
COPY_BNU(bData, pDataB, nsB);
}
/* clear result */
ZEXPAND_BNU(pDataR, 0, nsR+1);
if(pA==pB)
cpSqr_BNU_school(pDataR, aData, nsA);
else
cpMul_BNU_school(pDataR, aData, nsA, bData, nsB);
nsR = (bitSizeA + bitSizeB + BNU_CHUNK_BITS - 1) /BNU_CHUNK_BITS;
FIX_BNU(pDataR, nsR);
IPP_BADARG_RET(nsR>BN_ROOM(pR), ippStsOutOfRangeErr);
BN_SIZE(pR) = nsR;
BN_SIGN(pR) = (BN_SIGN(pA)==BN_SIGN(pB)? ippBigNumPOS : ippBigNumNEG);
return ippStsNoErr;
}
}
}
/*F*
// Name: ippsMAC_BN_I
//
// Purpose: Multiply and Accumulate BigNum.
//
// Returns: Reason:
// ippStsNullPtrErr pA == NULL
// pB == NULL
// pR == NULL
// ippStsContextMatchErr BN_VALID_ID(pA)
// BN_VALID_ID(pB)
// BN_VALID_ID(pR)
// ippStsOutOfRangeErr pR can not fit result
// ippStsNoErr no errors
//
// Parameters:
// pA source BigNum
// pB source BigNum
// pR resultant BigNum
//
*F*/
IPPFUN(IppStatus, ippsMAC_BN_I, (IppsBigNumState* pA, IppsBigNumState* pB, IppsBigNumState* pR))
{
IPP_BAD_PTR3_RET(pA, pB, pR);
pA = (IppsBigNumState*)( IPP_ALIGNED_PTR(pA, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pA), ippStsContextMatchErr);
pB = (IppsBigNumState*)( IPP_ALIGNED_PTR(pB, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pB), ippStsContextMatchErr);
pR = (IppsBigNumState*)( IPP_ALIGNED_PTR(pR, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pR), ippStsContextMatchErr);
{
BNU_CHUNK_T* pDataA = BN_NUMBER(pA);
BNU_CHUNK_T* pDataB = BN_NUMBER(pB);
cpSize nsA = BN_SIZE(pA);
cpSize nsB = BN_SIZE(pB);
cpSize bitSizeA = BITSIZE_BNU(pDataA, nsA);
cpSize bitSizeB = BITSIZE_BNU(pDataB, nsB);
/* size of temporary pruduct */
cpSize nsP = BITS_BNU_CHUNK(bitSizeA+bitSizeB);
/* test if multiplicant/multiplier is zero */
if(!bitSizeA || !bitSizeB) return ippStsNoErr;
/* test if product can't fit to the result */
IPP_BADARG_RET(BN_ROOM(pR)<nsP, ippStsOutOfRangeErr);
{
BNU_CHUNK_T* pDataR = BN_NUMBER(pR);
IppsBigNumSGN sgnR = BN_SIGN(pR);
cpSize nsR = BN_SIZE(pR);
cpSize room = BN_ROOM(pR);
/* temporary product */
BNU_CHUNK_T* pDataP = BN_BUFFER(pR);
IppsBigNumSGN sgnP = BN_SIGN(pA)==BN_SIGN(pB)? ippBigNumPOS : ippBigNumNEG;
/* clear the rest of R data buffer */
ZEXPAND_BNU(pDataR, nsR, room);
/* temporary product */
if(pA==pB)
cpSqr_BNU_school(pDataP, pDataA, nsA);
else
cpMul_BNU_school(pDataP, pDataA, nsA, pDataB, nsB);
/* clear the rest of rpoduct */
ZEXPAND_BNU(pDataP, nsP, room);
if(sgnR==sgnP) {
BNU_CHUNK_T carry = cpAdd_BNU(pDataR, pDataR, pDataP, room);
if(carry) {
BN_SIZE(pR) = room;
IPP_ERROR_RET(ippStsOutOfRangeErr);
}
}
else {
BNU_CHUNK_T* pTmp = pDataR;
int cmpRes = cpCmp_BNU(pDataR, room, pDataP, room);
if(0>cmpRes) {
SWAP_PTR(BNU_CHUNK_T, pTmp, pDataP);
}
cpSub_BNU(pDataR, pTmp, pDataP, room);
BN_SIGN(pR) = cmpRes>0? sgnR : INVERSE_SIGN(sgnR);
}
FIX_BNU(pDataR, room);
BN_SIZE(pR) = room;
return ippStsNoErr;
}
}
}
/*F*
// Name: ippsDiv_BN
//
// Purpose: Divide BigNum.
//
// Returns: Reason:
// ippStsNullPtrErr pA == NULL
// pB == NULL
// pQ == NULL
// pR == NULL
// ippStsContextMatchErr BN_VALID_ID(pA)
// BN_VALID_ID(pB)
// BN_VALID_ID(pQ)
// BN_VALID_ID(pR)
// ippStsOutOfRangeErr pQ and/or pR can not hold result
// ippStsNoErr no errors
//
// Parameters:
// pA source BigNum
// pB source BigNum
// pQ quotient BigNum
// pR reminder BigNum
//
// A = Q*B + R, 0 <= val(R) < val(B), sgn(A)==sgn(R)
//
*F*/
IPPFUN(IppStatus, ippsDiv_BN, (IppsBigNumState* pA, IppsBigNumState* pB, IppsBigNumState* pQ, IppsBigNumState* pR))
{
IPP_BAD_PTR4_RET(pA, pB, pQ, pR);
pA = (IppsBigNumState*)( IPP_ALIGNED_PTR(pA, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pA), ippStsContextMatchErr);
pB = (IppsBigNumState*)( IPP_ALIGNED_PTR(pB, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pB), ippStsContextMatchErr);
pQ = (IppsBigNumState*)( IPP_ALIGNED_PTR(pQ, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pQ), ippStsContextMatchErr);
pR = (IppsBigNumState*)( IPP_ALIGNED_PTR(pR, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pR), ippStsContextMatchErr);
IPP_BADARG_RET(BN_SIZE(pB)== 1 && BN_NUMBER(pB)[0]==0, ippStsDivByZeroErr);
IPP_BADARG_RET(BN_ROOM(pR)<BN_SIZE(pB), ippStsOutOfRangeErr);
IPP_BADARG_RET((int)BN_ROOM(pQ)<(int)(BN_SIZE(pA)-BN_SIZE(pB)), ippStsOutOfRangeErr);
{
BNU_CHUNK_T* pDataA = BN_BUFFER(pA);
cpSize nsA = BN_SIZE(pA);
BNU_CHUNK_T* pDataB = BN_NUMBER(pB);
cpSize nsB = BN_SIZE(pB);
BNU_CHUNK_T* pDataQ = BN_NUMBER(pQ);
cpSize nsQ;
BNU_CHUNK_T* pDataR = BN_NUMBER(pR);
cpSize nsR;
COPY_BNU(pDataA, BN_NUMBER(pA), nsA);
nsR = cpDiv_BNU(pDataQ, &nsQ, pDataA, nsA, pDataB, nsB);
COPY_BNU(pDataR, pDataA, nsR);
BN_SIGN(pQ) = BN_SIGN(pA)==BN_SIGN(pB)? ippBigNumPOS : ippBigNumNEG;
BN_SIZE(pQ) = nsQ;
if(nsQ==1 && pDataQ[0]==0) BN_SIGN(pQ) = ippBigNumPOS;
BN_SIGN(pR) = BN_SIGN(pA);
BN_SIZE(pR) = nsR;
if(nsR==1 && pDataR[0]==0) BN_SIGN(pR) = ippBigNumPOS;
return ippStsNoErr;
}
}
/*F*
// Name: ippsMod_BN
//
// Purpose: reduction BigNum.
//
// Returns: Reason:
// ippStsNullPtrErr pA == NULL
// pM == NULL
// pR == NULL
// ippStsContextMatchErr BN_VALID_ID(pA)
// BN_VALID_ID(pM)
// BN_VALID_ID(pR)
// ippStsOutOfRangeErr pR can not hold result
// ippStsNoErr no errors
//
// Parameters:
// pA source BigNum
// pB source BigNum
// pR reminder BigNum
//
// A = Q*M + R, 0 <= R < B
//
*F*/
IPPFUN(IppStatus, ippsMod_BN, (IppsBigNumState* pA, IppsBigNumState* pM, IppsBigNumState* pR))
{
IPP_BAD_PTR3_RET(pA, pM, pR);
pA = (IppsBigNumState*)( IPP_ALIGNED_PTR(pA, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pA), ippStsContextMatchErr);
pM = (IppsBigNumState*)( IPP_ALIGNED_PTR(pM, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pM), ippStsContextMatchErr);
pR = (IppsBigNumState*)( IPP_ALIGNED_PTR(pR, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pR), ippStsContextMatchErr);
IPP_BADARG_RET(BN_NEGATIVE(pM), ippStsBadModulusErr);
IPP_BADARG_RET(BN_SIZE(pM)== 1 && BN_NUMBER(pM)[0]==0, ippStsBadModulusErr);
IPP_BADARG_RET(BN_ROOM(pR)<BN_SIZE(pM), ippStsOutOfRangeErr);
if(cpEqu_BNU_CHUNK(BN_NUMBER(pA), BN_SIZE(pA), 0)) {
BN_SIGN(pR) = ippBigNumPOS;
BN_SIZE(pR) = 1;
BN_NUMBER(pR)[0] = 0;
}
else {
BNU_CHUNK_T* pDataM = BN_NUMBER(pM);
cpSize nsM = BN_SIZE(pM);
BNU_CHUNK_T* pBuffA = BN_BUFFER(pA);
cpSize nsA = BN_SIZE(pA);
BNU_CHUNK_T* pDataR = BN_NUMBER(pR);
cpSize nsR;
COPY_BNU(pBuffA, BN_NUMBER(pA), nsA);
nsR = cpMod_BNU(pBuffA, nsA, pDataM, nsM);
COPY_BNU(pDataR, pBuffA, nsR);
BN_SIZE(pR) = nsR;
BN_SIGN(pR) = ippBigNumPOS;
if(BN_NEGATIVE(pA) && !(nsR==1 && pDataR[0]==0)) {
ZEXPAND_BNU(pDataR, nsR, nsM);
cpSub_BNU(pDataR, pDataM, pDataR, nsM);
FIX_BNU(pDataR, nsM);
BN_SIZE(pR) = nsM;
}
}
return ippStsNoErr;
}
/*F*
// Name: ippsGcd_BN
//
// Purpose: compute GCD value.
//
// Returns: Reason:
// ippStsNullPtrErr pA == NULL
// pB == NULL
// pG == NULL
// ippStsContextMatchErr BN_VALID_ID(pA)
// BN_VALID_ID(pB)
// BN_VALID_ID(pG)
// ippStsBadArgErr A==B==0
// ippStsOutOfRangeErr pG can not hold result
// ippStsNoErr no errors
//
// Parameters:
// pA source BigNum
// pB source BigNum
// pG GCD value
//
*F*/
IPPFUN(IppStatus, ippsGcd_BN, (IppsBigNumState* pA, IppsBigNumState* pB, IppsBigNumState* pG))
{
IPP_BAD_PTR3_RET(pA, pB, pG);
pA = (IppsBigNumState*)(IPP_ALIGNED_PTR(pA, BN_ALIGNMENT));
pB = (IppsBigNumState*)(IPP_ALIGNED_PTR(pB, BN_ALIGNMENT));
pG = (IppsBigNumState*)(IPP_ALIGNED_PTR(pG, BN_ALIGNMENT));
IPP_BADARG_RET(!BN_VALID_ID(pA), ippStsContextMatchErr);
IPP_BADARG_RET(!BN_VALID_ID(pB), ippStsContextMatchErr);
IPP_BADARG_RET(!BN_VALID_ID(pG), ippStsContextMatchErr);
IPP_BADARG_RET(BN_ROOM(pG) < IPP_MIN(BN_SIZE(pA), BN_SIZE(pB)), ippStsOutOfRangeErr);
{
IppsBigNumState* x = pA;
IppsBigNumState* y = pB;
IppsBigNumState* g = pG;
int aIsZero = BN_SIZE(pA)==1 && BN_NUMBER(pA)[0]==0;
int bIsZero = BN_SIZE(pB)==1 && BN_NUMBER(pB)[0]==0;
if(aIsZero && bIsZero)
return ippStsBadArgErr;
if(aIsZero && !bIsZero) {
COPY_BNU(BN_NUMBER(g), BN_NUMBER(pB), BN_SIZE(pB));
BN_SIZE(g) = BN_SIZE(pB);
BN_SIGN(g) = ippBigNumPOS;
return ippStsNoErr;
}
if(bIsZero && !aIsZero) {
COPY_BNU(BN_NUMBER(g), BN_NUMBER(pA), BN_SIZE(pA));
BN_SIZE(g) = BN_SIZE(pA);
BN_SIGN(g) = ippBigNumPOS;
return ippStsNoErr;
}
/*
// Lehmer's algorithm requres that first number must be greater than second
// x is the first, y is the second
*/
{
int cmpRes = cpCmp_BNU(BN_NUMBER(x), BN_SIZE(x), BN_NUMBER(y), BN_SIZE(y));
if(0>cmpRes)
SWAP_PTR(IppsBigNumState, x, y);
if(0==cmpRes) {
COPY_BNU(BN_NUMBER(g), BN_NUMBER(x), BN_SIZE(x));
BN_SIGN(g) = ippBigNumPOS;
BN_SIZE(g) = BN_SIZE(x);
return ippStsNoErr;
}
if(BN_SIZE(x)==1) {
BNU_CHUNK_T gcd = cpGcd_BNU(BN_NUMBER(x)[0], BN_NUMBER(y)[0]);
BN_NUMBER(g)[0] = gcd;
BN_SIZE(g) = 1;
return ippStsNoErr;
}
}
{
Ipp32u* xBuffer = (Ipp32u*)BN_BUFFER(x);
Ipp32u* yBuffer = (Ipp32u*)BN_BUFFER(y);
Ipp32u* gBuffer = (Ipp32u*)BN_BUFFER(g);
Ipp32u* xData = (Ipp32u*)BN_NUMBER(x);
Ipp32u* yData = (Ipp32u*)BN_NUMBER(y);
Ipp32u* gData = (Ipp32u*)BN_NUMBER(g);
cpSize nsXmax = BN_ROOM(x)*(sizeof(BNU_CHUNK_T)/sizeof(Ipp32u));
cpSize nsYmax = BN_ROOM(y)*(sizeof(BNU_CHUNK_T)/sizeof(Ipp32u));
cpSize nsGmax = BN_ROOM(g)*(sizeof(BNU_CHUNK_T)/sizeof(Ipp32u));
cpSize nsX = BN_SIZE(x)*(sizeof(BNU_CHUNK_T)/sizeof(Ipp32u));
cpSize nsY = BN_SIZE(y)*(sizeof(BNU_CHUNK_T)/sizeof(Ipp32u));
Ipp32u* T;
Ipp32u* u;
FIX_BNU(xData, nsX);
FIX_BNU(yData, nsY);
/* init buffers */
ZEXPAND_COPY_BNU(xBuffer, nsXmax, xData, nsX);
ZEXPAND_COPY_BNU(yBuffer, nsYmax, yData, nsY);
T = gBuffer;
u = gData;
ZEXPAND_BNU(T, 0, nsGmax);
ZEXPAND_BNU(u, 0, nsGmax);
while(nsX > (cpSize)(sizeof(BNU_CHUNK_T)/sizeof(Ipp32u))) {
/* xx and yy is the high-order digits of x and y (yy could be 0) */
Ipp64u xx = (Ipp64u)(xBuffer[nsX-1]);
Ipp64u yy = (nsY < nsX)? 0 : (Ipp64u)(yBuffer[nsY-1]);
Ipp64s AA = 1;
Ipp64s BB = 0;
Ipp64s CC = 0;
Ipp64s DD = 1;
Ipp64s t;
while((yy+CC)!=0 && (yy+DD)!=0) {
Ipp64u q = ( xx + AA ) / ( yy + CC );
Ipp64u q1 = ( xx + BB ) / ( yy + DD );
if(q!=q1)
break;
t = AA - q*CC;
AA = CC;
CC = t;
t = BB - q*DD;
BB = DD;
DD = t;
t = xx - q*yy;
xx = yy;
yy = t;
}
if(BB == 0) {
/* T = x mod y */
cpSize nsT = cpMod_BNU32(xBuffer, nsX, yBuffer, nsY);
ZEXPAND_BNU(T, 0, nsGmax);
COPY_BNU(T, xBuffer, nsT);
/* a = b; b = T; */
ZEXPAND_BNU(xBuffer, 0, nsXmax);
COPY_BNU(xBuffer, yBuffer, nsY);
ZEXPAND_BNU(yBuffer, 0, nsYmax);
COPY_BNU(yBuffer, T, nsY);
}
else {
Ipp32u carry;
/*
// T = AA*x + BB*y;
// u = CC*x + DD*y;
// b = u; a = T;
*/
if((AA <= 0)&&(BB>=0)) {
Ipp32u a1 = (Ipp32u)(-AA);
carry = cpMulDgt_BNU32(T, yBuffer, nsY, (Ipp32u)BB);
carry = cpMulDgt_BNU32(u, xBuffer, nsY, a1);
/* T = BB*y - AA*x; */
carry = cpSub_BNU32(T, T, u, nsY);
}
else {
if((AA >= 0)&&(BB<=0)) {
Ipp32u b1 = (Ipp32u)(-BB);
carry = cpMulDgt_BNU32(T, xBuffer, nsY, (Ipp32u)AA);
carry = cpMulDgt_BNU32(u, yBuffer, nsY, b1);
/* T = AA*x - BB*y; */
carry = cpSub_BNU32(T, T, u, nsY);
}
else {
/*AA*BB>=0 */
carry = cpMulDgt_BNU32(T, xBuffer, nsY, (Ipp32u)AA);
carry = cpMulDgt_BNU32(u, yBuffer, nsY, (Ipp32u)BB);
/* T = AA*x + BB*y; */
carry = cpAdd_BNU32(T, T, u, nsY);
}
}
/* Now T is reserved. We use only u for intermediate results. */
if((CC <= 0)&&(DD>=0)){
Ipp32u c1 = (Ipp32u)(-CC);
/* u = x*CC; x = u; */
carry = cpMulDgt_BNU32(u, xBuffer, nsY, c1);
COPY_BNU(xBuffer, u, nsY);
/* u = y*DD; */
carry = cpMulDgt_BNU32(u, yBuffer, nsY, (Ipp32u)DD);
/* u = DD*y - CC*x; */
carry = cpSub_BNU32(u, u, xBuffer, nsY);
}
else {
if((CC >= 0)&&(DD<=0)){
Ipp32u d1 = (Ipp32u)(-DD);
/* u = y*DD; y = u */
carry = cpMulDgt_BNU32(u, yBuffer, nsY, d1);
COPY_BNU(yBuffer, u, nsY);
/* u = CC*x; */
carry = cpMulDgt_BNU32(u, xBuffer, nsY, (Ipp32u)CC);
/* u = CC*x - DD*y; */
carry = cpSub_BNU32(u, u, yBuffer, nsY);
}
else {
/*CC*DD>=0 */
/* y = y*DD */
carry = cpMulDgt_BNU32(u, yBuffer, nsY, (Ipp32u)DD);
COPY_BNU(yBuffer, u, nsY);
/* u = x*CC */
carry = cpMulDgt_BNU32(u, xBuffer, nsY, (Ipp32u)CC);
/* u = x*CC + y*DD */
carry = cpAdd_BNU32(u, u, yBuffer, nsY);
}
}
/* y = u; x = T; */
COPY_BNU(yBuffer, u, nsY);
COPY_BNU(xBuffer, T, nsY);
}
FIX_BNU(xBuffer, nsX);
FIX_BNU(yBuffer, nsY);
if (nsY > nsX) {
SWAP_PTR(IppsBigNumState, x, y);
SWAP(nsX, nsY);
}
if (nsY==1 && yBuffer[nsY-1]==0) {
/* End evaluation */
ZEXPAND_BNU(gData, 0, nsGmax);
COPY_BNU(gData, xBuffer, nsX);
BN_SIZE(g) = INTERNAL_BNU_LENGTH(nsX);
BN_SIGN(g) = ippBigNumPOS;
return ippStsNoErr;
}
}
BN_NUMBER(g)[0] = cpGcd_BNU(((BNU_CHUNK_T*)xBuffer)[0], ((BNU_CHUNK_T*)yBuffer)[0]);
BN_SIZE(g) = 1;
BN_SIGN(g) = ippBigNumPOS;
return ippStsNoErr;
}
}
}
/*F*
// Name: ippsModInv_BN
//
// Purpose: Multiplicative Inversion BigNum.
//
// Returns: Reason:
// ippStsNullPtrErr pA == NULL
// pM == NULL
// pR == NULL
// ippStsContextMatchErr BN_VALID_ID(pA)
// BN_VALID_ID(pM)
// BN_VALID_ID(pR)
// ippStsBadArgErr A<=0
// ippStsBadModulusErr M<=0
// ippStsScaleRangeErr A>=M
// ippStsOutOfRangeErr pR can not hold result
// ippStsNoErr no errors
// ippStsBadModulusErr inversion not found
//
// Parameters:
// pA source (value) BigNum
// pM source (modulus) BigNum
// pR reminder BigNum
//
*F*/
IPPFUN(IppStatus, ippsModInv_BN, (IppsBigNumState* pA, IppsBigNumState* pM, IppsBigNumState* pR) )
{
IPP_BAD_PTR3_RET(pA, pM, pR);
pA = (IppsBigNumState*)( IPP_ALIGNED_PTR(pA, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pA), ippStsContextMatchErr);
pM = (IppsBigNumState*)( IPP_ALIGNED_PTR(pM, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pM), ippStsContextMatchErr);
pR = (IppsBigNumState*)( IPP_ALIGNED_PTR(pR, BN_ALIGNMENT) );
IPP_BADARG_RET(!BN_VALID_ID(pR), ippStsContextMatchErr);
IPP_BADARG_RET(BN_ROOM(pR) < BN_SIZE(pM), ippStsOutOfRangeErr);
IPP_BADARG_RET(BN_NEGATIVE(pA) || (BN_SIZE(pA)==1 && BN_NUMBER(pA)[0]==0), ippStsBadArgErr);
IPP_BADARG_RET(BN_NEGATIVE(pM) || (BN_SIZE(pM)==1 && BN_NUMBER(pM)[0]==0), ippStsBadModulusErr);
IPP_BADARG_RET(cpCmp_BNU(BN_NUMBER(pA), BN_SIZE(pA), BN_NUMBER(pM), BN_SIZE(pM)) >= 0, ippStsScaleRangeErr);
{
cpSize nsR = cpModInv_BNU(BN_NUMBER(pR),
BN_NUMBER(pA), BN_SIZE(pA),
BN_NUMBER(pM), BN_SIZE(pM),
BN_BUFFER(pR), BN_BUFFER(pA), BN_BUFFER(pM));
if(nsR) {
BN_SIGN(pR) = ippBigNumPOS;
BN_SIZE(pR) = nsR;
return ippStsNoErr;
}
else
return ippStsBadModulusErr;
}
}