static void DivideGaussian(BigInteger *real, BigInteger *imag) { BigInteger Tmp, norm, realNum, imagNum; CopyBigInt(&Tmp, real); Tmp.sign = SIGN_POSITIVE; BigIntMultiply(real, real, &norm); BigIntMultiply(imag, imag, &Tmp); BigIntAdd(&norm, &Tmp, &norm); BigIntMultiply(&ReValue, real, &realNum); BigIntMultiply(&ImValue, imag, &Tmp); BigIntAdd(&realNum, &Tmp, &realNum); BigIntMultiply(&ImValue, real, &imagNum); BigIntMultiply(&ReValue, imag, &Tmp); BigIntSubt(&imagNum, &Tmp, &imagNum); BigIntRemainder(&realNum, &norm, &Tmp); if (Tmp.nbrLimbs == 1 && Tmp.limbs[0].x == 0) { BigIntRemainder(&imagNum, &norm, &Tmp); if (Tmp.nbrLimbs == 1 && Tmp.limbs[0].x == 0) { BigIntDivide(&realNum, &norm, &ReValue); BigIntDivide(&imagNum, &norm, &ImValue); w("<li>"); showNumber(real, imag); w("</li>"); } } }
// Compute tmpP1 <- Base1^3 + Base2^3 + Base3^3 + Base4^3 // Use tmpQ1 as temporary variable. static void getSumOfCubes(void) { (void)BigIntMultiply(&Base1, &Base1, &tmpQ1); (void)BigIntMultiply(&tmpQ1, &Base1, &tmpP1); (void)BigIntMultiply(&Base2, &Base2, &tmpQ1); (void)BigIntMultiply(&tmpQ1, &Base2, &tmpQ1); BigIntAdd(&tmpP1, &tmpQ1, &tmpP1); (void)BigIntMultiply(&Base3, &Base3, &tmpQ1); (void)BigIntMultiply(&tmpQ1, &Base3, &tmpQ1); BigIntAdd(&tmpP1, &tmpQ1, &tmpP1); (void)BigIntMultiply(&Base4, &Base4, &tmpQ1); (void)BigIntMultiply(&tmpQ1, &Base4, &tmpQ1); BigIntAdd(&tmpP1, &tmpQ1, &tmpP1); }
BigIntRef BigIntCreateDecimal (const char * _decstr) { const char * decstr = _decstr; if (strlen(decstr) == 0) { return BigIntNew(0); } if (_decstr[0] == '-') { decstr = &_decstr[1]; } // read each digit, multiplying something by ten // and adding the product of that and the digit // to the return value BigIntRef result = BigIntNew(0); BigIntRef digit = BigIntNew(1); BigIntRef base = BigIntNew(10); // call these so that we don't waste CPU BigIntRemoveDecimalString(digit); BigIntRemoveDecimalString(result); int len = strlen(decstr); for (int i = len - 1; i >= 0; i--) { char c = decstr[i]; int digitVal = c - '0'; if (digitVal < 0 || digitVal > 9) { BigIntRelease(result); BigIntRelease(digit); BigIntRelease(base); return NULL; } BigIntRef digitInt = BigIntNew(digitVal); BigIntRef adding = BigIntMultiply(digit, digitInt); BigIntRef newDigit = BigIntMultiply(digit, base); BigIntRelease(digit); digit = newDigit; BigIntRef newSum = BigIntAdd(adding, result); BigIntRelease(result); result = newSum; BigIntRelease(adding); BigIntRelease(digitInt); } BigIntRelease(digit); BigIntRelease(base); if (_decstr[0] == '-') { result->flags |= kBigIntFlagNegative; } return result; }
BigIntRef BigIntMultiply (BigIntRef bi, BigIntRef bi2) { if (bi2 == bi) { // create a copy of bi2, call, and release the copy BigIntRef nbi2 = BigIntCreateCopy(bi2, 0); BigIntRef answer = BigIntMultiply(bi, nbi2); BigIntRelease(nbi2); return answer; } BigIntRef productSum = BigIntNew(0); BigIntRemoveDecimalString(productSum); // sum up each new big int and replace // the productSum for (int i = 0; i < bi2->binDigits; i++) { // if we have a positive number in bi2 // then we have to add up or something if (BitBufferGetBit(bi2->bits, i)) { // add the shifted sum BigIntRef product = BigIntCreateCopy(bi, i); // add BigIntRef newSum = BigIntAdd(product, productSum); BigIntRemoveDecimalString(newSum); BigIntRelease(product); /*printf("%s + %s = %s\n", BigIntBase10Rep(product), BigIntBase10Rep(productSum), BigIntBase10Rep(newSum));*/ BigIntRelease(productSum); productSum = newSum; } } productSum->flags = 0; // check the negative stream BigBool neg1 = BigIntFlagIsSet(bi, kBigIntFlagNegative); BigBool neg2 = BigIntFlagIsSet(bi2, kBigIntFlagNegative); if (!neg1 && neg2) { productSum->flags |= kBigIntFlagNegative; } else if (neg1 && !neg2) { productSum->flags |= kBigIntFlagNegative; } return productSum; }
void GaussianFactorization(void) { BigInteger prime, q, r, M1, M2, Tmp; struct sFactors *pstFactor; BigIntMultiply(&ReValue, &ReValue, &tofactor); BigIntMultiply(&ImValue, &ImValue, &Tmp); BigIntAdd(&tofactor, &Tmp, &tofactor); NbrFactorsNorm = 0; #ifdef __EMSCRIPTEN__ originalTenthSecond = tenths(); #endif if (tofactor.nbrLimbs == 1 && tofactor.limbs[0].x == 0) { // Norm is zero. w("<ul><li>Any gaussian prime divides this number</li></ul>"); return; } w("<ul>"); if (tofactor.nbrLimbs > 1 || tofactor.limbs[0].x > 1) { // norm greater than 1. Factor norm. int index, index2; char *ptrFactorDec = tofactorDec; NumberLength = tofactor.nbrLimbs; CompressBigInteger(nbrToFactor, &tofactor); strcpy(ptrFactorDec, "Re² + Im² = "); ptrFactorDec += strlen(ptrFactorDec); Bin2Dec(ReValue.limbs, ptrFactorDec, ReValue.nbrLimbs, groupLen); ptrFactorDec += strlen(ptrFactorDec); strcpy(ptrFactorDec, "² + "); ptrFactorDec += strlen(ptrFactorDec); Bin2Dec(ImValue.limbs, ptrFactorDec, ImValue.nbrLimbs, groupLen); ptrFactorDec += strlen(ptrFactorDec); strcpy(ptrFactorDec, "²"); ptrFactorDec += strlen(ptrFactorDec); factor(&tofactor, nbrToFactor, factorsNorm, astFactorsNorm, NULL); NbrFactorsNorm = astFactorsNorm[0].multiplicity; pstFactor = &astFactorsNorm[1]; for (index = 0; index < NbrFactorsNorm; index++) { int *ptrPrime = pstFactor->ptrFactor; NumberLength = *ptrPrime; UncompressBigInteger(ptrPrime, &prime); prime.sign = SIGN_POSITIVE; if (prime.nbrLimbs == 1 && prime.limbs[0].x == 2) { // Prime factor is 2. for (index2 = 0; index2 < pstFactor->multiplicity; index2++) { M1.nbrLimbs = M2.nbrLimbs = 1; M1.limbs[0].x = M2.limbs[0].x = 1; M1.sign = SIGN_POSITIVE; M2.sign = SIGN_NEGATIVE; DivideGaussian(&M1, &M1); // Divide by 1+i DivideGaussian(&M1, &M2); // Divide by 1-i } } if ((prime.limbs[0].x & 2) == 0) { // Prime is congruent to 1 (mod 4) CopyBigInt(&q, &prime); NumberLength = prime.nbrLimbs; memcpy(&TestNbr, prime.limbs, NumberLength * sizeof(limb)); TestNbr[NumberLength].x = 0; GetMontgomeryParms(NumberLength); subtractdivide(&q, 1, 4); // q = (prime-1)/4 memset(&K, 0, NumberLength * sizeof(limb)); memset(minusOneMont, 0, NumberLength * sizeof(limb)); SubtBigNbrModN(minusOneMont, MontgomeryMultR1, minusOneMont, TestNbr, NumberLength); K[0].x = 1; do { // Loop that finds mult1 = sqrt(-1) mod prime in Montgomery notation. K[0].x++; modPow(K, q.limbs, q.nbrLimbs, mult1.limbs); } while (!memcmp(mult1.limbs, MontgomeryMultR1, NumberLength * sizeof(limb)) || !memcmp(mult1.limbs, minusOneMont, NumberLength * sizeof(limb))); K[0].x = 1; modmult(mult1.limbs, K, mult1.limbs); // Convert mult1 to standard notation. UncompressLimbsBigInteger(mult1.limbs, &mult1); // Convert to Big Integer. mult2.nbrLimbs = 1; // mult2 <- 1 mult2.limbs[0].x = 1; mult2.sign = SIGN_POSITIVE; for (;;) { // norm <- (mult1^2 + mult2^2) / prime BigIntMultiply(&mult1, &mult1, &tofactor); BigIntMultiply(&mult2, &mult2, &Tmp); BigIntAdd(&tofactor, &Tmp, &Tmp); BigIntDivide(&Tmp, &prime, &tofactor); if (tofactor.nbrLimbs == 1 && tofactor.limbs[0].x == 1) { // norm equals 1. break; } BigIntRemainder(&mult1, &tofactor, &M1); BigIntRemainder(&mult2, &tofactor, &M2); BigIntAdd(&M1, &M1, &Tmp); BigIntSubt(&tofactor, &Tmp, &Tmp); if (Tmp.sign == SIGN_NEGATIVE) { BigIntSubt(&M1, &tofactor, &M1); } BigIntAdd(&M2, &M2, &Tmp); BigIntSubt(&tofactor, &Tmp, &Tmp); if (Tmp.sign == SIGN_NEGATIVE) { BigIntSubt(&M2, &tofactor, &M2); } // Compute q <- (mult1*M1 + mult2*M2) / norm BigIntMultiply(&mult1, &M1, &q); BigIntMultiply(&mult2, &M2, &Tmp); BigIntAdd(&q, &Tmp, &Tmp); BigIntDivide(&Tmp, &tofactor, &q); // Compute Mult2 <- (mult1*M2 - mult2*M1) / tofactor BigIntMultiply(&mult1, &M2, &r); BigIntMultiply(&mult2, &M1, &Tmp); BigIntSubt(&r, &Tmp, &Tmp); BigIntDivide(&Tmp, &tofactor, &mult2); CopyBigInt(&mult1, &q); mult1.sign = SIGN_POSITIVE; // mult1 <- abs(mult1) mult2.sign = SIGN_POSITIVE; // mult2 <- abs(mult2) } /* end while */ CopyBigInt(&M1, &mult1); CopyBigInt(&M2, &mult2); BigIntSubt(&M1, &M2, &Tmp); if (Tmp.sign == SIGN_NEGATIVE) { CopyBigInt(&Tmp, &mult1); CopyBigInt(&mult1, &mult2); CopyBigInt(&mult2, &Tmp); } for (index2 = 0; index2 < pstFactor->multiplicity; index2++) { DivideGaussian(&mult1, &mult2); BigIntNegate(&mult2, &Tmp); DivideGaussian(&mult1, &Tmp); } } // end p = 1 (mod 4) else { // if p = 3 (mod 4) q.nbrLimbs = 1; // q <- 0 q.limbs[0].x = 0; q.sign = SIGN_POSITIVE; for (index2 = 0; index2 < pstFactor->multiplicity; index2++) { DivideGaussian(&prime, &q); } // end p = 3 (mod 4) } pstFactor++; } } // Process units: 1, -1, i, -i. if (ReValue.nbrLimbs == 1 && ReValue.limbs[0].x == 1) { if (ReValue.sign == SIGN_POSITIVE) { // Value is 1. if (NbrFactorsNorm == 0) { w("No gaussian prime divides this number"); } } else { // Value is -1. w("<li>-1</li>"); } } else if (ImValue.sign == SIGN_POSITIVE) { w("<li>i</li>"); } else { w("<li>-i</li>"); } w("</ul>"); }
/***************************************************************************** Function: RSA_STATUS RSAStep(void) Summary: Performs non-blocking RSA calculations. Description: Call this function to process a portion of the pending RSA operation until RSA_DONE is returned. This function performs small pieces of work each time it is called, so it must be called repeatedly in order to complete an operation. Performing small pieces at a time and then yielding to the main application allows long calculations to be performed in a non-blocking manner that fits with the co-operative multi-tasking model of the stack. Status updates are periodically returned. For lengthy decryption operations, this helps prevent client time-outs by allowing the application to periodically transmit a few bytes if necessary. Precondition: RSA has already been initialized and RSABeginUsage has returned TRUE. Parameters: None Return Values: RSA_WORKING - Calculation is in progress; no status update available. RSA_FINISHED_M1 - This call has completed the decryption calculation of the M1 CRT value. RSA_FINISHED_M2 - This call has completed the decryption calculation of the M2 CRT value. RSA_DONE - The RSA operation is complete. ***************************************************************************/ RSA_STATUS RSAStep(void) { #if defined(STACK_USE_RSA_DECRYPT) static BIGINT m1, m2; #endif switch(smRSA) { #if defined(STACK_USE_RSA_ENCRYPT) case SM_RSA_ENCRYPT_START: // Actually nothing to do here anymore smRSA = SM_RSA_ENCRYPT; case SM_RSA_ENCRYPT: // Call ModExp until complete if(_RSAModExp(&Y, &X, &E, &N)) {// Calculation is finished // Swap endian-ness if needed if(outputFormat == RSA_BIG_ENDIAN) BigIntSwapEndianness(&Y); // Indicate that we're finished smRSA = SM_RSA_DONE; return RSA_DONE; } break; #endif #if defined(STACK_USE_RSA_DECRYPT) case SM_RSA_DECRYPT_START: // Set up the RSA Decryption memories BigInt(&m1, (BIGINT_DATA_TYPE*)((BYTE*)&sslBuffer+(SSL_RSA_KEY_SIZE/8)), RSA_PRIME_WORDS); BigInt(&m2, (BIGINT_DATA_TYPE*)((BYTE*)&sslBuffer+3*(SSL_RSA_KEY_SIZE/16)), RSA_PRIME_WORDS); smRSA = SM_RSA_DECRYPT_FIND_M1; break; case SM_RSA_DECRYPT_FIND_M1: // m1 = c^dP % p if(_RSAModExpROM(&m1, &X, &dP, &P)) { smRSA = SM_RSA_DECRYPT_FIND_M2; return RSA_FINISHED_M1; } break; case SM_RSA_DECRYPT_FIND_M2: // m2 = c^dQ % q if(_RSAModExpROM(&m2, &X, &dQ, &Q)) { smRSA = SM_RSA_DECRYPT_FINISH; return RSA_FINISHED_M2; } break; case SM_RSA_DECRYPT_FINISH: // Almost done...finalize the CRT math if(BigIntCompare(&m1, &m2) > 0) {// if(m1 > m2) // m1 = m1 - m2 BigIntSubtract(&m1, &m2); // tmp = m1 * qInv BigIntMultiplyROM(&m1, &qInv, &tmp); // m1 = tmp % p BigIntModROM(&tmp, &P); BigIntCopy(&m1, &tmp); } else {// m1 < m2 // tmp = m2 BigIntCopy(&tmp, &m2); // m2 = m2 - m1 BigIntSubtract(&m2, &m1); // m1 = tmp BigIntCopy(&m1, &tmp); // tmp = m2 * qInv BigIntMultiplyROM(&m2, &qInv, &tmp); // m2 = m1 BigIntCopy(&m2, &m1); // tmp = tmp % p BigIntModROM(&tmp, &P); // m1 = P BigIntCopyROM(&m1, &P); // m1 = m1 - tmp; BigIntSubtract(&m1, &tmp); } // msg = m1 * q BigIntMultiplyROM(&m1, &Q, &tmp); // tmp = m2 + tmp BigIntAdd(&tmp, &m2); // Copy the decrypted value back to X BigIntCopy(&X, &tmp); // Swap endian-ness if needed if(outputFormat == RSA_BIG_ENDIAN) BigIntSwapEndianness(&X); // Indicate that we're finished smRSA = SM_RSA_DONE; return RSA_DONE; #endif default: // Unknown state return RSA_DONE; } // Indicate that we're still working return RSA_WORKING; }
static int fcubes(BigInteger *pArgument) { int mod18, modulus, i, mod83, mask; int pow, exp; boolean converted = FALSE; CopyBigInt(&value, pArgument); // Compute argument mod 18. mod18 = getRemainder(pArgument, 18); if (mod18 == 4 || mod18 == 5 || mod18 == 13 || mod18 == 14) { return -1; // Applet does not work if the number is congruent to 4 or 5 (mod 9) } if (mod18 == 16) { // Change sign. converted = TRUE; BigIntNegate(&value, &value); } for (i = 0; i<(int)(sizeof(sums)/sizeof(sums[0])); i += 10) { modulus = sums[i]; if ((getRemainder(&value, modulus) + modulus)% modulus == sums[i + 1]) { break; } } if (i<(int)(sizeof(sums) / sizeof(sums[0]))) { subtractdivide(&value, sums[i + 1], modulus); // value <- (value-sums[i+1])/modulus multadd(&Base1, sums[i + 2], &value, sums[i + 3]); // Base1 <- sums[i+2]*value+sums[i+3] multadd(&Base2, sums[i + 4], &value, sums[i + 5]); // Base2 <- sums[i+4]*value+sums[i+5] multadd(&Base3, sums[i + 6], &value, sums[i + 7]); // Base3 <- sums[i+6]*value+sums[i+7] multadd(&Base4, sums[i + 8], &value, sums[i + 9]); // Base4 <- sums[i+8]*value+sums[i+9] } else if (getRemainder(&value, 54) == 2) { // If value == 2 (mod 54)... subtractdivide(&value, 2, 54); // value <- (value-2)/54 EvaluateQuadraticPoly(&Base1, &value, 29484, 2211, 43); EvaluateQuadraticPoly(&Base2, &value, -29484, -2157, -41); EvaluateQuadraticPoly(&Base3, &value, 9828, 485, 4); EvaluateQuadraticPoly(&Base4, &value, -9828, -971, -22); } else if (getRemainder(&value, 83 * 108) == 83*46) { // If value == 83*46 (mod 83*108)... subtractdivide(&value, 83*46, 83*108); // value <-(value - (83*46)) / (83*108) EvaluateQuadraticPoly(&Base1, &value, 29484, 25143, 5371); EvaluateQuadraticPoly(&Base2, &value, -29484, -25089, -5348); EvaluateQuadraticPoly(&Base3, &value, 9828, 8129, 1682); EvaluateQuadraticPoly(&Base4, &value, -9828, -8615, -1889); } else { // Perform Pell solution of Demjanenko's theorem // Using these values of P, Q, R and S, a and b will be // always one and zero (mod 6) respectively. // P <- -112488782561 = -(52*2^31+819632865) // Q <- -6578430178320 = -(3063*2^31+687764496) // R <- -1923517596 = -(0*2^31+1923517596) // S <- P // P1 <- 1 // Q1 <- 0 // R1 <- 0 // S1 <- 1 P.limbs[1].x = S.limbs[1].x = 52; P.limbs[0].x = S.limbs[0].x = 819632865; Q.limbs[1].x = 3063; Q.limbs[0].x = 687764496; R.limbs[1].x = 0; R.limbs[0].x = 1923517596; P.nbrLimbs = Q.nbrLimbs = R.nbrLimbs = S.nbrLimbs = 3; P.sign = Q.sign = R.sign = S.sign = SIGN_NEGATIVE; P1.limbs[0].x = S1.limbs[0].x = 1; Q1.limbs[0].x = R1.limbs[0].x = 0; P1.nbrLimbs = Q1.nbrLimbs = R1.nbrLimbs = S1.nbrLimbs = 1; P1.sign = Q1.sign = R1.sign = S1.sign = SIGN_POSITIVE; mod83 = getRemainder(&value, 83); pow = 71; exp = 0; while (pow != mod83) { exp++; pow = (pow * 50) % 83; } if (exp > 82 / 2) { exp = 82 - exp; Q.sign = R.sign = SIGN_POSITIVE; } // Now exp is in range 0-41. mask = 32; while (mask > 0) { // tmpP1 <- P1*P1 + Q1*R1 // tmpQ1 <- (P1+S1) * Q1 // tmpR1 <- (P1+S1) * R1 // tmpS1 <- S1*S1 + Q1*R1 // P1 <- tmpP1 // Q1 <- tmpQ1 // R1 <- tmpR1 // S1 <- tmpS1 (void)BigIntMultiply(&P1, &P1, &tmpP1); (void)BigIntMultiply(&Q1, &R1, &tmpQ1); (void)BigIntMultiply(&S1, &S1, &tmpS1); BigIntAdd(&P1, &S1, &tmpR1); BigIntAdd(&tmpP1, &tmpQ1, &P1); BigIntAdd(&tmpS1, &tmpQ1, &S1); (void)BigIntMultiply(&tmpR1, &Q1, &Q1); (void)BigIntMultiply(&tmpR1, &R1, &R1); if ((exp & mask) != 0) { // tmpP1 <- P*P1 + Q*R1 // tmpQ1 <- P*Q1 + Q*S1 // tmpR1 <- R*P1 + S*R1 // tmpS1 <- R*Q1 + S*S1 // P1 <- tmpP1 // Q1 <- tmpQ1 // R1 <- tmpR1 // S1 <- tmpS1 (void)BigIntMultiply(&P, &P1, &tmpP1); (void)BigIntMultiply(&Q, &R1, &tmpQ1); (void)BigIntMultiply(&R, &P1, &tmpR1); (void)BigIntMultiply(&S, &R1, &tmpS1); BigIntAdd(&tmpP1, &tmpQ1, &P1); BigIntAdd(&tmpR1, &tmpS1, &R1); (void)BigIntMultiply(&P, &Q1, &tmpP1); (void)BigIntMultiply(&Q, &S1, &tmpQ1); (void)BigIntMultiply(&R, &Q1, &tmpR1); (void)BigIntMultiply(&S, &S1, &tmpS1); BigIntAdd(&tmpP1, &tmpQ1, &Q1); BigIntAdd(&tmpR1, &tmpS1, &S1); } mask >>= 1; } addmult(&a, &P1, -3041, &Q1, -52); // a <- -3041*P1 - 52*Q1 addmult(&b, &R1, -3041, &S1, -52); // b <- -3041*R1 - 52*S1 addmult(&Base1, &a, 27, &b, -928); // Base1 <- 27*a - 928*b addmult(&Base2, &a, -9, &b, -602); // Base2 <- -9*a - 602*b addmult(&Base3, &a, 25, &b, -2937); // Base3 <- 25*a - 2937*b addmult(&Base4, &a, -19, &b, 2746); // Base4 <- -19*a - 2746*b // a <- (value - Base1^3 - Base2^3 - Base3^3 - Base4^3)/(18*83) getSumOfCubes(); // tmpP1 = Base1^3 + Base2^3 + Base3^3 + Base4^3 BigIntSubt(&value, &tmpP1, &a); subtractdivide(&a, 0, 18 * 83); // Divide a by 18*83. multint(&tmpP1, &a, 10); // Base1 <- Base1 + 10*a BigIntAdd(&tmpP1, &Base1, &Base1); multint(&tmpP1, &a, -19); // Base2 <- Base2 - 19*a BigIntAdd(&tmpP1, &Base2, &Base2); multint(&tmpP1, &a, -24); // Base3 <- Base3 - 24*a BigIntAdd(&tmpP1, &Base3, &Base3); multint(&tmpP1, &a, 27); // Base4 <- Base4 + 27*a BigIntAdd(&tmpP1, &Base4, &Base4); } if (converted != 0) { BigIntNegate(&Base1, &Base1); BigIntNegate(&Base2, &Base2); BigIntNegate(&Base3, &Base3); BigIntNegate(&Base4, &Base4); } // Sort cubes SortBigIntegers(&Base1, &Base2); SortBigIntegers(&Base1, &Base3); SortBigIntegers(&Base1, &Base4); SortBigIntegers(&Base2, &Base3); SortBigIntegers(&Base2, &Base4); SortBigIntegers(&Base3, &Base4); // Validate getSumOfCubes(); // tmpP1 = Base1^3 - Base2^3 - Base3^3 - Base4^3 BigIntSubt(&tmpP1, pArgument, &tmpQ1); if (tmpQ1.nbrLimbs != 1 || tmpQ1.limbs[0].x != 0) { return 1; // Result does not validate. } return 0; }
void DiscreteLogarithm(void) { BigInteger groupOrder, subGroupOrder, powSubGroupOrder, powSubGroupOrderBak; BigInteger Exponent, runningExp, baseExp, mod; BigInteger logar, logarMult, runningExpBase; BigInteger currentExp; int indexBase, indexExp; int index, expon; limb addA, addB, addA2, addB2; limb mult1, mult2; double magnitude, firstLimit, secondLimit; long long brentK, brentR; unsigned char EndPollardBrentRho; int nbrLimbs; struct sFactors *pstFactors; enum eLogMachineState logMachineState; char *ptr; #ifdef __EMSCRIPTEN__ lModularMult = 0; #endif NumberLength = modulus.nbrLimbs; if (!TestBigNbrEqual(&LastModulus, &modulus)) { CompressBigInteger(nbrToFactor, &modulus); Bin2Dec(modulus.limbs, tofactorDec, modulus.nbrLimbs, groupLen); factor(&modulus, nbrToFactor, factorsMod, astFactorsMod, NULL); NbrFactorsMod = astFactorsMod[0].multiplicity; } intToBigInteger(&DiscreteLog, 0); // DiscreteLog <- 0 intToBigInteger(&DiscreteLogPeriod, 1); // DiscreteLogPeriod <- 1 for (index = 1; index <= NbrFactorsMod; index++) { int mostSignificantDword, leastSignificantDword; int NbrFactors; int *ptrPrime; int multiplicity; ptrPrime = astFactorsMod[index].ptrFactor; NumberLength = *ptrPrime; UncompressBigInteger(ptrPrime, &groupOrder); groupOrder.sign = SIGN_POSITIVE; BigIntRemainder(&base, &groupOrder, &tmpBase); if (tmpBase.nbrLimbs == 1 && tmpBase.limbs[0].x == 0) { // modulus and base are not relatively prime. int ctr; multiplicity = astFactorsMod[index].multiplicity; CopyBigInt(&bigNbrA, &power); for (ctr = multiplicity; ctr > 0; ctr--) { BigIntRemainder(&bigNbrA, &groupOrder, &bigNbrB); if (bigNbrB.nbrLimbs != 1 || bigNbrB.limbs[0].x != 0) { // Exit loop if integer division cannot be performed break; } BigIntDivide(&bigNbrA, &groupOrder, &bigNbrB); CopyBigInt(&bigNbrA, &bigNbrB); } if (ctr == 0) { // Power is multiple of prime^exp. continue; } // Compute prime^mutliplicity. BigIntPowerIntExp(&groupOrder, multiplicity, &tmp2); BigIntRemainder(&base, &tmp2, &tmpBase); // Get tentative exponent. ctr = multiplicity - ctr; intToBigInteger(&bigNbrB, ctr); // Convert exponent to big integer. NumberLength = tmp2.nbrLimbs; memcpy(TestNbr, tmp2.limbs, (NumberLength + 1) * sizeof(limb)); GetMontgomeryParms(NumberLength); BigIntModularPower(&tmpBase, &bigNbrB, &bigNbrA); BigIntRemainder(&power, &tmp2, &bigNbrB); BigIntSubt(&bigNbrA, &bigNbrB, &bigNbrA); if (bigNbrA.nbrLimbs == 1 && bigNbrA.limbs[0].x == 0) { intToBigInteger(&DiscreteLog, ctr); // DiscreteLog <- exponent intToBigInteger(&DiscreteLogPeriod, 0); // DiscreteLogPeriod <- 0 break; } showText("There is no discrete logarithm"); DiscreteLogPeriod.sign = SIGN_NEGATIVE; return; } else { // modulus and base are relatively prime. BigIntRemainder(&power, &groupOrder, &bigNbrB); if (bigNbrB.nbrLimbs == 1 && bigNbrB.limbs[0].x == 0) { // power is multiple of prime. Error. showText("There is no discrete logarithm"); DiscreteLogPeriod.sign = SIGN_NEGATIVE; return; } } CompressLimbsBigInteger(baseMontg, &tmpBase); BigIntRemainder(&power, &groupOrder, &tmpBase); CompressLimbsBigInteger(powerMontg, &tmpBase); // Compute group order as the prime minus 1. groupOrder.limbs[0].x--; showText("Computing discrete logarithm..."); CompressBigInteger(nbrToFactor, &groupOrder); factor(&groupOrder, nbrToFactor, factorsGO, astFactorsGO, NULL); // factor groupOrder. NbrFactors = astFactorsGO[0].multiplicity; NumberLength = *ptrPrime; UncompressBigInteger(ptrPrime, &mod); intToBigInteger(&logar, 0); // logar <- 0 intToBigInteger(&logarMult, 1); // logarMult <- 1 NumberLength = mod.nbrLimbs; memcpy(TestNbr, mod.limbs, NumberLength * sizeof(limb)); TestNbr[NumberLength].x = 0; // yieldFreq = 1000000 / (NumberLength*NumberLength); GetMontgomeryParms(NumberLength); #if 0 char *ptrText = textExp; strcpy(ptrText, "<p>NumberLength (2) = "); ptrText = ptrText + strlen(ptrText); int2dec(&ptrText, NumberLength); strcpy(ptrText, "</p>"); DiscreteLogPeriod.sign = SIGN_NEGATIVE; return; #endif // Convert base and power to Montgomery notation. modmult(baseMontg, MontgomeryMultR2, baseMontg); modmult(powerMontg, MontgomeryMultR2, powerMontg); mostSignificantDword = NumberLength - 1; if (NumberLength == 1) { leastSignificantDword = NumberLength - 1; firstLimit = (double)TestNbr[leastSignificantDword].x / 3; } else { leastSignificantDword = NumberLength - 2; firstLimit = ((double)TestNbr[mostSignificantDword].x * LIMB_RANGE + TestNbr[leastSignificantDword].x) / 3; } secondLimit = firstLimit * 2; for (indexBase = 0; indexBase < NbrFactors; indexBase++) { NumberLength = *astFactorsGO[indexBase + 1].ptrFactor; UncompressBigInteger(astFactorsGO[indexBase + 1].ptrFactor, &subGroupOrder); subGroupOrder.sign = SIGN_POSITIVE; strcpy(textExp, "Computing discrete logarithm in subgroup of "); Bin2Dec(subGroupOrder.limbs, textExp + strlen(textExp), subGroupOrder.nbrLimbs, groupLen); ptr = textExp + strlen(textExp); if (astFactorsGO[indexBase + 1].multiplicity > 1) { *ptr++ = '<'; *ptr++ = 's'; *ptr++ = 'u'; *ptr++ = 'p'; *ptr++ = '>'; int2dec(&ptr, astFactorsGO[indexBase + 1].multiplicity); *ptr++ = '<'; *ptr++ = '/'; *ptr++ = 's'; *ptr++ = 'u'; *ptr++ = 'p'; *ptr++ = '>'; } strcpy(ptr, " elements."); showText(textExp); NumberLength = mod.nbrLimbs; memcpy(TestNbr, mod.limbs, NumberLength * sizeof(limb)); NumberLengthOther = subGroupOrder.nbrLimbs; memcpy(TestNbrOther, subGroupOrder.limbs, NumberLengthOther * sizeof(limb)); TestNbr[NumberLength].x = 0; GetMontgomeryParms(NumberLength); nbrLimbs = subGroupOrder.nbrLimbs; dN = (double)subGroupOrder.limbs[nbrLimbs - 1].x; if (nbrLimbs > 1) { dN += (double)subGroupOrder.limbs[nbrLimbs - 2].x / LIMB_RANGE; if (nbrLimbs > 2) { dN += (double)subGroupOrder.limbs[nbrLimbs - 3].x / LIMB_RANGE / LIMB_RANGE; } } CopyBigInt(&baseExp, &groupOrder); // Check whether base is primitive root. BigIntDivide(&groupOrder, &subGroupOrder, &tmpBase); modPow(baseMontg, tmpBase.limbs, tmpBase.nbrLimbs, primRootPwr); if (!memcmp(primRootPwr, MontgomeryMultR1, NumberLength * sizeof(limb))) { // Power is one, so it is not a primitive root. logMachineState = CALC_LOG_BASE; // Find primitive root primRoot[0].x = 1; if (NumberLength > 1) { memset(&primRoot[1], 0, (NumberLength - 1) * sizeof(limb)); } do { primRoot[0].x++; modPow(primRoot, tmpBase.limbs, tmpBase.nbrLimbs, primRootPwr); } while (!memcmp(primRootPwr, MontgomeryMultR1, NumberLength * sizeof(limb))); } else { // Power is not 1, so the base is a primitive root. logMachineState = BASE_PRIMITIVE_ROOT; memcpy(primRoot, baseMontg, NumberLength * sizeof(limb)); } for (;;) { // Calculate discrete logarithm in subgroup. runningExp.nbrLimbs = 1; // runningExp <- 0 runningExp.limbs[0].x = 0; runningExp.sign = SIGN_POSITIVE; powSubGroupOrder.nbrLimbs = 1; // powSubGroupOrder <- 1 powSubGroupOrder.limbs[0].x = 1; powSubGroupOrder.sign = SIGN_POSITIVE; CopyBigInt(¤tExp, &groupOrder); if (logMachineState == BASE_PRIMITIVE_ROOT) { memcpy(basePHMontg, baseMontg, NumberLength * sizeof(limb)); memcpy(currPowerMontg, powerMontg, NumberLength * sizeof(limb)); } else if (logMachineState == CALC_LOG_BASE) { memcpy(basePHMontg, primRoot, NumberLength * sizeof(limb)); memcpy(currPowerMontg, baseMontg, NumberLength * sizeof(limb)); } else { // logMachineState == CALC_LOG_POWER memcpy(primRoot, basePHMontg, NumberLength * sizeof(limb)); memcpy(currPowerMontg, powerMontg, NumberLength * sizeof(limb)); } for (indexExp = 0; indexExp < astFactorsGO[indexBase + 1].multiplicity; indexExp++) { /* PH below comes from Pohlig-Hellman algorithm */ BigIntDivide(¤tExp, &subGroupOrder, ¤tExp); modPow(currPowerMontg, currentExp.limbs, currentExp.nbrLimbs, powerPHMontg); BigIntDivide(&baseExp, &subGroupOrder, &baseExp); if (subGroupOrder.nbrLimbs == 1 && subGroupOrder.limbs[0].x < 20) { // subGroupOrder less than 20. if (!ComputeDLogModSubGroupOrder(indexBase, indexExp, &Exponent, &subGroupOrder)) { return; } } else { // Use Pollard's rho method with Brent's modification memcpy(nbrPower, powerPHMontg, NumberLength * sizeof(limb)); memcpy(nbrBase, primRootPwr, NumberLength * sizeof(limb)); memcpy(nbrR2, nbrBase, NumberLength * sizeof(limb)); memset(nbrA2, 0, NumberLength * sizeof(limb)); memset(nbrB2, 0, NumberLength * sizeof(limb)); nbrB2[0].x = 1; addA2.x = addB2.x = 0; mult2.x = 1; brentR = 1; brentK = 0; EndPollardBrentRho = FALSE; do { memcpy(nbrR, nbrR2, NumberLength * sizeof(limb)); memcpy(nbrA, nbrA2, NumberLength * sizeof(limb)); memcpy(nbrB, nbrB2, NumberLength * sizeof(limb)); addA = addA2; addB = addB2; mult1 = mult2; brentR *= 2; do { brentK++; if (NumberLength == 1) { magnitude = (double)nbrR2[leastSignificantDword].x; } else { magnitude = (double)nbrR2[mostSignificantDword].x * LIMB_RANGE + nbrR2[leastSignificantDword].x; } if (magnitude < firstLimit) { modmult(nbrR2, nbrPower, nbrROther); addA2.x++; } else if (magnitude < secondLimit) { modmult(nbrR2, nbrR2, nbrROther); mult2.x *= 2; addA2.x *= 2; addB2.x *= 2; } else { modmult(nbrR2, nbrBase, nbrROther); addB2.x++; } // Exchange nbrR2 and nbrROther memcpy(nbrTemp, nbrR2, NumberLength * sizeof(limb)); memcpy(nbrR2, nbrROther, NumberLength * sizeof(limb)); memcpy(nbrROther, nbrTemp, NumberLength * sizeof(limb)); if (addA2.x >= (int)(LIMB_RANGE / 2) || addB2.x >= (int)(LIMB_RANGE / 2) || mult2.x >= (int)(LIMB_RANGE / 2)) { // nbrA2 <- (nbrA2 * mult2 + addA2) % subGroupOrder AdjustExponent(nbrA2, mult2, addA2, &subGroupOrder); // nbrB2 <- (nbrB2 * mult2 + addB2) % subGroupOrder AdjustExponent(nbrB2, mult2, addB2, &subGroupOrder); mult2.x = 1; addA2.x = addB2.x = 0; } if (!memcmp(nbrR, nbrR2, NumberLength * sizeof(limb))) { EndPollardBrentRho = TRUE; break; } } while (brentK < brentR); } while (EndPollardBrentRho == FALSE); ExchangeMods(); // TestNbr <- subGroupOrder // nbrA <- (nbrA * mult1 + addA) % subGroupOrder AdjustExponent(nbrA, mult1, addA, &subGroupOrder); // nbrB <- (nbrB * mult1 + addB) % subGroupOrder AdjustExponent(nbrB, mult1, addB, &subGroupOrder); // nbrA2 <- (nbrA * mult2 + addA2) % subGroupOrder AdjustExponent(nbrA2, mult2, addA2, &subGroupOrder); // nbrB2 <- (nbrA * mult2 + addB2) % subGroupOrder AdjustExponent(nbrB2, mult2, addB2, &subGroupOrder); // nbrB <- (nbrB2 - nbrB) % subGroupOrder SubtBigNbrMod(nbrB2, nbrB, nbrB); SubtBigNbrMod(nbrA, nbrA2, nbrA); if (BigNbrIsZero(nbrA)) { // Denominator is zero, so rho does not work. ExchangeMods(); // TestNbr <- modulus if (!ComputeDLogModSubGroupOrder(indexBase, indexExp, &Exponent, &subGroupOrder)) { return; // Cannot compute discrete logarithm. } } else { // Exponent <- (nbrB / nbrA) (mod subGroupOrder) UncompressLimbsBigInteger(nbrA, &bigNbrA); UncompressLimbsBigInteger(nbrB, &bigNbrB); BigIntModularDivisionSaveTestNbr(&bigNbrB, &bigNbrA, &subGroupOrder, &Exponent); Exponent.sign = SIGN_POSITIVE; ExchangeMods(); // TestNbr <- modulus } } modPow(primRoot, Exponent.limbs, Exponent.nbrLimbs, tmpBase.limbs); ModInvBigNbr(tmpBase.limbs, tmpBase.limbs, TestNbr, NumberLength); modmult(tmpBase.limbs, currPowerMontg, currPowerMontg); BigIntMultiply(&Exponent, &powSubGroupOrder, &tmpBase); BigIntAdd(&runningExp, &tmpBase, &runningExp); BigIntMultiply(&powSubGroupOrder, &subGroupOrder, &powSubGroupOrder); modPow(primRoot, subGroupOrder.limbs, subGroupOrder.nbrLimbs, tmpBase.limbs); memcpy(primRoot, tmpBase.limbs, NumberLength * sizeof(limb)); } if (logMachineState == BASE_PRIMITIVE_ROOT) { // Discrete logarithm was determined for this subgroup. ExponentsGOComputed[indexBase] = astFactorsGO[indexBase + 1].multiplicity; break; } if (logMachineState == CALC_LOG_BASE) { CopyBigInt(&runningExpBase, &runningExp); logMachineState = CALC_LOG_POWER; } else { // Set powSubGroupOrderBak to powSubGroupOrder. // if runningExpBase is not multiple of subGroupOrder, // discrete logarithm is runningExp/runningExpBase mod powSubGroupOrderBak. // Otherwise if runningExp is multiple of subGroupOrder, there is no logarithm. // Otherwise, divide runningExp, runnignExpBase and powSubGroupOrderBak by subGroupOrder and repeat. ExponentsGOComputed[indexBase] = astFactorsGO[indexBase + 1].multiplicity; CopyBigInt(&powSubGroupOrderBak, &powSubGroupOrder); do { BigIntRemainder(&runningExpBase, &subGroupOrder, &tmpBase); if (tmpBase.nbrLimbs > 1 || tmpBase.limbs[0].x != 0) { // runningExpBase is not multiple of subGroupOrder BigIntModularDivisionSaveTestNbr(&runningExp, &runningExpBase, &powSubGroupOrderBak, &tmpBase); CopyBigInt(&runningExp, &tmpBase); break; } BigIntRemainder(&runningExp, &subGroupOrder, &tmpBase); if (tmpBase.nbrLimbs > 1 || tmpBase.limbs[0].x != 0) { // runningExpBase is not multiple of subGroupOrder showText("There is no discrete logarithm"); DiscreteLogPeriod.sign = SIGN_NEGATIVE; return; } BigIntDivide(&runningExp, &subGroupOrder, &tmpBase); CopyBigInt(&runningExp, &tmpBase); BigIntDivide(&runningExpBase, &subGroupOrder, &tmpBase); CopyBigInt(&runningExpBase, &tmpBase); BigIntDivide(&powSubGroupOrderBak, &subGroupOrder, &tmpBase); CopyBigInt(&powSubGroupOrderBak, &tmpBase); ExponentsGOComputed[indexBase]--; if (tmpBase.nbrLimbs == 1 && tmpBase.limbs[0].x == 1) { break; } BigIntRemainder(&runningExpBase, &subGroupOrder, &tmpBase); } while (tmpBase.nbrLimbs == 1 && tmpBase.limbs[0].x == 0); CopyBigInt(&powSubGroupOrder, &powSubGroupOrderBak); // The logarithm is runningExp / runningExpBase mod powSubGroupOrder // When powSubGroupOrder is even, we cannot use Montgomery. if (powSubGroupOrder.limbs[0].x & 1) { // powSubGroupOrder is odd. BigIntModularDivisionSaveTestNbr(&runningExp, &runningExpBase, &powSubGroupOrder, &tmpBase); CopyBigInt(&runningExp, &tmpBase); } else { // powSubGroupOrder is even (power of 2). NumberLength = powSubGroupOrder.nbrLimbs; CompressLimbsBigInteger(nbrB, &runningExpBase); ComputeInversePower2(nbrB, nbrA, nbrB2); // nbrB2 is auxiliary var. CompressLimbsBigInteger(nbrB, &runningExp); multiply(nbrA, nbrB, nbrA, NumberLength, NULL); // nbrA <- quotient. UncompressLimbsBigInteger(nbrA, &runningExp); } break; } } CopyBigInt(&nbrV[indexBase], &runningExp); NumberLength = powSubGroupOrder.nbrLimbs; memcpy(TestNbr, powSubGroupOrder.limbs, NumberLength * sizeof(limb)); TestNbr[NumberLength].x = 0; GetMontgomeryParms(NumberLength); for (indexExp = 0; indexExp < indexBase; indexExp++) { // nbrV[indexBase] <- (nbrV[indexBase] - nbrV[indexExp])* // modinv(PrimesGO[indexExp]^(ExponentsGO[indexExp]), // powSubGroupOrder) NumberLength = mod.nbrLimbs; BigIntSubt(&nbrV[indexBase], &nbrV[indexExp], &nbrV[indexBase]); BigIntRemainder(&nbrV[indexBase], &powSubGroupOrder, &nbrV[indexBase]); if (nbrV[indexBase].sign == SIGN_NEGATIVE) { BigIntAdd(&nbrV[indexBase], &powSubGroupOrder, &nbrV[indexBase]); } pstFactors = &astFactorsGO[indexExp + 1]; UncompressBigInteger(pstFactors->ptrFactor, &tmpBase); BigIntPowerIntExp(&tmpBase, ExponentsGOComputed[indexExp], &tmpBase); BigIntRemainder(&tmpBase, &powSubGroupOrder, &tmpBase); NumberLength = powSubGroupOrder.nbrLimbs; CompressLimbsBigInteger(tmp2.limbs, &tmpBase); modmult(tmp2.limbs, MontgomeryMultR2, tmp2.limbs); if (NumberLength > 1 || TestNbr[0].x != 1) { // If TestNbr != 1 ... ModInvBigNbr(tmp2.limbs, tmp2.limbs, TestNbr, NumberLength); } tmpBase.limbs[0].x = 1; memset(&tmpBase.limbs[1], 0, (NumberLength - 1) * sizeof(limb)); modmult(tmpBase.limbs, tmp2.limbs, tmp2.limbs); UncompressLimbsBigInteger(tmp2.limbs, &tmpBase); BigIntMultiply(&tmpBase, &nbrV[indexBase], &nbrV[indexBase]); } BigIntRemainder(&nbrV[indexBase], &powSubGroupOrder, &nbrV[indexBase]); BigIntMultiply(&nbrV[indexBase], &logarMult, &tmpBase); BigIntAdd(&logar, &tmpBase, &logar); BigIntMultiply(&logarMult, &powSubGroupOrder, &logarMult); } multiplicity = astFactorsMod[index].multiplicity; UncompressBigInteger(ptrPrime, &bigNbrB); expon = 1; if (bigNbrB.nbrLimbs == 1 && bigNbrB.limbs[0].x == 2) { // Prime factor is 2. Base and power are odd at this moment. int lsbBase = base.limbs[0].x; int lsbPower = power.limbs[0].x; if (multiplicity > 1) { int mask = (multiplicity == 2? 3 : 7); expon = (multiplicity == 2 ? 2 : 3); if ((lsbPower & mask) == 1) { intToBigInteger(&logar, 0); intToBigInteger(&logarMult, (lsbBase == 1 ? 1 : 2)); } else if (((lsbPower - lsbBase) & mask) == 0) { intToBigInteger(&logar, 1); intToBigInteger(&logarMult, 2); } else { showText("There is no discrete logarithm"); DiscreteLogPeriod.sign = SIGN_NEGATIVE; return; } } } for (; expon < multiplicity; expon++) { // Repeated factor. // L = logar, LM = logarMult // B = base, P = power, p = prime // B^n = P (mod p^(k+1)) -> n = L + m*LM m = ? // B^(L + m*LM) = P // (B^LM) ^ m = P*B^(-L) // B^LM = r*p^k + 1, P*B^(-L) = s*p^k + 1 // (r*p^k + 1)^m = s*p^k + 1 // From binomial theorem: m = s / r (mod p) // If r = 0 and s != 0 there is no solution. // If r = 0 and s = 0 do not change LM. BigIntPowerIntExp(&bigNbrB, expon + 1, &bigNbrA); NumberLength = bigNbrA.nbrLimbs; memcpy(TestNbr, bigNbrA.limbs, NumberLength * sizeof(limb)); GetMontgomeryParms(NumberLength); BigIntRemainder(&base, &bigNbrA, &tmpBase); CompressLimbsBigInteger(baseMontg, &tmpBase); modmult(baseMontg, MontgomeryMultR2, baseMontg); modPow(baseMontg, logarMult.limbs, logarMult.nbrLimbs, primRootPwr); // B^LM tmpBase.limbs[0].x = 1; // Convert from Montgomery to standard notation. memset(&tmpBase.limbs[1], 0, (NumberLength - 1) * sizeof(limb)); modmult(primRootPwr, tmpBase.limbs, primRootPwr); // B^LM ModInvBigNbr(baseMontg, tmpBase.limbs, TestNbr, NumberLength); // B^(-1) modPow(tmpBase.limbs, logar.limbs, logar.nbrLimbs, primRoot); // B^(-L) BigIntRemainder(&power, &bigNbrA, &tmpBase); CompressLimbsBigInteger(tmp2.limbs, &tmpBase); modmult(primRoot, tmp2.limbs, primRoot); // P*B^(-L) BigIntDivide(&bigNbrA, &bigNbrB, &tmpBase); UncompressLimbsBigInteger(primRootPwr, &tmp2); BigIntDivide(&tmp2, &tmpBase, &bigNbrA); // s UncompressLimbsBigInteger(primRoot, &baseModGO); // Use baseMontGO as temp var. BigIntDivide(&baseModGO, &tmpBase, &tmp2); // r if (bigNbrA.nbrLimbs == 1 && bigNbrA.limbs[0].x == 0) { // r equals zero. if (tmp2.nbrLimbs != 1 || tmp2.limbs[0].x != 0) { // s does not equal zero. showText("There is no discrete logarithm"); DiscreteLogPeriod.sign = SIGN_NEGATIVE; return; } } else { // r does not equal zero. BigIntModularDivisionSaveTestNbr(&tmp2, &bigNbrA, &bigNbrB, &tmpBase); // m BigIntMultiply(&tmpBase, &logarMult, &tmp2); BigIntAdd(&logar, &tmp2, &logar); BigIntMultiply(&logarMult, &bigNbrB, &logarMult); } } // Based on logar and logarMult, compute DiscreteLog and DiscreteLogPeriod // using the following formulas, that can be deduced from the Chinese // Remainder Theorem: // L = logar, LM = logarMult, DL = DiscreteLog, DLP = DiscreteLogPeriod. // The modular implementation does not allow operating with even moduli. // // g <- gcd(LM, DLP) // if (L%g != DL%g) there is no discrete logarithm, so go out. // h <- LM / g // if h is odd: // t <- (L - DL) / DLP (mod h) // t <- DLP * t + DL // else // i <- DLP / g // t <- (DL - L) / LM (mod i) // t <- LM * t + L // endif // DLP <- DLP * h // DL <- t % DLP BigIntGcd(&logarMult, &DiscreteLogPeriod, &tmpBase); BigIntRemainder(&logar, &tmpBase, &bigNbrA); BigIntRemainder(&DiscreteLog, &tmpBase, &bigNbrB); if (!TestBigNbrEqual(&bigNbrA, &bigNbrB)) { showText("There is no discrete logarithm"); DiscreteLogPeriod.sign = SIGN_NEGATIVE; return; } BigIntDivide(&logarMult, &tmpBase, &tmp2); if (tmp2.limbs[0].x & 1) { // h is odd. BigIntSubt(&logar, &DiscreteLog, &tmpBase); BigIntModularDivisionSaveTestNbr(&tmpBase, &DiscreteLogPeriod, &tmp2, &bigNbrA); BigIntMultiply(&DiscreteLogPeriod, &bigNbrA, &tmpBase); BigIntAdd(&tmpBase, &DiscreteLog, &tmpBase); } else { // h is even. BigIntDivide(&DiscreteLogPeriod, &tmpBase, &bigNbrB); BigIntSubt(&DiscreteLog, &logar, &tmpBase); BigIntModularDivisionSaveTestNbr(&tmpBase, &logarMult, &bigNbrB, &bigNbrA); BigIntMultiply(&logarMult, &bigNbrA, &tmpBase); BigIntAdd(&tmpBase, &logar, &tmpBase); } BigIntMultiply(&DiscreteLogPeriod, &tmp2, &DiscreteLogPeriod); BigIntRemainder(&tmpBase, &DiscreteLogPeriod, &DiscreteLog); } #if 0 textExp.setText(DiscreteLog.toString()); textPeriod.setText(DiscreteLogPeriod.toString()); long t = OldTimeElapsed / 1000; labelStatus.setText("Time elapsed: " + t / 86400 + "d " + (t % 86400) / 3600 + "h " + ((t % 3600) / 60) + "m " + (t % 60) + "s mod mult: " + lModularMult); #endif }
BigIntRef BigIntSubtract (BigIntRef bi, BigIntRef bi2) { // for now assume that bi > bi2 if (bi2 == bi) { // create a copy of bi2, call, and release the copy BigIntRef nbi2 = BigIntCreateCopy(bi2, 0); BigIntRef answer = BigIntSubtract(bi, nbi2); BigIntRelease(nbi2); return answer; } if (!BigIntFlagIsSet(bi, kBigIntFlagNegative) && BigIntFlagIsSet(bi2, kBigIntFlagNegative)) { // add instead of subtracting bi2->flags ^= kBigIntFlagNegative; BigIntRef answer = BigIntAdd(bi, bi2); bi2->flags |= kBigIntFlagNegative; return answer; } else if (BigIntFlagIsSet(bi, kBigIntFlagNegative) && !BigIntFlagIsSet(bi2, kBigIntFlagNegative)) { bi->flags ^= kBigIntFlagNegative; BigIntRef answer = BigIntAdd(bi, bi2); answer->flags |= kBigIntFlagNegative; bi->flags |= kBigIntFlagNegative; return answer; } else if (BigIntFlagIsSet(bi, kBigIntFlagNegative) && BigIntFlagIsSet(bi2, kBigIntFlagNegative)) { // it is a negative plus a positive, or a positive minus a negative! bi2->flags ^= kBigIntFlagNegative; bi->flags ^= kBigIntFlagNegative; BigIntRef answer = BigIntSubtract(bi2, bi); bi2->flags |= kBigIntFlagNegative; bi->flags |= kBigIntFlagNegative; return answer; } if (BigIntOperatorCheck(bi, kBigIntLessThan, bi2)) { // switch the two around, and make the answer negative. BigIntRef answer = BigIntSubtract(bi2, bi); answer->flags |= kBigIntFlagNegative; return answer; } else if (BigIntOperatorCheck(bi, kBigIntEqual, bi2)) { BigIntRef answer = BigIntNew(0); return answer; } BigBool carry = BBNo; BigIntRef difference = (BigIntRef)malloc(sizeof(_BigInt)); difference->flags = 0; difference->bits = BitBufferNew((bi->binDigits / 8) + 1); difference->referenceCount = 1; difference->b10string = NULL; difference->binDigits = 0; register UInt8 outBit; for (int i = 0; i < bi->binDigits; i++) { UInt8 bit1 = BitBufferGetBit(bi->bits, i); UInt8 bit2 = 0; outBit = bit1; if (i < bi2->bits->bitCount) bit2 = BitBufferGetBit(bi2->bits, i); if (bit2) { // we need to change the output buffer if (bit1) { if (!carry) { outBit = 0; } else { // leave carry as yes outBit = 1; } } else { if (!carry) { outBit = 1; carry = BBYes; } else { outBit = 0; } } } else { if (bit1) { if (carry) { carry = BBNo; outBit = 0; } } else { if (carry) { outBit = 1; } } } // add the bit BitBufferAddBit(difference->bits, outBit); if (outBit) difference->binDigits = i + 1; } return difference; }