Kawe Mazidjatari b3a68ed095 Add EABase, EAThread and DirtySDK to R5sdk
DirtySDK (EA's Dirty Sockets library) will be used for the LiveAPI implementation, and depends on: EABase, EAThread.
2024-04-05 18:29:03 +02:00

1376 lines
41 KiB
C

/*H*************************************************************************************/
/*!
\File cryptbn.c
\Description
This module is implements big integer math needed for our cryptography
\Copyright
Copyright (c) Electronic Arts 2017. ALL RIGHTS RESERVED.
\Version 01/18/2017 (eesponda) First version split from CryptRSA
*/
/*************************************************************************************H*/
/*** Include files *********************************************************************/
#include <string.h>
#include "DirtySDK/dirtysock/dirtylib.h"
#include "DirtySDK/crypt/cryptbn.h"
/*** Private Functions *****************************************************************/
/*F*************************************************************************************/
/*!
\Function _CryptBnLzCnt
\Description
Implements the function to find the MSB
\Input uValue - the input we are finding the msb for
\Output
int32_t - the index of the MSB
\Notes
Uses BitScanReverse on PC as some processors that completely support
the lzcnt instruction.
Durango supports the lzcnt instruction so it can be used.
The remaining platforms use the builtin as it has been supported by gcc
for some time.
\Version 03/06/2017 (eesponda)
*/
/*************************************************************************************H*/
static int32_t _CryptBnLzCnt(ucrypt_t uValue)
{
#if defined(DIRTYCODE_PC)
unsigned long uResult;
#if UCRYPT_SIZE == 4
_BitScanReverse(&uResult, uValue);
#else
_BitScanReverse64(&uResult, uValue);
#endif
return(uResult + 1);
#elif defined(DIRTYCODE_XBOXONE) || defined(DIRTYCODE_GDK)
#if UCRYPT_SIZE == 4
return(UCRYPT_BITSIZE - __lzcnt(uValue));
#else
return(UCRYPT_BITSIZE - __lzcnt64(uValue));
#endif
#else
#if UCRYPT_SIZE == 4
return(UCRYPT_BITSIZE - __builtin_clz(uValue));
#elif DIRTYCODE_64BITPTR == 1
return(UCRYPT_BITSIZE - __builtin_clzl(uValue));
#else
return(UCRYPT_BITSIZE - __builtin_clzll(uValue));
#endif
#endif
}
/*F*************************************************************************************/
/*!
\Function _CryptBnExpand
\Description
Expands the width of the big number by one prepending an entry
\Input *pState - the big number
\Input uNewEntry - the entry we are adding
\Version 02/27/2017 (eesponda)
*/
/*************************************************************************************H*/
static void _CryptBnExpand(CryptBnT *pState, ucrypt_t uNewEntry)
{
if (pState->iWidth < CRYPTBN_MAX_WIDTH)
{
pState->aData[pState->iWidth++] = uNewEntry;
}
else
{
NetPrintf(("cryptbn: tried to increase the size of number's width past the max\n"));
}
}
/*F*************************************************************************************/
/*!
\Function _CryptBnShrink
\Description
Shrink until you find a non-zero entry or the width is one
\Input *pState - the big number
\Version 02/27/2017 (eesponda)
*/
/*************************************************************************************H*/
static void _CryptBnShrink(CryptBnT *pState)
{
int32_t iWidth = pState->iWidth;
while ((iWidth > 1) && (pState->aData[iWidth-1] == 0))
{
iWidth -= 1;
}
pState->iWidth = iWidth;
}
/*F*************************************************************************************/
/*!
\Function _CryptBnSet
\Description
Set an entry from the big number
\Input *pState - the big number
\Input iIndex - the index of the entry
\Input uValue - the entry value
\Notes
This helps us safely retrieve entries when the index is outside our bounds
\Version 02/27/2017 (eesponda)
*/
/*************************************************************************************H*/
static void _CryptBnSet(CryptBnT *pState, int32_t iIndex, ucrypt_t uValue)
{
if (iIndex < pState->iWidth)
{
pState->aData[iIndex] = uValue;
}
else if (iIndex < CRYPTBN_MAX_WIDTH)
{
pState->aData[iIndex] = uValue;
pState->iWidth = iIndex + 1;
}
}
/*F*************************************************************************************/
/*!
\Function _CryptBnIsZero
\Description
Checks if a big number is zero
\Input *pState - the big number
\Output
uint8_t - TRUE if zero, FALSE otherwise
\Version 02/17/2017 (eesponda)
*/
/*************************************************************************************H*/
static uint8_t _CryptBnIsZero(const CryptBnT *pState)
{
int32_t iWidth;
for (iWidth = pState->iWidth; iWidth > 0; iWidth -= 1)
{
if (pState->aData[iWidth-1] != 0)
{
return(FALSE);
}
}
return(TRUE);
}
/*F*************************************************************************************/
/*!
\Function _CryptBnIsEven
\Description
Checks if a big number is even
\Input *pState - the big number
\Output
uint8_t - TRUE if even, FALSE if odd
\Version 02/07/2018 (eesponda)
*/
/*************************************************************************************H*/
static uint8_t _CryptBnIsEven(const CryptBnT *pState)
{
// we only check the bottom limb
return((pState->aData[0] & 1) == 0);
}
/*F*************************************************************************************/
/*!
\Function _CryptBnAdd
\Description
Adds two big numbers together
\Input *pState - the result of the operation
\Input *pAdd1 - the left side
\Input *pAdd2 - the right side
\Version 02/17/2017 (eesponda)
*/
/*************************************************************************************H*/
static void _CryptBnAdd(CryptBnT *pState, const CryptBnT *pAdd1, const CryptBnT *pAdd2)
{
ucrypt_t uAccum;
int32_t iWidth = DS_MAX(pAdd1->iWidth, pAdd2->iWidth), iCount;
// do the add
for (uAccum = 0, iCount = 0; iCount < iWidth; iCount += 1)
{
ucrypt_t uResult = uAccum, uLhs = pAdd1->aData[iCount], uRhs = pAdd2->aData[iCount];
// do the math, setting carry on overflow
uAccum = ((uResult += uLhs) < uLhs);
uAccum |= ((uResult += uRhs) < uRhs);
// set the value
_CryptBnSet(pState, iCount, uResult);
}
if (uAccum != 0)
{
_CryptBnExpand(pState, uAccum);
}
}
/*F*************************************************************************************/
/*!
\Function _CryptBnSubtract
\Description
Subtracts two big numbers
\Input *pState - result of subtraction
\Input *pSub1 - the left hand side of the equation
\Input *pSub2 - the right hand side of the equation
\Version 02/17/2017 (eesponda)
*/
/*************************************************************************************H*/
static void _CryptBnSubtract(CryptBnT *pState, const CryptBnT *pSub1, const CryptBnT *pSub2)
{
ucrypt_t uAccum;
int32_t iWidth = DS_MAX(pSub1->iWidth, pSub2->iWidth), iCount;
for (uAccum = 0, iCount = 0; iCount < iWidth; iCount += 1)
{
ucrypt_t uResult, uFinalResult;
ucrypt_t uLhs = pSub1->aData[iCount], uRhs = pSub2->aData[iCount];
// calculate the result without borrow
uResult = uLhs - uRhs;
// calculate the result after borrow
uFinalResult = uResult - uAccum;
// calculate the new borrow if first or second calculation resulted in overflow
uAccum = (uResult > uLhs) | (uFinalResult > uResult);
// save result
_CryptBnSet(pState, iCount, uFinalResult);
}
}
/*** Public functions ******************************************************************/
/*F*************************************************************************************/
/*!
\Function CryptBnInit
\Description
Initializes the large number with zero at a given width
\Input *pState - pointer to output large number array of ucrypt_t units
\Input iWidth - width of output
\Version 01/18/2017 (eesponda)
*/
/*************************************************************************************H*/
void CryptBnInit(CryptBnT *pState, int32_t iWidth)
{
ds_memclr(pState, sizeof(*pState));
pState->iWidth = iWidth;
}
/*F*************************************************************************************/
/*!
\Function CryptBnInitSet
\Description
Initializes the large number with a number
\Input *pState - pointer to output large number array of ucrypt_t units
\Input uValue - value we are initializing the big number with
\Version 01/18/2017 (eesponda)
*/
/*************************************************************************************H*/
void CryptBnInitSet(CryptBnT *pState, uint32_t uValue)
{
ds_memclr(pState, sizeof(*pState));
pState->iWidth = 1;
pState->aData[0] = uValue;
}
/*F*************************************************************************************/
/*!
\Function CryptBnInitFrom
\Description
Convert from msb bytes to int32_t number format
\Input *pState - pointer to output large number array of ucrypt_t units
\Input iWidth - width of output - if negative, auto-calculate width
\Input *pSource - pointer to input large number array of bytes
\Input iLength - length of input in bytes
\Output
int32_t - width in ucrypt_t units
\Version 03/08/2002 (gschaefer)
\Version 03/03/2004 (sbevan) Handle odd iLength
*/
/*************************************************************************************H*/
int32_t CryptBnInitFrom(CryptBnT *pState, int32_t iWidth, const uint8_t *pSource, int32_t iLength)
{
ucrypt_t *pResult = pState->aData;
int32_t iFullWordCount = iLength/sizeof(*pResult);
int32_t iWordCount = (iLength+sizeof(*pResult)-1)/sizeof(*pResult);
// clear the contents
ds_memclr(pState, sizeof(*pState));
if (iWidth < 0)
{
iWidth = iWordCount;
}
pState->iWidth = iWidth;
if (iFullWordCount != iWordCount)
{
/* calculate how many bytes we need to write and
generate a left shift amount based on that */
int32_t iDiff = iLength - (iFullWordCount * UCRYPT_SIZE);
int32_t iLeftShiftAmount = (iDiff - 1) * 8;
// encode the bytes into the buffer until there is nothing left
while (iLeftShiftAmount >= 0)
{
pResult[iWidth - 1] |= ((ucrypt_t)*pSource++ << iLeftShiftAmount);
iLeftShiftAmount -= 8;
}
iWidth -= 1;
}
for (; iWidth > 0; iWidth -= 1)
{
#if (UCRYPT_SIZE == 4)
pResult[iWidth-1] = (pSource[0] << 24) | (pSource[1] << 16) | (pSource[2] << 8) | (pSource[3] << 0);
#else
pResult[iWidth-1] = ((ucrypt_t)pSource[0] << 56) | ((ucrypt_t)pSource[1] << 48) | ((ucrypt_t)pSource[2] << 40) | ((ucrypt_t)pSource[3] << 32) |
((ucrypt_t)pSource[4] << 24) | ((ucrypt_t)pSource[5] << 16) | ((ucrypt_t)pSource[6] << 8) | ((ucrypt_t)pSource[7] << 0);
#endif
pSource += UCRYPT_SIZE;
}
return(iWordCount);
}
/*F*************************************************************************************/
/*!
\Function CryptBnInitLeFrom
\Description
Convert the bytes into a big number in little-endian form
\Input *pState - pointer to output large number array of ucrypt_t units
\Input *pSource - pointer to input large number array of bytes
\Input iLength - length of input in bytes
\Output
int32_t - width in ucrypt_t units
\Version 04/11/2018 (eesponda)
*/
/*************************************************************************************H*/
int32_t CryptBnInitLeFrom(CryptBnT *pState, const uint8_t *pSource, int32_t iLength)
{
//int32_t iWidth;
ucrypt_t *pResult = pState->aData;
int32_t iWordCount = (iLength+sizeof(*pResult)-1)/sizeof(*pResult);
// clear the contents and init
ds_memclr(pState, sizeof(*pState));
pState->iWidth = iWordCount;
ds_memcpy_s(pState->aData, pState->iWidth*sizeof(*pState->aData), pSource, iLength);
return(iWordCount);
}
/*F*************************************************************************************/
/*!
\Function CryptBnLeftShift
\Description
Left shifts a large number by a bit
\Input *pState - pointer to input and output large number array
\Notes
pState:iWidth <-- pState:iWidth << 1
\Version 10/11/2011 (mdonais)
*/
/*************************************************************************************H*/
void CryptBnLeftShift(CryptBnT *pState)
{
ucrypt_t uAccum;
int32_t iWidth, iCount;
// do the shift
for (uAccum = 0, iCount = 0, iWidth = pState->iWidth; iCount < iWidth; iCount += 1)
{
ucrypt_t uResult, uFinalResult, uVal;
uVal = pState->aData[iCount];
uResult = uVal << 1;
uFinalResult = uResult + uAccum;
uAccum = (uResult < uVal);
pState->aData[iCount] = uFinalResult;
}
// expand if necessary
if (uAccum != 0)
{
_CryptBnExpand(pState, uAccum);
}
}
/*F*************************************************************************************/
/*!
\Function CryptBnLeftShift2
\Description
Left shifts a large number by a number of bits
\Input *pState - pointer to input and output large number array
\Input iBits - the number of bits to shift
\Notes
pState:iWidth <-- pState:iWidth << iBits
\Version 4/14/2017 (eesponda)
*/
/*************************************************************************************H*/
void CryptBnLeftShift2(CryptBnT *pState, int32_t iBits)
{
int32_t iOffset, iIndex;
const int32_t iBitLen = CryptBnBitLen(pState) + iBits;
/* make sure this shift would not exceed the width of the number
normally I would just set to zero but I need to indicate to the caller
that the output might not be what they expected */
if (iBitLen > CRYPTBN_MAX_BITS)
{
NetPrintf(("cryptbn: tried to left shift past the max width which will truncate all the data\n"));
return;
}
/* if we are trying to shift up one ucrypt_t unit or more
then calculate the number of ucrypt_t units and the number
of leftover bits we need to calculate */
if (iBits >= UCRYPT_BITSIZE)
{
iOffset = iBits / UCRYPT_BITSIZE;
iBits %= UCRYPT_BITSIZE;
/* shift the array to the right (left shift) the number of full ucrypt_t units (UCRYPT_BITSIZE)
clear the lower ucrypt_t units
update the width */
memmove(pState->aData+iOffset, pState->aData, pState->iWidth * sizeof(*pState->aData));
ds_memclr(pState->aData, iOffset * sizeof(*pState->aData));
pState->iWidth += iOffset;
// if there are no left over bits then we have nothing left to do
if (iBits == 0)
{
return;
}
}
// check if we past a ucrypt_t boundary and need to expand
if (iBitLen > pState->iWidth*UCRYPT_BITSIZE)
{
pState->iWidth += 1;
}
// shift the items in the array over manually
for (iIndex = pState->iWidth-1; iIndex > 0; iIndex -= 1)
{
pState->aData[iIndex] = (pState->aData[iIndex] << iBits) | (pState->aData[iIndex - 1] >> (UCRYPT_BITSIZE - iBits));
}
pState->aData[0] <<= iBits;
}
/*F*************************************************************************************/
/*!
\Function CryptBnRightShift2
\Description
Right shifts a large number by a number of bits
\Input *pState - pointer to input and output large number array
\Input iBits - the number of bits to shift
\Notes
pState:iWidth <-- pState:iWidth >> iBits
\Version 4/17/2017 (eesponda)
*/
/*************************************************************************************H*/
void CryptBnRightShift2(CryptBnT *pState, int32_t iBits)
{
int32_t iIndex;
/* if shifting right more than the bit length is the same
as setting to zero */
if (CryptBnBitLen(pState) <= iBits)
{
CryptBnInitSet(pState, 0);
return;
}
/* if we are trying to shift up one ucrypt_t unit or more
then calculate the number of ucrypt_t units and the number
of leftover bits we need to calculate */
if (iBits >= UCRYPT_BITSIZE)
{
int32_t iOffset = iBits / UCRYPT_BITSIZE;
iBits %= UCRYPT_BITSIZE;
/* shift the array to the left (right shift) the number of full ucrypt_t units (UCRYPT_BITSIZE)
update the width
clear the upper ucrypt_t units */
memmove(pState->aData, pState->aData+iOffset, (pState->iWidth-iOffset)*sizeof(*pState->aData));
pState->iWidth -= iOffset;
ds_memclr(pState->aData+pState->iWidth, iOffset*sizeof(*pState->aData));
// if there are no left over bits then we have nothing left to do
if (iBits == 0)
{
return;
}
}
// shift the items in the array over manually
for (iIndex = 0; iIndex < pState->iWidth-1; iIndex += 1)
{
pState->aData[iIndex] = (pState->aData[iIndex] >> iBits) | (pState->aData[iIndex + 1] << (UCRYPT_BITSIZE - iBits));
}
pState->aData[iIndex] >>= iBits;
/* check if we past a ucrypt_t boundary and need to shrink
if the number of bits is at or under the next boundary then shrink to there
we do not shrink under 1, as that is handled at the top of the function */
if ((pState->iWidth > 1) && (CryptBnBitLen(pState) <= ((pState->iWidth-1)*UCRYPT_BITSIZE)))
{
pState->iWidth -= 1;
}
}
/*F*************************************************************************************/
/*!
\Function CryptBnBitTest
\Description
Check to see if a particular bit is set within a large bit vector
\Input *pState - pointer to input bit vector
\Input iBit - bit number to test (zero-relative)
\Output
uint8_t - TRUE if set, else FALSE
\Notes
uResult <-- pValue:iWidth & (1 << iBit)
\Version 03/08/2002 (gschaefer)
*/
/*************************************************************************************H*/
uint8_t CryptBnBitTest(const CryptBnT *pState, int32_t iBit)
{
int32_t iBitOff = iBit & (UCRYPT_BITSIZE-1);
int32_t iOffset = iBit / UCRYPT_BITSIZE;
return((pState->aData[iOffset] & ((ucrypt_t)1 << iBitOff)) != 0);
}
/*F*************************************************************************************/
/*!
\Function CryptBnBitSet
\Description
Set a particular bit in the big number
\Input *pState - pointer to input bit vector
\Input iBit - bit number to set (zero-relative)
\Version 02/17/2017 (eesponda)
*/
/*************************************************************************************H*/
void CryptBnBitSet(CryptBnT *pState, int32_t iBit)
{
int32_t iBitOff, iOffset;
while (pState->iWidth*UCRYPT_BITSIZE <= iBit)
{
_CryptBnExpand(pState, 0);
}
iBitOff = iBit & (UCRYPT_BITSIZE - 1);
iOffset = iBit / UCRYPT_BITSIZE;
pState->aData[iOffset] |= ((ucrypt_t)1 << iBitOff);
}
/*F*************************************************************************************/
/*!
\Function CryptBnBitAnd
\Description
Performs bitwise and on two big numbers
\Input *pState - [out] output of the result of the operation
\Input *pLhs - big number on left hand side of operation
\Input *pRhs - big number on right hand side of operation
\Version 04/06/2018 (eesponda)
*/
/*************************************************************************************H*/
void CryptBnBitAnd(CryptBnT *pState, const CryptBnT *pLhs, const CryptBnT *pRhs)
{
int32_t iWidth = DS_MAX(pLhs->iWidth, pRhs->iWidth), iCount;
for (iCount = 0; iCount < iWidth; iCount += 1)
{
_CryptBnSet(pState, iCount, pLhs->aData[iCount] & pRhs->aData[iCount]);
}
// compact the big number in the case the operation zeroed out the upper limps
_CryptBnShrink(pState);
}
/*F*************************************************************************************/
/*!
\Function CryptBnBitXor
\Description
Performs bitwise xor on two big numbers
\Input *pState - [out] output of the result of the operation
\Input *pLhs - big number on left hand side of operation
\Input *pRhs - big number on right hand side of operation
\Version 04/06/2018 (eesponda)
*/
/*************************************************************************************H*/
void CryptBnBitXor(CryptBnT *pState, const CryptBnT *pLhs, const CryptBnT *pRhs)
{
int32_t iWidth = DS_MAX(pLhs->iWidth, pRhs->iWidth), iCount;
for (iCount = 0; iCount < iWidth; iCount += 1)
{
_CryptBnSet(pState, iCount, pLhs->aData[iCount] ^ pRhs->aData[iCount]);
}
// compact the big number in the case the operation zeroed out the upper limps
_CryptBnShrink(pState);
}
/*F*************************************************************************************/
/*!
\Function CryptBnBitLen
\Description
Figures out the bit length of big number
\Input *pState - big number state
\Output
int32_t - the number of bits in the big number
\Version 03/02/2017 (eesponda)
*/
/*************************************************************************************H*/
int32_t CryptBnBitLen(const CryptBnT *pState)
{
int32_t iResult, iIndex;
for (iResult = 0, iIndex = pState->iWidth - 1; iIndex >= 0; iIndex -= 1)
{
if (pState->aData[iIndex] != 0)
{
iResult = _CryptBnLzCnt(pState->aData[iIndex]);
break;
}
}
return(iResult > 0 ? iResult + (UCRYPT_BITSIZE * iIndex) : 0);
}
/*F*************************************************************************************/
/*!
\Function CryptBnByteLen
\Description
Figures out the byte length of big number
\Input *pState - big number state
\Output
int32_t - the number of bytes in the big number
\Version 03/13/2018 (eesponda)
*/
/*************************************************************************************H*/
int32_t CryptBnByteLen(const CryptBnT *pState)
{
return(pState->iWidth * (signed)sizeof(*pState->aData));
}
/*F*************************************************************************************/
/*!
\Function CryptBnModAdd
\Description
Adds to big numbers over a modulus
\Input *pState - big number state
\Input *pAdd1 - first big number to add
\Input *pAdd2 - second big number to add
\Input *pMod - modulus we are adding over
\Notes
This function does the redunction in a very simple way and isn't meant for
numbers very large over the modulus. We needed to make sure that if we use
the output for modulus multiply it would work under those constraints.
\Version 04/11/2018 (eesponda)
*/
/*************************************************************************************H*/
void CryptBnModAdd(CryptBnT *pState, const CryptBnT *pAdd1, const CryptBnT *pAdd2, const CryptBnT *pMod)
{
// do the addition
_CryptBnAdd(pState, pAdd1, pAdd2);
// reduce?
if (CryptBnCompare(pState, pMod) > 0)
{
CryptBnSubtract(pState, pState, pMod);
}
}
/*F*************************************************************************************/
/*!
\Function CryptBnAccumulate
\Description
Accumulate one large number into another
\Input *pState - pointer to large number accumulation buffer
\Input *pAdd - pointer to large number to accumulate to accumulation buffer
\Notes
pState:iWidth <-- pState:iWidth + pAdd:iWidth
\Version 02/17/2017 (eesponda)
*/
/*************************************************************************************H*/
void CryptBnAccumulate(CryptBnT *pState, const CryptBnT *pAdd)
{
if (pState->uSign == 0)
{
_CryptBnAdd(pState, pState, pAdd);
}
else
{
pState->uSign = 0;
CryptBnSubtract(pState, pAdd, pState);
}
}
/*F*************************************************************************************/
/*!
\Function CryptBnIncrement
\Description
Increment a large number by 1
\Input *pState - pointer to large number accumulation buffer
\Version 02/21/2017 (eesponda)
*/
/*************************************************************************************H*/
void CryptBnIncrement(CryptBnT *pState)
{
ucrypt_t uAccum;
int32_t iCount, iWidth;
// do the add
for (uAccum = 1, iCount = 0, iWidth = pState->iWidth; iCount < iWidth; iCount += 1)
{
ucrypt_t uResult = uAccum, uVal = pState->aData[iCount];
uAccum = ((uResult += uVal) < uVal);
pState->aData[iCount] = uResult;
// if we have nothing to carry over we are done
if (uAccum == 0)
{
break;
}
}
if (uAccum != 0)
{
_CryptBnExpand(pState, uAccum);
}
}
/*F*************************************************************************************/
/*!
\Function CryptBnSubtract
\Description
Subtract two large numbers
\Input *pState - pointer to output large number array
\Input *pSub1 - pointer to large number to subtract pSub2 from.
\Input *pSub2 - pointer to second large number
\Notes
pState:iWidth <-- pSub1:iWidth - pSub2:iWidth
\Version 02/17/2017 (eesponda)
*/
/*************************************************************************************H*/
void CryptBnSubtract(CryptBnT *pState, const CryptBnT *pSub1, const CryptBnT *pSub2)
{
// if sub1 - (-sub2) or -sub1 - (sub2) then sub1 + sub2, sign depends on which side is negative
if (pSub1->uSign ^ pSub2->uSign)
{
// add
_CryptBnAdd(pState, pSub1, pSub2);
// set sign
pState->uSign = pSub1->uSign;
}
// if -sub1 - (-sub2) or sub1 - sub2
else
{
const int32_t iCompare = CryptBnCompare(pSub1, pSub2);
// if sub1 > sub2
if (iCompare > 0)
{
// sub1 - sub2
_CryptBnSubtract(pState, pSub1, pSub2);
// set sign
pState->uSign = pSub1->uSign;
}
// else if sub1 < sub2
else if (iCompare < 0)
{
// sub2 - sub1
_CryptBnSubtract(pState, pSub2, pSub1);
// set sign
pState->uSign = ~pSub1->uSign;
}
// else they are the same so it is zero
else
{
CryptBnInitSet(pState, 0);
}
}
_CryptBnShrink(pState);
}
/*F*************************************************************************************/
/*!
\Function CryptBnDecrement
\Description
Decrement a large number by 1
\Input *pState - pointer to output large number array
\Version 02/21/2017 (eesponda)
*/
/*************************************************************************************H*/
void CryptBnDecrement(CryptBnT *pState)
{
ucrypt_t uAccum;
int32_t iWidth, iCount;
for (uAccum = 1, iCount = 0, iWidth = pState->iWidth; iCount < iWidth; iCount += 1)
{
ucrypt_t uResult, uVal = pState->aData[iCount];
// calculate the result after borrow
uResult = uVal - uAccum;
// calculate the new borrow if first or second calculation resulted in overflow
uAccum = (uResult > uVal);
// save result
_CryptBnSet(pState, iCount, uResult);
// if nothing left to borrow we are done
if (uAccum == 0)
{
break;
}
}
}
/*F*************************************************************************************/
/*!
\Function CryptBnModMultiply
\Description
Modular multiply using the classical algorithm
\Input *pState - pointer to output large number array
\Input *pMul1 - pointer to large number to multiply with pMul2
\Input *pMul2 - pointer to second large number
\Input *pMod - pointer to modulous large number
\Notes
pState:iWidth <-- pMul1:iWidth * pMul2:iWidth % pMod:iWidth
\Version 02/27/2002 (eesponda)
*/
/*************************************************************************************H*/
void CryptBnModMultiply(CryptBnT *pState, const CryptBnT *pMul1, const CryptBnT *pMul2, const CryptBnT *pMod)
{
int32_t iCount;
CryptBnT Temp1;
CryptBnT *pCur = &Temp1;
uint32_t uSign = pMul2->uSign ^ pMul1->uSign;
CryptBnInit(pCur, pMul1->iWidth);
// do all the bits
for (iCount = CryptBnBitLen(pMul1) - 1; iCount >= 0; iCount -= 1)
{
// left shift the result
CryptBnLeftShift(pCur);
// do modulus reduction?
if (CryptBnCompare(pCur, pMod) > 0)
{
CryptBnSubtract(pCur, pCur, pMod);
}
// see if we need to add in multiplicand
if (CryptBnBitTest(pMul1, iCount))
{
// add it in
CryptBnAccumulate(pCur, pMul2);
// do modulus reduction?
if (CryptBnCompare(pCur, pMod) > 0)
{
CryptBnSubtract(pCur, pCur, pMod);
}
}
}
// deal with going negative
if (uSign != 0)
{
CryptBnSubtract(pCur, pMod, pCur);
}
// copy over the result
CryptBnClone(pState, pCur);
}
/*F*************************************************************************************/
/*!
\Function CryptBnMultiply
\Description
Performs multiplication of two big numbers using the classical method
\Input *pState - pointer to output large number array
\Input *pMul1 - pointer to large number to multiply with pMul2
\Input *pMul2 - pointer to second large number
\Notes
pState:iWidth <-- pMul1:iWidth * pMul2:iWidth
\Version 02/28/2017 (eesponda)
*/
/*************************************************************************************H*/
void CryptBnMultiply(CryptBnT *pState, const CryptBnT *pMul1, const CryptBnT *pMul2)
{
int32_t iCount;
CryptBnT Temp1;
CryptBnT *pCur = &Temp1;
CryptBnInit(pCur, pMul1->iWidth);
// do all the bits
for (iCount = CryptBnBitLen(pMul1) - 1; iCount >= 0; iCount -= 1)
{
// left shift the result
CryptBnLeftShift(pCur);
// see if we need to add in multiplicand
if (CryptBnBitTest(pMul1, iCount))
{
// add it in
CryptBnAccumulate(pCur, pMul2);
}
}
pCur->uSign = pMul1->uSign ^ pMul2->uSign;
// copy over the result
CryptBnClone(pState, pCur);
}
/*F*************************************************************************************/
/*!
\Function CryptBnMod
\Description
Performs modulo / divison of dividend by divisor
\Input *pDividend - the dividend in the equation
\Input *pDivisor - the divisor in the equation
\Input *pRemainder - [out] the result of the modulo operation can be NULL
\Input *pQuotient - [out] the result of the division operation can be NULL
\Version 02/17/2017 (eesponda)
*/
/*************************************************************************************H*/
void CryptBnMod(const CryptBnT *pDividend, const CryptBnT *pDivisor, CryptBnT *pRemainder, CryptBnT *pQuotient)
{
int32_t iCount;
CryptBnT Result, Quotient;
/* if the dividend is less than the divisor means the result of
the modulus is the dividend and the quotient is zero */
const int32_t iCompare = CryptBnCompare(pDividend, pDivisor);
if (iCompare < 0)
{
CryptBnClone(&Result, pDividend);
CryptBnInitSet(&Quotient, 0);
}
else if (iCompare > 0)
{
CryptBnInitSet(&Result, 0);
CryptBnInitSet(&Quotient, 0);
/* since we don't need to perform the other operations until we increment
past zero, lets do this in a loop before we move onto the normal flow */
for (iCount = CryptBnBitLen(pDividend) - 1; iCount >= 0; iCount -= 1)
{
if (CryptBnBitTest(pDividend, iCount))
{
CryptBnIncrement(&Result);
CryptBnLeftShift(&Result);
break;
}
}
for (iCount = iCount - 1; iCount >= 0; iCount -= 1)
{
if (CryptBnBitTest(pDividend, iCount))
{
CryptBnIncrement(&Result);
}
// check if we need to reduce, we can bypass when the limbs don't match
if ((Result.iWidth >= pDivisor->iWidth) && (CryptBnCompare(&Result, pDivisor) >= 0))
{
CryptBnSubtract(&Result, &Result, pDivisor);
CryptBnBitSet(&Quotient, iCount);
}
if (iCount > 0)
{
CryptBnLeftShift(&Result);
}
}
}
else
{
CryptBnInitSet(&Result, 0);
CryptBnInitSet(&Quotient, 1);
}
if ((pDividend->uSign != 0) && (CryptBnBitLen(&Result) != 0))
{
Result.uSign = 0;
CryptBnSubtract(&Result, pDivisor, &Result);
}
if (pRemainder != NULL)
{
CryptBnClone(pRemainder, &Result);
}
if (pQuotient != NULL)
{
CryptBnClone(pQuotient, &Quotient);
}
}
/*F*************************************************************************************/
/*!
\Function CryptBnInverseMod
\Description
Calculates the modular multiplicative inverse using binary extended gcd
\Input *pState - the big number state
\Input *pMod - the modulus
\Notes
See Handbook of Applied Cryptography Chapter 14.4.3 (14.61)
http://cacr.uwaterloo.ca/hac/about/chap14.pdf
\Version 02/17/2017 (eesponda)
*/
/*************************************************************************************H*/
void CryptBnInverseMod(CryptBnT *pState, const CryptBnT *pMod)
{
int32_t iShift;
CryptBnT U, V, A, B, C, D;
// if the number is negative then switch the sign and subtract the result from mod
if (pState->uSign != 0)
{
pState->uSign = 0;
CryptBnInverseMod(pState, pMod);
CryptBnSubtract(pState, pMod, pState);
return;
}
CryptBnClone(&U, pState);
CryptBnClone(&V, pMod);
CryptBnInitSet(&A, 1);
CryptBnInitSet(&B, 0);
CryptBnInitSet(&C, 0);
CryptBnInitSet(&D, 1);
// while u and v are even divide by zero, accounting for the number of shifts
for (iShift = 0; (_CryptBnIsEven(&U) && _CryptBnIsEven(&V)); iShift += 1)
{
CryptBnRightShift(&U);
CryptBnRightShift(&V);
}
// quit out when u is zero
while (!_CryptBnIsZero(&U))
{
// while u is even
while (_CryptBnIsEven(&U))
{
// u <- u/2
CryptBnRightShift(&U);
/* if a congruent to b congruent to 0 mod 2 (they are both even)
then a <- a/2 and b <- b/2 */
if (_CryptBnIsEven(&A) && _CryptBnIsEven(&B))
{
CryptBnRightShift(&A);
CryptBnRightShift(&B);
}
// else a <- (a+y)/2 and b <- (b-x)/2
else
{
CryptBnAccumulate(&A, pMod);
CryptBnRightShift(&A);
CryptBnSubtract(&B, &B, pState);
CryptBnRightShift(&B);
}
}
// while v is even
while (_CryptBnIsEven(&V))
{
// v <- v/2
CryptBnRightShift(&V);
/* if c congruent to d congruent to 0 mod 2 (they are both even)
then c <- c/2 and d <- d/2 */
if (_CryptBnIsEven(&C) && _CryptBnIsEven(&D))
{
CryptBnRightShift(&C);
CryptBnRightShift(&D);
}
// else c <- (c+y)/2 and d <- (d-x)/2
else
{
CryptBnAccumulate(&C, pMod);
CryptBnRightShift(&C);
CryptBnSubtract(&D, &D, pState);
CryptBnRightShift(&D);
}
}
// if u > v then u <- u-v, a <- a-c and b <- b-d
if (CryptBnCompare(&U, &V) >= 0)
{
CryptBnSubtract(&U, &U, &V);
CryptBnSubtract(&A, &A, &C);
CryptBnSubtract(&B, &B, &D);
}
// else v <- v-u, c <- c-a and d <- d-b
else
{
CryptBnSubtract(&V, &V, &U);
CryptBnSubtract(&C, &C, &A);
CryptBnSubtract(&D, &D, &B);
}
}
// a <- C, b <- D but we only need a for the inverse so return that
CryptBnClone(pState, &C);
/* note: if you needed to return v, you would need to left shift by iShift
but since we don't we don't do anything else */
}
/*F*************************************************************************************/
/*!
\Function CryptBnFinal
\Description
Convert from ucrypt_t units back to big-endian bytes
\Input *pState - the ucrypt_t units to convert
\Input *pResult - where to write the 8-bit result.
\Input iLength - size of the result array in bytes.
\Version 03/08/2002 (gschaefer)
*/
/*************************************************************************************H*/
void CryptBnFinal(const CryptBnT *pState, uint8_t *pResult, int32_t iLength)
{
const ucrypt_t *pSource = pState->aData;
// make the length in terms of words
iLength /= sizeof(*pSource);
// word to byte conversion
for (; iLength > 0; iLength -= 1)
{
#if UCRYPT_SIZE > 4
*pResult++ = (uint8_t)(pSource[iLength-1] >> 56);
*pResult++ = (uint8_t)(pSource[iLength-1] >> 48);
*pResult++ = (uint8_t)(pSource[iLength-1] >> 40);
*pResult++ = (uint8_t)(pSource[iLength-1] >> 32);
#endif
*pResult++ = (uint8_t)(pSource[iLength-1] >> 24);
*pResult++ = (uint8_t)(pSource[iLength-1] >> 16);
*pResult++ = (uint8_t)(pSource[iLength-1] >> 8);
*pResult++ = (uint8_t)(pSource[iLength-1]);
}
}
/*F*************************************************************************************/
/*!
\Function CryptBnFinalLe
\Description
Convert from ucrypt_t units back to little-endian bytes
\Input *pState - the ucrypt_t units to convert
\Input *pResult - where to write the 8-bit result.
\Input iLength - size of the result array in bytes.
\Version 04/11/2018 (eesponda)
*/
/*************************************************************************************H*/
void CryptBnFinalLe(const CryptBnT *pState, uint8_t *pResult, int32_t iLength)
{
ds_memcpy_s(pResult, iLength, pState->aData, CryptBnByteLen(pState));
}
/*F*************************************************************************************/
/*!
\Function CryptBnClone
\Description
Copies a big number's contents
\Input *pDst - where we are copying to
\Input *pSrc - where we are copying from
\Version 02/27/2017 (eesponda)
*/
/*************************************************************************************H*/
void CryptBnClone(CryptBnT *pDst, const CryptBnT *pSrc)
{
ds_memcpy(pDst, pSrc, sizeof(*pDst));
}
/*F*************************************************************************************/
/*!
\Function CryptBnPrint
\Description
Prints the contents of a big number
\Input *pState - the big number we are printing
\Input *pTitle - title of the big number
\Version 02/06/2018 (eesponda)
*/
/*************************************************************************************H*/
void CryptBnPrint(const CryptBnT *pState, const char *pTitle)
{
#if DIRTYCODE_LOGGING
int32_t iIndex, iOffset;
char strNumber[16*CRYPTBN_MAX_WIDTH];
const char *pPrefix = (pState->uSign == 0) ? "0x" : "-0x";
for (iIndex = pState->iWidth, iOffset = 0; iIndex > 0; iIndex -= 1)
{
iOffset += ds_snzprintf(strNumber+iOffset, sizeof(strNumber)-iOffset, "%016llx", pState->aData[iIndex - 1]);
}
NetPrintf(("cryptbn: %s %s%s (%d)\n", pTitle, pPrefix, strNumber, CryptBnBitLen(pState)));
#endif
}
/*F*************************************************************************************/
/*!
\Function CryptBnCompare
\Description
Compare two big numbers together
\Input *pLhs - the left side
\Input *pRhs - the right side
\Output
int32_t - 0=equal, >0=left side larger, <0=right side larger
\Version 02/17/2017 (eesponda)
*/
/*************************************************************************************H*/
int32_t CryptBnCompare(const CryptBnT *pLhs, const CryptBnT *pRhs)
{
int32_t iWidth;
for (iWidth = DS_MAX(pLhs->iWidth, pRhs->iWidth); iWidth > 0; iWidth -= 1)
{
ucrypt_t uLhs = pLhs->aData[iWidth - 1], uRhs = pRhs->aData[iWidth - 1];
if (uLhs == uRhs)
{
continue;
}
return((uLhs > uRhs) ? 1 : -1);
}
return(0);
}