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>"); } } }
// implement of Multiplication by using booth algorithm // result = a * b BigInt* DoMul(BigInt* a, BigInt* b, BigInt* result) { int i; BigInt c, t; ToOppositeNumberComplement(a, &c); // c = [-a] complement memset(t.bit, 0, BIG_INT_BIT_LEN); // init 0 // filter for (i = SIGN_BIT; i > 0 && b->bit[i] == b->bit[i - 1]; i--); while (i > 0) { ShiftArithmeticLeft(&t, 1, &t); if (b->bit[i] != b->bit[i - 1]) { DoAdd(&t, b->bit[i - 1] > b->bit[i] ? a : &c, &t); } i--; } // the last shift ShiftArithmeticLeft(&t, 1, &t); if (b->bit[0] != 0) { DoAdd(&t, &c, &t); } return CopyBigInt(&t, result); }
// implement of pow by using binary pow BigInt* DoPow(BigInt* a, BigInt* b, BigInt* result) { int i, len; BigInt t, buf; CopyBigInt(a, &buf); StrToBigInt("1", &t); len = GetTrueValueLen(b); for (i = 0; i < len; i++) { if (b->bit[i] == 1) DoMul(&t, &buf, &t); // t = t * buf DoMul(&buf, &buf, &buf); // buf = buf * buf } return CopyBigInt(&t, result); }
void gaussianText(char *valueText, int doFactorization) { enum eExprErr rc; #ifndef __EMSCRIPTEN__ groupLen = 6; #endif rc = ComputeGaussianExpression(valueText, value); output[0] = '2'; ptrOutput = &output[1]; if (rc == EXPR_OK) { CopyBigInt(&ReValue, &value[0]); CopyBigInt(&ImValue, &value[1]); if (doFactorization != '0') { w(lang ? "<p>Factores de " : "<p>Factors of "); } else { w(lang ? "<p>El valor es " : "<p>Value is equal to "); } showNumber(&ReValue, &ImValue); if (doFactorization != '0') { GaussianFactorization(); } } if (rc == EXPR_OK) { showElapsedTime(&ptrOutput); } else { textError(ptrOutput, rc); ptrOutput = output + strlen(output); } strcat(ptrOutput, lang ? "<p>" COPYRIGHT_SPANISH "</p>" : "<p>" COPYRIGHT_ENGLISH "</p>"); }
static void showNumber(BigInteger *real, BigInteger *imag) { BigInteger Tmp; CopyBigInt(&Tmp, imag); if (real->sign == SIGN_NEGATIVE) { w("-"); } Bin2Dec(real->limbs, ptrOutput, real->nbrLimbs, groupLen); ptrOutput += strlen(ptrOutput); if (imag->sign == SIGN_POSITIVE) { w(" + "); } else { w(" - "); } Bin2Dec(Tmp.limbs, ptrOutput, Tmp.nbrLimbs, groupLen); ptrOutput += strlen(ptrOutput); w(" i"); }
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 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>"); }
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; }
// implement of division by using binary search // result = a / b BigInt* DoDiv(BigInt* a, BigInt* b, BigInt* result, BigInt* remainder) { int low, high, mid; BigInt c, d, e, t; low = 0; // the min of left shift high = GetMaxLeftShiftLen(b); // the max of left shift memset(t.bit, 0, BIG_INT_BIT_LEN); // init 0 CopyBigInt(a, &c); // c = a // if a sign == b sign, do subtraction if (a->bit[SIGN_BIT] == b->bit[SIGN_BIT]) { t.bit[SIGN_BIT] = POSITIVE; while (1) { while (low <= high) { mid = (low + high) / 2; ShiftArithmeticLeft(b, mid, &d); DoSub(&c, &d, &e); // e = c - d // e >= 0 if (d.bit[SIGN_BIT] == e.bit[SIGN_BIT] || IsZero(&e)) low = mid + 1; else high = mid - 1; } // high == -1 means c - b < 0 if (high != -1) { t.bit[high] = 1; // here unified the operation // it can improve i think ShiftArithmeticLeft(b, high, &d); // c = c - d, let c be the next dividend DoSub(&c, &d, &c); low = 0; high--; } else { // now the dividend c is the remainder CopyBigInt(&c, remainder); break; } } } // if a sign != b sign, do addition else { t.bit[SIGN_BIT] = NEGATIVE; while (1) { while (low <= high) { mid = (low + high) / 2; ShiftArithmeticLeft(b, mid, &d); DoAdd(&c, &d, &e); // e = c + d // e >= 0 if (d.bit[SIGN_BIT] != e.bit[SIGN_BIT] || IsZero(&e)) low = mid + 1; else high = mid - 1; } // high == -1 means c - b < 0 if (high != -1) { t.bit[high] = 1; // here unified the operation // it can improve i think ShiftArithmeticLeft(b, high, &d); // c = c + d, let c be the next dividend DoAdd(&c, &d, &c); low = 0; high--; } else { // now the dividend c is the remainder CopyBigInt(&c, remainder); break; } } } return ToComplement(&t, result); }
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 }