static enum eExprErr ComputeExpr(char *expr, BigInteger *ExpressionResult) { int i, shLeft; int retcode; limb carry; boolean leftNumberFlag = FALSE; int exprIndexAux, offset; enum eExprErr SubExprResult; int len; limb largeLen; limb *ptrLimb; BigInteger *pBigInt; int c; int startStackIndex = stackIndex; exprLength = (int)strlen(expr); while (exprIndex < exprLength) { char charValue; charValue = *(expr+exprIndex); if (charValue == ' ' || charValue == 9) { // Ignore spaces and horizontal tabs. exprIndex++; continue; } if (charValue == '^') { // Caret is exponentiation operation. charValue = OPER_POWER; exprIndex++; } else if (charValue == '*' && *(expr + exprIndex + 1) == '*') { // Double asterisk is exponentiation operation too. charValue = OPER_POWER; exprIndex += 2; } else if (charValue == '*') { charValue = OPER_MULTIPLY; exprIndex++; } else if (charValue == '/') { charValue = OPER_DIVIDE; exprIndex++; } else if (charValue == '%') { charValue = OPER_REMAINDER; exprIndex++; } else if (charValue == '+') { charValue = OPER_PLUS; exprIndex++; } else if (charValue == '-') { charValue = OPER_MINUS; exprIndex++; } else if (charValue == '<' && *(expr + exprIndex + 1) == '=') { charValue = OPER_NOT_GREATER; exprIndex += 2; } else if (charValue == '>' && *(expr + exprIndex + 1) == '=') { charValue = OPER_NOT_LESS; exprIndex += 2; } else if (charValue == '!' && *(expr + exprIndex + 1) == '=') { charValue = OPER_NOT_EQUAL; exprIndex += 2; } else if (charValue == '=' && *(expr + exprIndex + 1) == '=') { charValue = OPER_EQUAL; exprIndex += 2; } else if (charValue == '>') { charValue = OPER_GREATER; exprIndex++; } else if (charValue == '<') { charValue = OPER_LESS; exprIndex++; } else if ((charValue & 0xDF) == 'N' && (*(expr + exprIndex + 1) & 0xDF) == 'O' && (*(expr + exprIndex + 2) & 0xDF) == 'T') { charValue = OPER_NOT; exprIndex += 3; } else if ((charValue & 0xDF) == 'A' && (*(expr + exprIndex + 1) & 0xDF) == 'N' && (*(expr + exprIndex + 2) & 0xDF) == 'D') { charValue = OPER_AND; exprIndex += 3; } else if ((charValue & 0xDF) == 'O' && (*(expr + exprIndex + 1) & 0xDF) == 'R') { charValue = OPER_OR; exprIndex += 2; } else if ((charValue & 0xDF) == 'X' && (*(expr + exprIndex + 1) & 0xDF) == 'O' && (*(expr + exprIndex + 2) & 0xDF) == 'R') { charValue = OPER_XOR; exprIndex += 3; } else if ((charValue & 0xDF) == 'S' && (*(expr + exprIndex + 1) & 0xDF) == 'H' && (*(expr + exprIndex + 2) & 0xDF) == 'L') { charValue = OPER_SHL; exprIndex += 3; } else if ((charValue & 0xDF) == 'S' && (*(expr + exprIndex + 1) & 0xDF) == 'H' && (*(expr + exprIndex + 2) & 0xDF) == 'R') { charValue = OPER_SHR; exprIndex += 3; } else if (charValue == '!') { // Calculating factorial. if (leftNumberFlag == FALSE) { return EXPR_SYNTAX_ERROR; } if (stackValues[stackIndex].nbrLimbs > 1) { return EXPR_INTERM_TOO_HIGH; } #ifdef FACTORIZATION_APP if (stackValues[stackIndex].limbs[0].x < 0 || stackValues[stackIndex].limbs[0].x >= 47177) #else if (stackValues[stackIndex].limbs[0].x < 0 || stackValues[stackIndex].limbs[0].x >= 5984) #endif { return EXPR_INTERM_TOO_HIGH; } factorial(&stackValues[stackIndex], (int)stackValues[stackIndex].limbs[0].x); exprIndex++; continue; } else if (charValue == '#') { // Calculating primorial. if (leftNumberFlag == FALSE) { return EXPR_SYNTAX_ERROR; } if (stackValues[stackIndex].nbrLimbs > 2) { return EXPR_INTERM_TOO_HIGH; } if (stackValues[stackIndex].nbrLimbs == 2) { largeLen.x = stackValues[stackIndex].limbs[0].x + (stackValues[stackIndex].limbs[1].x << BITS_PER_GROUP); } else { largeLen.x = stackValues[stackIndex].limbs[0].x; } len = (int)largeLen.x; #ifdef FACTORIZATION_APP if (len < 0 || len > 460490) #else if (len < 0 || len > 46049) #endif { return EXPR_INTERM_TOO_HIGH; } primorial(&stackValues[stackIndex], (int)stackValues[stackIndex].limbs[0].x); exprIndex++; continue; } else if ((retcode = func(expr, ExpressionResult, "GCD", 2, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } BigIntGcd(&stackValues[stackIndex], &stackValues[stackIndex + 1], &stackValues[stackIndex]); leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "MODPOW", 3, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = BigIntGeneralModularPower(&stackValues[stackIndex], &stackValues[stackIndex + 1], &stackValues[stackIndex + 2], &stackValues[stackIndex]); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "MODINV", 2, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputeModInv(); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } #ifdef FACTORIZATION_FUNCTIONS else if ((retcode = func(expr, ExpressionResult, "TOTIENT", 1, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputeTotient(); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "NUMDIVS", 1, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputeNumDivs(); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "SUMDIVS", 1, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputeSumDivs(); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "CONCATFACT", 2, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputeConcatFact(); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } #endif else if ((retcode = func(expr, ExpressionResult, "SUMDIGITS", 2, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputeSumDigits(); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "NUMDIGITS", 2, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputeNumDigits(); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "REVDIGITS", 2, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputeRevDigits(); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "ISPRIME", 1, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } #ifdef FACTORIZATION_APP if (BpswPrimalityTest(&stackValues[stackIndex], NULL) == 0) #else if (BpswPrimalityTest(&stackValues[stackIndex]) == 0) #endif { // Argument is a probable prime. intToBigInteger(&stackValues[stackIndex], -1); } else { // Argument is not a probable prime. intToBigInteger(&stackValues[stackIndex], 0); } leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "F", 1, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputeFibLucas(0); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "L", 1, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputeFibLucas(2); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "P", 1, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputePartition(); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "N", 1, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputeNext(); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "B", 1, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputeBack(); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } else if ((charValue & 0xDF) == 'X') { if (leftNumberFlag || valueX.nbrLimbs == 0) { return EXPR_SYNTAX_ERROR; } CopyBigInt(&stackValues[stackIndex], &valueX); valueXused = TRUE; exprIndex++; leftNumberFlag = TRUE; continue; } else if ((charValue & 0xDF) == 'C') { if (leftNumberFlag || valueX.nbrLimbs == 0) { return EXPR_SYNTAX_ERROR; } intToBigInteger(&stackValues[stackIndex], counterC); valueXused = TRUE; exprIndex++; leftNumberFlag = TRUE; continue; } else if (charValue == '(') { if (leftNumberFlag == TRUE) { return EXPR_SYNTAX_ERROR; } if (stackIndex >= PAREN_STACK_SIZE) { return EXPR_TOO_MANY_PAREN; } stackOperators[stackIndex++] = charValue; exprIndex++; continue; } else if (charValue == ')' || charValue == ',') { if (leftNumberFlag == 0) { return EXPR_SYNTAX_ERROR; } while (stackIndex > startStackIndex && stackOperators[stackIndex - 1] != '(') { if ((SubExprResult = ComputeSubExpr()) != 0) { return SubExprResult; } } if (stackIndex == startStackIndex) { break; } if (charValue == ',') { return EXPR_PAREN_MISMATCH; } stackIndex--; /* Discard ')' */ stackValues[stackIndex] = stackValues[stackIndex + 1]; leftNumberFlag = 1; exprIndex++; continue; } else if (charValue >= '0' && charValue <= '9') { exprIndexAux = exprIndex; if (charValue == '0' && exprIndexAux < exprLength - 2 && *(expr+exprIndexAux + 1) == 'x') { // hexadecimal exprIndexAux++; while (exprIndexAux < exprLength - 1) { charValue = *(expr+exprIndexAux + 1); if ((charValue >= '0' && charValue <= '9') || (charValue >= 'A' && charValue <= 'F') || (charValue >= 'a' && charValue <= 'f')) { exprIndexAux++; } else { break; } } // Generate big integer from hexadecimal number from right to left. carry.x = 0; i = 0; // limb number. shLeft = 0; offset = exprIndexAux; ptrLimb = &stackValues[stackIndex].limbs[0]; for (; exprIndexAux >= exprIndex + 2; exprIndexAux--) { c = *(expr + exprIndexAux); if (c >= '0' && c <= '9') { c -= '0'; } else if (c >= 'A' && c <= 'F') { c -= 'A' - 10; } else { c -= 'a' - 10; } carry.x += c << shLeft; shLeft += 4; // 4 bits per hex digit. if (shLeft >= BITS_PER_GROUP) { shLeft -= BITS_PER_GROUP; (ptrLimb++)->x = carry.x & MAX_VALUE_LIMB; carry.x = c >> (4-shLeft); } } if (carry.x != 0 || ptrLimb == &stackValues[stackIndex].limbs[0]) { (ptrLimb++)->x = carry.x; } exprIndex = offset+1; stackValues[stackIndex].nbrLimbs = (int)(ptrLimb - &stackValues[stackIndex].limbs[0]); stackValues[stackIndex].sign = SIGN_POSITIVE; }
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 }