int aws_mp_n_root()

in AWSCognitoIdentityProvider/Internal/JKBigInteger/LibTomMath/tommath.c [730:832]


int aws_mp_n_root(aws_mp_int *a, aws_mp_digit b, aws_mp_int *c)
{
  aws_mp_int t1, t2, t3;
  int     res, neg;

  /* input must be positive if b is even */
  if ((b & 1) == 0 && a->sign == AWS_MP_NEG) {
    return AWS_MP_VAL;
  }

  if ((res = aws_mp_init(&t1)) != AWS_MP_OKAY) {
    return res;
  }

  if ((res = aws_mp_init(&t2)) != AWS_MP_OKAY) {
    goto LBL_T1;
  }

  if ((res = aws_mp_init(&t3)) != AWS_MP_OKAY) {
    goto LBL_T2;
  }

  /* if a is negative fudge the sign but keep track */
  neg     = a->sign;
  a->sign = AWS_MP_ZPOS;

  /* t2 = 2 */
    aws_mp_set(&t2, 2);

  do {
    /* t1 = t2 */
    if ((res = aws_mp_copy(&t2, &t1)) != AWS_MP_OKAY) {
      goto LBL_T3;
    }

    /* t2 = t1 - ((t1**b - a) / (b * t1**(b-1))) */
    
    /* t3 = t1**(b-1) */
    if ((res = aws_mp_expt_d(&t1, b - 1, &t3)) != AWS_MP_OKAY) {
      goto LBL_T3;
    }

    /* numerator */
    /* t2 = t1**b */
    if ((res = aws_mp_mul(&t3, &t1, &t2)) != AWS_MP_OKAY) {
      goto LBL_T3;
    }

    /* t2 = t1**b - a */
    if ((res = aws_mp_sub(&t2, a, &t2)) != AWS_MP_OKAY) {
      goto LBL_T3;
    }

    /* denominator */
    /* t3 = t1**(b-1) * b  */
    if ((res = aws_mp_mul_d(&t3, b, &t3)) != AWS_MP_OKAY) {
      goto LBL_T3;
    }

    /* t3 = (t1**b - a)/(b * t1**(b-1)) */
    if ((res = aws_mp_div(&t2, &t3, &t3, NULL)) != AWS_MP_OKAY) {
      goto LBL_T3;
    }

    if ((res = aws_mp_sub(&t1, &t3, &t2)) != AWS_MP_OKAY) {
      goto LBL_T3;
    }
  }  while (aws_mp_cmp(&t1, &t2) != AWS_MP_EQ);

  /* result can be off by a few so check */
  for (;;) {
    if ((res = aws_mp_expt_d(&t1, b, &t2)) != AWS_MP_OKAY) {
      goto LBL_T3;
    }

    if (aws_mp_cmp(&t2, a) == AWS_MP_GT) {
      if ((res = aws_mp_sub_d(&t1, 1, &t1)) != AWS_MP_OKAY) {
         goto LBL_T3;
      }
    } else {
      break;
    }
  }

  /* reset the sign of a first */
  a->sign = neg;

  /* set the result */
    aws_mp_exch(&t1, c);

  /* set the sign of the result */
  c->sign = neg;

  res = AWS_MP_OKAY;

LBL_T3:
aws_mp_clear(&t3);
LBL_T2:
aws_mp_clear(&t2);
LBL_T1:
aws_mp_clear(&t1);
  return res;
}