Example #1
0
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>");
    }
  }
}
Example #2
0
   // 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);
}
Example #3
0
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;
}
Example #4
0
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;
}
Example #5
0
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&sup2; + Im&sup2; = ");
    ptrFactorDec += strlen(ptrFactorDec);
    Bin2Dec(ReValue.limbs, ptrFactorDec, ReValue.nbrLimbs, groupLen);
    ptrFactorDec += strlen(ptrFactorDec);
    strcpy(ptrFactorDec, "&sup2; + ");
    ptrFactorDec += strlen(ptrFactorDec);
    Bin2Dec(ImValue.limbs, ptrFactorDec, ImValue.nbrLimbs, groupLen);
    ptrFactorDec += strlen(ptrFactorDec);
    strcpy(ptrFactorDec, "&sup2;");
    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>");
}
Example #6
0
/*****************************************************************************
  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;
	
}
Example #7
0
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;
}
Example #8
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(&currentExp, &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(&currentExp, &subGroupOrder, &currentExp);
          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
}
Example #9
0
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;
}