/********************************************************************* * 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; }
void BigIntMod(BIGINT *n, BIGINT* m) { BIGINT_DATA_TYPE *ptrMSBn, MSBm; BIGINT_DATA_TYPE_2 qHatInt; union { BIGINT_DATA_TYPE v[2]; BIGINT_DATA_TYPE_2 Val; } topTwoWords; // Find the starting MSBs ptrMSBn = BigIntMSB(n); MSBm = *BigIntMSB(m); // Set up assembly pointers for m // _iB and _xB are limiters in the _mas function _iB = m->ptrLSB; _xB = BigIntMSB(m); // Find out how many bytes we need to shift and move the LSB up _iR = n->ptrLSB + (BigIntMagnitudeDifference(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.Val = *((BIGINT_DATA_TYPE_2*)(ptrMSBn - 1)); qHatInt = topTwoWords.Val / 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 = "); BigIntPrint(m); putrsUART("\r\n qHat ("); putulhexUART(qHatInt); putrsUART(") = topTwo("); putulhexUART(topTwoWords.Val); 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. masBI(); // 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] < *BigIntMSB(n)) // while(((BIGINT_DATA_TYPE*)&topTwoWords)[1] < *BigIntMSB(n)) { _iA = _iR; _xA = BigIntMSB(n); addBI(); } // 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(BigIntCompare(n, m) >= 0) { _iA = n->ptrLSB; _xA = n->ptrMSB; subBI(); // Invalidate MSB pointer n->bMSBValid = 0; } }