/******************************************************************************* Function: void BIGINT_Multiply(BIGINT_DATA*result, BIGINT_DATA *arg1, BIGINT_DATA *arg2 ) Summary: Big Integer multiplication routine. Description: This function performs the multiplication of A and B and saves it in C. result=arg1*arg2; Precondition: result is initialized to all zeros. Parameters: Pointers to the operands and the result Returns: None. Example: <code> void BigIntMultiply(res,arg1,arg2); </code> Remarks: Only Little Endianness is supported.If the operands are not in the Little Endian format, They need to be changed to Little-Endianness format. *****************************************************************************/ BIGINT_RESULT BIGINT_Multiply(BIGINT_DATA *result, BIGINT_DATA *arg1, BIGINT_DATA *arg2) { BIGINT_DATA_TYPE * a, *b; a = BigIntMSB(arg1); b = BigIntMSB(arg2); if ((result->bLength) < ((a - (uint16_t *)arg1->startAddress) + (b - (uint16_t *)arg2->startAddress) + 2)) return BIGINT_RESULT_RESULT_BUFFER_LENGTH_INSUFFICIENT; BIGINT_Set(result,0x00); // clear res before performing multiplication _mulBI(arg1, arg2, result); // Perform the multiplication return BIGINT_RESULT_OK; }
void BigIntMultiply(BIGINT *a, BIGINT *b, BIGINT *res) { // Clear out the result BigIntZero(res); // Load the start and stop pointers _iA = a->ptrLSB; _xA = BigIntMSB(a); _iB = b->ptrLSB; _xB = BigIntMSB(b); _iR = res->ptrLSB; // Perform the multiplication mulBI(); // Invalidate the MSB ptr res->bMSBValid = 0; }
/********************************************************************* * Function: CHAR BIGINT_Compare(BIGINTGINT *a, BIGINTGINT *b) * * PreCondition: None * * Input: *a: a pointer to the first number * *b: a pointer to the second number * * Output: 0 if a == b * 1 if a > b * -1 if a < b * * Side Effects: None * * Overview: Determines if a > b, a < b, or a == b * * Note: Supports at least 2048 bits. * ********************************************************************/ int BIGINT_Compare(BIGINT_DATA *a, BIGINT_DATA *b) { uint32_t magA, magB; BIGINT_DATA_TYPE valA, valB; BIGINT_DATA_TYPE *ptrA; BIGINT_DATA_TYPE *ptrB; magA = BigIntMSB(a) - (BIGINT_DATA_TYPE *)a->startAddress; magB = BigIntMSB(b) - (BIGINT_DATA_TYPE *)b->startAddress; if(magA > magB) { return 1; } else if(magA < magB) { return -1; } // Loop through all words, looking for a non-equal word ptrA = BigIntMSB(a); ptrB = BigIntMSB(b); while(ptrA >= (BIGINT_DATA_TYPE *)a->startAddress) // Magnitude is same, no need to check ptrB bounds { valA = *ptrA--; valB = *ptrB--; if(valA > valB) { return 1; } else if(valA < valB) { return -1; } } // All words were exactly identical, return match return 0; }
void BigIntSubtract(BIGINT *a, BIGINT *b) { _iA = a->ptrLSB; _xA = a->ptrMSBMax; _iB = b->ptrLSB; _xB = BigIntMSB(b); subBI(); // Invalidate MSB pointer a->bMSBValid = 0; }
void BigIntAdd(BIGINT *a, BIGINT *b) { _iA = a->ptrLSB; _xA = a->ptrMSBMax; _iB = b->ptrLSB; _xB = BigIntMSB(b); addBI(); // Invalidate MSB pointer a->bMSBValid = 0; }
void BigIntSquare(BIGINT *a, BIGINT *res) { BigIntZero(res); _iA = a->ptrLSB; _xA = BigIntMSB(a); _iR = res->ptrLSB; sqrBI(); // Invalidate the MSB ptr res->bMSBValid = 0; }
uint32_t BigIntMagnitude(BIGINT_DATA *n) { return BigIntMSB(n) - (BIGINT_DATA_TYPE *)n->startAddress; }
/********************************************************************* * Function: void BIGINTMod(BIGINT_DATA *n, BIGINT_DATA *m) * * PreCondition: None * * Input: *n: a pointer to the number * *m: a pointer to the modulus * * Output: *n contains the modded number * i.e: *n = *n % *m * * Side Effects: None * * Overview: Call BigIntMod() to calculate the modulus of two * really big numbers. * * Note: Supports at least 2048 bits ********************************************************************/ BIGINT_RESULT BIGINT_Mod(BIGINT_DATA *result, BIGINT_DATA *a, BIGINT_DATA *b) { BIGINT_DATA_TYPE *_iB, *_xB, *_iR, _wC; BIGINT_DATA_TYPE *ptrMSBa, MSBb; BIGINT_DATA_TYPE_2 qHatInt; BIGINT_DATA temp1; uint32_t tempLen; union { BIGINT_DATA_TYPE v[2]; BIGINT_DATA_TYPE_2 Val; } topTwoWords; if (result == b) { // We can't store the result in m return BIGINT_RESULT_INVALID_PARAMETER; } else if (result != a) { // The result buffer is a separate buffer from n BIGINT_Copy (result, a); } // Set up assembly pointers for m // _iB and _xB are limiters in the _mas function _iB = b->startAddress; _xB = BigIntMSB(b); // Find the starting MSBs ptrMSBa = BigIntMSB(result); MSBb = *_xB; temp1.startAddress = result->startAddress; temp1.bLength = result->bLength; // Find out how many bytes we need to shift and move the LSB up _iR = result->startAddress + ((BigIntMagnitudeDifference(result, b) - 1) * BIGINT_DATA_SIZE); // This loops while the order of magnitude (in words) of n > m // Each iteration modulos off one word of magnitude from n while(_iR >= (BIGINT_DATA_TYPE *)result->startAddress) { // Find qHat = MSBn:MSBn-1/MSBb topTwoWords.Val = *((BIGINT_DATA_TYPE_2*)(ptrMSBa - 1)); qHatInt = topTwoWords.Val / MSBb; if(qHatInt > BIGINT_DATA_MAX) qHatInt = BIGINT_DATA_MAX; // Once qHat is determined, we multiply M by qHat, shift it up // as many bytes as possible, and subtract the result. // In essence, qHat is a rough estimation of the quotient, divided // by a power of 2^8 (PIC18) or 2^16 (PIC24/dsPIC) // This implementation multiplies and subtracts in the same step // using a _mas function which saves about 30% of clock cycles. // Save the old MSB and set up the ASM pointers _wC = (BIGINT_DATA_TYPE)qHatInt; // Do the multiply and subtract // Occassionally this results in underflow...this is solved below. _masBI(_xB, _iB, _wC, _iR); // qHat may have been 1 or 2 greater than possible. If so, // the new MSB will be greater than the old one, so we *add* // M back to N in the shifted position until overflow occurs // and this case corrects itself. while(topTwoWords.v[1] < *ptrMSBa) { tempLen = result->bLength; result->bLength = (BigIntMSB(result) - _iR + 1) * BIGINT_DATA_SIZE; result->startAddress = _iR; _addBI(result,b); result->startAddress = temp1.startAddress; result->bLength = tempLen; } // We should have modulated off a word (or two if we were lucky), // so move our MSB and LSB pointers as applicable while(*ptrMSBa == 0x0u) { _iR--; result->bLength -= 2; ptrMSBa--; } } // Iteration of the _mas function can only handle full-byte orders // of magnitude. The result may still be a little larger, so this // cleans up the last few multiples with simple subtraction. while(BIGINT_Compare(result, b) >= 0) { // _iA = result->startAddress; // _xA = result->startAddress + result->bLength - 1; _subBI(result,b); } result->startAddress = temp1.startAddress; result->bLength = temp1.bLength; return BIGINT_RESULT_OK; }
WORD BigIntMagnitude(BIGINT *n) { return BigIntMSB(n) - n->ptrLSB; }
CHAR BigIntCompareROM(BIGINT *a, BIGINT_ROM *b) { PTR_BASE magA, magB; BIGINT_DATA_TYPE valA, valB; BIGINT_DATA_TYPE *ptrA; ROM BIGINT_DATA_TYPE *ptrB; magA = BigIntMSB(a) - a->ptrLSB; magB = b->ptrMSB - b->ptrLSB; #if BIGINT_DEBUG_COMPARE putrsUART("\r\n Compared Magnitudes |a|:"); putulhexUART(w1); putrsUART(" |b|:"); putulhexUART(w2); putrsUART(" diff:"); putulhexUART(s); #endif if(magA > magB) { #if BIGINT_DEBUG_COMPARE putrsUART(" a > b"); #endif return 1; } else if(magA < magB) { #if BIGINT_DEBUG_COMPARE putrsUART(" a < b"); #endif return -1; } #if BIGINT_DEBUG_COMPARE putrsUART(" Checking further bytes..."); #endif // Loop through all words, looking for a non-equal word ptrA = BigIntMSB(a); ptrB = b->ptrMSB; while(ptrA >= a->ptrLSB) // Magnitude is same, no need to check ptrB bounds { valA = *ptrA--; valB = *ptrB--; if(valA > valB) { #if BIGINT_DEBUG_COMPARE putrsUART(" a > b"); #endif return 1; } else if (valA < valB) { #if BIGINT_DEBUG_COMPARE putrsUART(" a < b"); #endif return -1; } } // All words were exactly identical, return match return 0; }
void BigIntModROM(BIGINT *n, BIGINT_ROM* m) { BIGINT_DATA_TYPE *ptrMSBn, MSBm; BIGINT_DATA_TYPE_2 qHatInt, topTwoWords; // Find the starting MSBs ptrMSBn = BigIntMSB(n); MSBm = *m->ptrMSB; // Set up assembly pointers for m // _iBr and _xBr are limiters in the _masROM function _iBr = m->ptrLSB; _xBr = m->ptrMSB; // Find out how many bytes we need to shift and move the LSB up _iR = n->ptrLSB + (BigIntMagnitudeDifferenceROM(n, m) - 1); // This loops while the order of magnitude (in words) of n > m // Each iteration modulos off one word of magnitude from n while(_iR >= n->ptrLSB) { // Find qHat = MSBn:MSBn-1/MSBm topTwoWords = *((BIGINT_DATA_TYPE_2*)(ptrMSBn - 1)); qHatInt = topTwoWords / MSBm; if(qHatInt > BIGINT_DATA_MAX) qHatInt = BIGINT_DATA_MAX; #if BIGINT_DEBUG putrsUART("\r\n\r\n n = "); BigIntPrint(n); putrsUART("\r\n m = "); BigIntPrintROM(m); putrsUART("\r\n qHat ("); putulhexUART(qHatInt); putrsUART(") = topTwo("); putulhexUART(topTwoWords); putrsUART(") / ("); putulhexUART(MSBm); putrsUART(") "); #endif // Once qHat is determined, we multiply M by qHat, shift it up // as many bytes as possible, and subtract the result. // In essence, qHat is a rough estimation of the quotient, divided // by a power of 2^8 (PIC18) or 2^16 (PIC24/dsPIC) or 2^32 (PIC32) // This implementation multiplies and subtracts in the same step // using a _mas function which saves about 30% of clock cycles. // Save the old MSB and set up the ASM pointers _wC = (BIGINT_DATA_TYPE)qHatInt; // Do the multiply and subtract // Occassionally this results in underflow...this is solved below. masBIROM(); // qHat may have been 1 or 2 greater than possible. If so, // the new MSB will be greater than the old one, so we *add* // M back to N in the shifted position until overflow occurs // and this case corrects itself. while(((BIGINT_DATA_TYPE*)&topTwoWords)[1] < *BigIntMSB(n)) { _iA = _iR; _xA = BigIntMSB(n); addBIROM(); } // We should have modulated off a word (or two if we were lucky), // so move our MSB and LSB pointers as applicable while(*ptrMSBn == 0x0u) { _iR--; n->ptrMSB--; ptrMSBn--; } } // Iteration of the _mas function can only handle full-byte orders // of magnitude. The result may still be a little larger, so this // cleans up the last few multiples with simple subtraction. while(BigIntCompareROM(n, m) >= 0) { _iA = n->ptrLSB; _xA = n->ptrMSB; subBIROM(); // Invalidate MSB pointer n->bMSBValid = 0; } }