Пример #1
0
static inline void
fib_matrix_mul (mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t f, mpz_t g, mpz_t h)
{
	mpz_t r, s, t, u;

	mpz_init (r);
	mpz_init (s);
	mpz_init (t);
	mpz_init (u);

	mpz_mul (r, a, e);
	mpz_mul (s, a, f);
	mpz_mul (t, c, e);
	mpz_mul (u, c, f);

	mpz_addmul (r, b, g);
	mpz_addmul (s, b, h);
	mpz_addmul (t, d, g);
	mpz_addmul (u, d, h);

	mpz_set (a, r);
	mpz_set (b, s);
	mpz_set (c, t);
	mpz_set (d, u);

	mpz_clear (r);
	mpz_clear (s);
	mpz_clear (t);
	mpz_clear (u);
}
Пример #2
0
/*-------------------------------------------------------------------*/
static void convert_to_integer(mpz_poly_t *alg_sqrt, mpz_t n,
				mpz_t c, mpz_t m1, 
				mpz_t m0, mpz_t res) {

	/* given the completed square root, apply the homomorphism
	   to convert the polynomial to an integer. We do this
	   by evaluating alg_sqrt at -c*m0/m1, with all calculations
	   performed mod n */

	uint32 i;
	mpz_t m1_pow;
	mpz_t m0c;

	mpz_init_set(m1_pow, m1);
	mpz_poly_mod_q(alg_sqrt, n, alg_sqrt);

	mpz_init_set_ui(m0c, 0);
	mpz_submul(m0c, m0, c);
	mpz_mod(m0c, m0c, n);

	i = alg_sqrt->degree;
	mpz_set(res, alg_sqrt->coeff[i]);
	while (--i) {
		mpz_mul(res, res, m0c);
		mpz_addmul(res, m1_pow, alg_sqrt->coeff[i]);
		mpz_mul(m1_pow, m1_pow, m1);
	}
	mpz_mul(res, res, m0c);
	mpz_addmul(res, m1_pow, alg_sqrt->coeff[i]);
	mpz_mod(res, res, n);

	mpz_clear(m1_pow);
	mpz_clear(m0c);
}
Пример #3
0
static int
hgcd_ref (struct hgcd_ref *hgcd, mpz_t a, mpz_t b)
{
  mp_size_t n = MAX (mpz_size (a), mpz_size (b));
  mp_size_t s = n/2 + 1;
  mpz_t q;
  int res;

  if (mpz_size (a) <= s || mpz_size (b) <= s)
    return 0;

  res = mpz_cmp (a, b);
  if (res < 0)
    {
      mpz_sub (b, b, a);
      if (mpz_size (b) <= s)
	return 0;

      mpz_set_ui (hgcd->m[0][0], 1); mpz_set_ui (hgcd->m[0][1], 0);
      mpz_set_ui (hgcd->m[1][0], 1); mpz_set_ui (hgcd->m[1][1], 1);
    }
  else if (res > 0)
    {
      mpz_sub (a, a, b);
      if (mpz_size (a) <= s)
	return 0;

      mpz_set_ui (hgcd->m[0][0], 1); mpz_set_ui (hgcd->m[0][1], 1);
      mpz_set_ui (hgcd->m[1][0], 0); mpz_set_ui (hgcd->m[1][1], 1);
    }
  else
    return 0;

  mpz_init (q);

  for (;;)
    {
      ASSERT (mpz_size (a) > s);
      ASSERT (mpz_size (b) > s);

      if (mpz_cmp (a, b) > 0)
	{
	  if (!sdiv_qr (q, a, s, a, b))
	    break;
	  mpz_addmul (hgcd->m[0][1], q, hgcd->m[0][0]);
	  mpz_addmul (hgcd->m[1][1], q, hgcd->m[1][0]);
	}
      else
	{
	  if (!sdiv_qr (q, b, s, b, a))
	    break;
	  mpz_addmul (hgcd->m[0][0], q, hgcd->m[0][1]);
	  mpz_addmul (hgcd->m[1][0], q, hgcd->m[1][1]);
	}
    }

  mpz_clear (q);

  return 1;
}
Пример #4
0
ecc_point* existPoint(mpz_t  p){
	mpz_t l;
	mpz_init(l);
	mpz_pow_ui(l,p,3);
	mpz_addmul(l,a,p);
	mpz_add(l,l,b);
	mpz_mod(l,l,prime);
	mpz_t i;
	mpz_init_set_ui(i,0);
	mpz_t y;
	mpz_init(y);
	if (quadratic_residue(y,l,prime)==1){
		gmp_printf("entrei");

		ecc_point* r= malloc(sizeof(ecc_point));
		mpz_init_set((*r).x,p);
		mpz_init_set((*r).y,y);
		return r;
	} else
		return NULL;
/*	while(mpz_cmp(i,prime)!=0){
		mpz_set(y,i);
		mpz_pow_ui(y,y,2);
		mpz_mod(y,y,prime);
		gmp_printf(" x %Zd Y %Zd \n",l,y);
		if (mpz_cmp(y,l)==0){
			ecc_point* r= malloc(sizeof(ecc_point));
			mpz_init_set((*r).x,p);
			mpz_init_set((*r).y,i);
			return r;
		}else
			mpz_add_ui(i,i,1);
	}*/
	return NULL;
}
Пример #5
0
ecc_point* sum(ecc_point p1,ecc_point p2){
	ecc_point* result;
	result = malloc(sizeof(ecc_point));
	mpz_init((*result).x);
	mpz_init((*result).y);
	if (mpz_cmp(p1.x,p2.x)==0 && mpz_cmp(p1.y,p2.y)==0)
		result=double_p(p1);
	else
		if( mpz_cmp(p1.x,p2.x)==0 && mpz_cmpabs(p2.y,p1.y)==0)
			result=INFINITY_POINT;
		else{
			mpz_t delta_x,x,y,delta_y,s,s_2;
			mpz_init(delta_x);
			mpz_init(x); mpz_init(y);
			mpz_init(s); mpz_init(s_2);
			mpz_init(delta_y);
			mpz_sub(delta_x,p1.x,p2.x);
			mpz_sub(delta_y,p1.y,p2.y);
			mpz_mod(delta_x,delta_x,prime);
			mpz_invert(delta_x,delta_x,prime);
			mpz_mul(s,delta_x,delta_y);
			mpz_mod(s,s,prime);
			mpz_pow_ui(s_2,s,2);
			mpz_sub(x,s_2,p1.x);
			mpz_sub(x,x,p2.x);
			mpz_mod(x,x,prime);
			mpz_set((*result).x,x);
			mpz_sub(delta_x,p2.x,x);
			mpz_neg(y,p2.y);
			mpz_addmul(y,s,delta_x);
			mpz_mod(y,y,prime);
			mpz_set((*result).y,y);
		};
	return result;	
}
Пример #6
0
/*------------------------------------------------------------------------*/
static uint32 
lift_roots(sieve_fb_t *s, curr_poly_t *c, 
		uint64 p, uint32 num_roots)
{
	uint32 i;
	uint32 degree = s->degree;

	uint64_2gmp(p, s->p);
	mpz_mul(s->p2, s->p, s->p);
	mpz_tdiv_r(s->nmodp2, c->trans_N, s->p2);
	mpz_sub(s->tmp1, c->trans_m0, c->mp_sieve_size);
	mpz_tdiv_r(s->m0, s->tmp1, s->p2);

	for (i = 0; i < num_roots; i++) {

		mpz_powm_ui(s->tmp1, s->roots[i], (mp_limb_t)degree, s->p2);
		mpz_sub(s->tmp1, s->nmodp2, s->tmp1);
		if (mpz_cmp_ui(s->tmp1, (mp_limb_t)0) < 0)
			mpz_add(s->tmp1, s->tmp1, s->p2);
		mpz_tdiv_q(s->tmp1, s->tmp1, s->p);

		mpz_powm_ui(s->tmp2, s->roots[i], (mp_limb_t)(degree-1), s->p);
		mpz_mul_ui(s->tmp2, s->tmp2, (mp_limb_t)degree);
		mpz_invert(s->tmp2, s->tmp2, s->p);

		mpz_mul(s->tmp1, s->tmp1, s->tmp2);
		mpz_tdiv_r(s->tmp1, s->tmp1, s->p);
		mpz_addmul(s->roots[i], s->tmp1, s->p);
		mpz_sub(s->roots[i], s->roots[i], s->m0);
		if (mpz_cmp_ui(s->roots[i], (mp_limb_t)0) < 0)
			mpz_add(s->roots[i], s->roots[i], s->p2);
	}

	return num_roots;
}
Пример #7
0
/* multiplies b[0]+...+b[k-1]*x^(k-1)+x^k by c[0]+...+c[l-1]*x^(l-1)+x^l
   and puts the results in a[0]+...+a[k+l-1]*x^(k+l-1)
   [the leading monomial x^(k+l) is implicit].
   If monic_b (resp. monic_c) is 0, don't consider x^k in b (resp. x^l in c).
   Assumes k = l or k = l+1.
   The auxiliary array t contains at least list_mul_mem(l) entries.
   a and t should not overlap.
*/
void
list_mul (listz_t a, listz_t b, unsigned int k, int monic_b,
          listz_t c, unsigned int l, int monic_c, listz_t t)
{
  unsigned int i, po2;

  ASSERT(k == l || k == l + 1);
  
  for (po2 = l; (po2 & 1) == 0; po2 >>= 1);
  po2 = (po2 == 1);

#ifdef DEBUG
  if (Fermat && !(po2 && l == k))
    fprintf (ECM_STDOUT, "list_mul: Fermat number, but poly lengths %d and %d\n", k, l);
#endif

  if (po2 && Fermat)
    {
      if (monic_b && monic_c && l == k)
        {
          F_mul (a, b, c, l, MONIC, Fermat, t);
          monic_b = monic_c = 0;
        }
      else
        F_mul (a, b, c, l, DEFAULT, Fermat, t);
    }
  else
    LIST_MULT_N (a, b, c, l, t); /* set a[0]...a[2l-2] */

  if (k > l) /* multiply b[l]*x^l by c[0]+...+c[l-1]*x^(l-1) */
    {
      for (i = 0; i < l - 1; i++)
        mpz_addmul (a[l+i], b[l], c[i]);
      mpz_mul (a[2*l-1], b[l], c[l-1]);
    }

  /* deal with x^k and x^l */
  if (monic_b || monic_c)
    {
      mpz_set_ui (a[k + l - 1], 0);
      
      if (monic_b && monic_c) /* Single pass over a[] */
        {
          /* a += b * x^l + c * x^k, so a[i] += b[i-l]; a[i] += c[i-k] 
             if 0 <= i-l < k  or  0 <= i-k < l, respectively */
          if (k > l)
            mpz_add (a[l], a[l], b[0]);
          for (i = k; i < k + l; i++)
            {
              mpz_add (a[i], a[i], b[i-l]); /* i-l < k */
              mpz_add (a[i], a[i], c[i-k]); /* i-k < l */
            }
        }
      else if (monic_c) /* add b * x^l */
        list_add (a + l, a + l, b, k);

      else /* only monic_b, add x^k * c */
        list_add (a + k, a + k, c, l);
    }
}
Пример #8
0
// sign a hash using ECDSA, hash must be a string in base used during initialisation.
// private key and a generator point are required for it to work (look SetDomain 
// and SetKeys)
void ECDSA::Sign( char *hash, char *&r, char *&s )
{
	mpz_t z,k,rr,ss,t,u;
	ECPoint kG;

	mpz_init_set_str(z, hash, m_base);
	mpz_inits(k, rr, ss, t, u, NULL);

	do 
	{
		mpz_urandomm(k, m_st, ecc->m_n);
		ecc->MultiplePoint(k, ecc->m_G, kG);
		mpz_set(rr, kG.x);
		mpz_mod(rr, rr, ecc->m_n);
	} while (!mpz_cmp_ui(rr, 0));

	do 
	{
		mpz_set(t,z);
		mpz_addmul(t,rr,ecc->m_dA);
		mpz_set(u,k);
		mpz_invert(u,u,ecc->m_n);
		mpz_mul(ss, t, u);
		mpz_mod(ss, ss, ecc->m_n);
	} while (!mpz_cmp_ui(ss, 0));

	mpz_get_str(r, m_base, rr);
	mpz_get_str(s, m_base, ss);

	mpz_clears(z,k,rr,ss,t,u,NULL);

	return;
}
Пример #9
0
 int sign_quad() {
   // Returns sign of c0 z^2 - 2 a0 z - b0
   mpz_mul_si(t0, p->a0, -2);
   mpz_addmul(t0, p->c0, z);
   mpz_mul(t0, t0, z);
   mpz_sub(t0, t0, p->b0);
   return mpz_sgn(t0);
 }
Пример #10
0
 int sign_quad1() {
   // Returns sign of c1 z^2 - 2 a1 z - b1
   mpz_mul_si(t0, p->a1, -2);
   mpz_addmul(t0, p->c1, z);
   mpz_mul(t0, t0, z);
   mpz_sub(t0, t0, p->b1);
   return mpz_sgn(t0);
 }
void
refmpq_add (mpq_ptr w, mpq_srcptr x, mpq_srcptr y)
{
  mpz_mul    (mpq_numref(w), mpq_numref(x), mpq_denref(y));
  mpz_addmul (mpq_numref(w), mpq_denref(x), mpq_numref(y));
  mpz_mul    (mpq_denref(w), mpq_denref(x), mpq_denref(y));
  mpq_canonicalize (w);
}
Пример #12
0
/* puts in a[K-1]..a[2K-2] the K high terms of the product 
   of b[0..K-1] and c[0..K-1].
   Assumes K >= 1, and a[0..2K-2] exist.
   Needs space for list_mul_mem(K) in t.
*/
void
list_mul_high (listz_t a, listz_t b, listz_t c, unsigned int K, listz_t t)
{
#ifdef KS_MULTIPLY /* ks is faster */
  LIST_MULT_N (a, b, c, K, t);
#else
  unsigned int p, q;

  ASSERT(K > 0);
  switch (K)
    {
    case 1:
      mpz_mul (a[0], b[0], c[0]);
      return;
      
    case 2:
      mpz_mul (a[2], b[1], c[1]);
      mpz_mul (a[1], b[1], c[0]);
      mpz_addmul (a[1], b[0], c[1]);
      return;

    case 3:
      karatsuba (a + 2, b + 1, c + 1, 2, t);
      mpz_addmul (a[2], b[0], c[2]);
      mpz_addmul (a[2], b[2], c[0]);
      return;

    default:
      /* MULT is 2 for Karatsuba, 3 for Toom3, 4 for Toom4 */
      for (p = 1; MULT * p <= K; p *= MULT);
      p = (K / p) * p;
      q = K - p;
      LIST_MULT_N (a + 2 * q, b + q, c + q, p, t);
      if (q)
        {
          list_mul_high (t, b + p, c, q, t + 2 * q - 1);
          list_add (a + K - 1, a + K - 1, t + q - 1, q);
          list_mul_high (t, c + p, b, q, t + 2 * q - 1);
          list_add (a + K - 1, a + K - 1, t + q - 1, q);
        }
    }
#endif
}
Пример #13
0
/**
 * Multiplies two polynomials with appropriate mod where their coefficients are indexed into the array. 
 */
void polymul(mpz_t* rop, mpz_t* op1, unsigned int len1, mpz_t* op2, unsigned int len2, mpz_t n) {
  int i, j, t;

  for (i = 0; i < len1; i++) {
    for (j = 0; j < len2; j++) {
      t = (i + j) % len1;
      mpz_addmul(rop[t], op1[i], op2[j]);
      mpz_mod(rop[t], rop[t], n);
    }
  }
}
Пример #14
0
void poly_mod_sqr(mpz_t* px, mpz_t* ptmp, UV r, mpz_t mod)
{
    UV i, d, s;
    UV degree = r-1;

    for (i = 0; i < r; i++)
        mpz_set_ui(ptmp[i], 0);
    for (d = 0; d <= 2*degree; d++) {
        UV prindex = d % r;
        for (s = (d <= degree) ? 0 : d-degree; s <= (d/2); s++) {
            if (s*2 == d) {
                mpz_addmul( ptmp[prindex], px[s], px[s] );
            } else {
                mpz_addmul( ptmp[prindex], px[s], px[d-s] );
                mpz_addmul( ptmp[prindex], px[s], px[d-s] );
            }
        }
    }
    /* Put ptmp into px and mod n */
    for (i = 0; i < r; i++)
        mpz_mod(px[i], ptmp[i], mod);
}
Пример #15
0
/* puts in a[0]..a[K-1] the K low terms of the product 
   of b[0..K-1] and c[0..K-1].
   Assumes K >= 1, and a[0..2K-2] exist.
   Needs space for list_mul_mem(K) in t.
*/
static void
list_mul_low (listz_t a, listz_t b, listz_t c, unsigned int K, listz_t t,
	      mpz_t n)
{
  unsigned int p, q;

  ASSERT(K > 0);
  switch (K)
    {
    case 1:
      mpz_mul (a[0], b[0], c[0]);
      return;
    case 2:
      mpz_mul (a[0], b[0], c[0]);
      mpz_mul (a[1], b[0], c[1]);
      mpz_addmul (a[1], b[1], c[0]);
      return;
    case 3:
      karatsuba (a, b, c, 2, t);
      mpz_addmul (a[2], b[2], c[0]);
      mpz_addmul (a[2], b[0], c[2]);
      return;
    default:
      /* MULT is 2 for Karatsuba, 3 for Toom3, 4 for Toom4 */
      for (p = 1; MULT * p <= K; p *= MULT); /* p = greatest power of MULT <=K */
      p = (K / p) * p;
      ASSERTD(list_check(b,p,n) && list_check(c,p,n));
      LIST_MULT_N (a, b, c, p, t);
      if ((q = K - p))
        {
          list_mul_low (t, b + p, c, q, t + 2 * q - 1, n);
          list_add (a + p, a + p, t, q);
          list_mul_low (t, c + p, b, q, t + 2 * q - 1, n);
          list_add (a + p, a + p, t, q);
        }
    }
}
Пример #16
0
int existPoint1(mpz_t x, mpz_t  y){
	mpz_t exp,eq_result;
	mpz_init(eq_result);	//Equation Result
	mpz_init(exp); 			//Exponentiation Result
	mpz_pow_ui(exp,x,3);
	mpz_addmul(exp,x,a);
	mpz_add(exp,exp,b);	
	gmp_printf("%Zd x \n",exp);
	mpz_mod(exp,exp,prime);
	mpz_pow_ui(eq_result,y,2);
	mpz_mod(eq_result,eq_result,prime);
	if (mpz_cmp(eq_result,exp)==0)
		return 1;
	else
		return 0;
}
Пример #17
0
void test_ext_gcd()
{
	const char *list[][3] = {
		{"2","3","1"},
		{"2","4","2"},
		{"20","40","20"},
		{"-20","31","1"},
		{"-20","-30","10"}
	};
	int n = sizeof(list)/sizeof(list[0]);
	int correct = 0;
	test_info(stderr,"Start testing ext_gcd.");
	for(int i = 0; i < n; i++)
	{
		mpz_t a,b,c,d,e,f;
		mpz_init_set_str(a,list[i][0],10);
		mpz_init_set_str(b,list[i][1],10);
		mpz_init_set_str(c,list[i][2],10);
		mpz_init(d);
		mpz_init(e);
		mpz_init(f);
		cpt_ext_gcd(d,e,f,a,b);
		if(mpz_cmp(c,d)!=0)
		{
			test_unmatch(stderr,"test_ext_gcd",c,d);
		}
		else
		{
			mpz_mul(d,e,a);
			mpz_addmul(d,f,b);
			if(mpz_cmp(c,d)!=0)
				test_unmatch(stderr,"test_ext_gcd",c,d);
			else
				correct++;
		}
		mpz_clear(a);
		mpz_clear(b);
		mpz_clear(c);
		mpz_clear(d);
		mpz_clear(e);
		mpz_clear(f);
	}
	if(correct == n)
		test_info(stderr,"test_ext_gcd success.");
	else
		test_info(stderr,"test_ext_gcd failed.");
}
Пример #18
0
//All our byte arrays are supposed to be little endian.
static void
ecdsa_sign(unsigned char signature[96], const unsigned char digest[48], const unsigned char keyb[48]){
  unsigned char kbuf[96];
  unsigned char kexp[48];
  unsigned char point[96];
  for(int i=0; i<48; i++){
    kexp[i]=0;
  }
  mpz_t order;
  mpz_t k;
  mpz_t kinv;
  mpz_t x; //x coordinate
  mpz_t d; //digest
  mpz_t key; //key
  mpz_init(order);
  mpz_init(k);
  mpz_init(x);
  mpz_init(d);
  mpz_init(key);
  mpz_init(kinv);
  mpz_set_str(order, "39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942643", 10);
  randombytes(kbuf, 96);
  mpz_import(k, 96, -1, 1, 1, 0, kbuf);
  mpz_mod(k, k, order);
  mpz_export(kexp, NULL, -1, 1, 1, 0, k);
  p384_32_scalarmult_base(point, kexp);
  mpz_import(x, 48, 1, 1, 1, 0, point);
  mpz_mod(x, x, order);
  mpz_import(d, 48, -1, 1, 1, 0, digest);
  mpz_import(key, 48, -1, 1, 1, 0, keyb);
  mpz_invert(kinv, k, order);
  mpz_addmul(d, x, key);
  mpz_mod(d, d, order);
  mpz_mul(d, kinv, d);
  mpz_mod(d, d, order);
  for(int i=0; i<96; i++){
    signature[i]=0;
  }
  mpz_export(signature, NULL, -1, 1, 1, 0, x);
  mpz_export(signature+48, NULL, -1, 1, 1, 0, d);
  mpz_clear(order);
  mpz_clear(k);
  mpz_clear(kinv);
  mpz_clear(x);
  mpz_clear(d);
  mpz_clear(key);
}
Пример #19
0
void
testmain (int argc, char **argv)
{
  unsigned i;
  mpz_t a, b, res, ref;

  mpz_init (a);
  mpz_init (b);
  mpz_init_set_ui (res, 5);
  mpz_init (ref);

  for (i = 0; i < COUNT; i++)
    {
      mini_random_op3 (OP_MUL, MAXBITS, a, b, ref);
      if (i & 1) {
	mpz_add (ref, ref, res);
	if (mpz_fits_ulong_p (b))
	  mpz_addmul_ui (res, a, mpz_get_ui (b));
	else
	  mpz_addmul (res, a, b);
      } else {
	mpz_sub (ref, res, ref);
	if (mpz_fits_ulong_p (b))
	  mpz_submul_ui (res, a, mpz_get_ui (b));
	else
	  mpz_submul (res, a, b);
      }
      if (mpz_cmp (res, ref))
	{
	  if (i & 1)
	    fprintf (stderr, "mpz_addmul failed:\n");
	  else
	    fprintf (stderr, "mpz_submul failed:\n");
	  dump ("a", a);
	  dump ("b", b);
	  dump ("r", res);
	  dump ("ref", ref);
	  abort ();
	}
    }
  mpz_clear (a);
  mpz_clear (b);
  mpz_clear (res);
  mpz_clear (ref);
}
Пример #20
0
/* Simple polynomial multiplication */
void poly_mod_mul(mpz_t* px, mpz_t* py, mpz_t* ptmp, UV r, mpz_t mod)
{
    UV i, j, prindex;

    for (i = 0; i < r; i++)
        mpz_set_ui(ptmp[i], 0);
    for (i = 0; i < r; i++) {
        if (!mpz_sgn(px[i])) continue;
        for (j = 0; j < r; j++) {
            if (!mpz_sgn(py[j])) continue;
            prindex = (i+j) % r;
            mpz_addmul( ptmp[prindex], px[i], py[j] );
        }
    }
    /* Put ptmp into px and mod n */
    for (i = 0; i < r; i++)
        mpz_mod(px[i], ptmp[i], mod);
}
Пример #21
0
/* assuming b[0]...b[2(n-1)] are computed, computes and stores B[2n]*(2n+1)!

   t/(exp(t)-1) = sum(B[j]*t^j/j!, j=0..infinity)
   thus t = (exp(t)-1) * sum(B[j]*t^j/j!, n=0..infinity).
   Taking the coefficient of degree n+1 > 1, we get:
   0 = sum(1/(n+1-k)!*B[k]/k!, k=0..n)
   which gives:
   B[n] = -sum(binomial(n+1,k)*B[k], k=0..n-1)/(n+1).

   Let C[n] = B[n]*(n+1)!.
   Then C[n] = -sum(binomial(n+1,k)*C[k]*n!/(k+1)!,  k=0..n-1),
   which proves that the C[n] are integers.
*/
mpz_t*
mpfr_bernoulli_internal (mpz_t *b, unsigned long n)
{
  if (n == 0)
    {
      b = (mpz_t *) (*__gmp_allocate_func) (sizeof (mpz_t));
      mpz_init_set_ui (b[0], 1);
    }
  else
    {
      mpz_t t;
      unsigned long k;

      b = (mpz_t *) (*__gmp_reallocate_func)
        (b, n * sizeof (mpz_t), (n + 1) * sizeof (mpz_t));
      mpz_init (b[n]);
      /* b[n] = -sum(binomial(2n+1,2k)*C[k]*(2n)!/(2k+1)!,  k=0..n-1) */
      mpz_init_set_ui (t, 2 * n + 1);
      mpz_mul_ui (t, t, 2 * n - 1);
      mpz_mul_ui (t, t, 2 * n);
      mpz_mul_ui (t, t, n);
      mpz_fdiv_q_ui (t, t, 3); /* exact: t=binomial(2*n+1,2*k)*(2*n)!/(2*k+1)!
                               for k=n-1 */
      mpz_mul (b[n], t, b[n-1]);
      for (k = n - 1; k-- > 0;)
        {
          mpz_mul_ui (t, t, 2 * k + 1);
          mpz_mul_ui (t, t, 2 * k + 2);
          mpz_mul_ui (t, t, 2 * k + 2);
          mpz_mul_ui (t, t, 2 * k + 3);
          mpz_fdiv_q_ui (t, t, 2 * (n - k) + 1);
          mpz_fdiv_q_ui (t, t, 2 * (n - k));
          mpz_addmul (b[n], t, b[k]);
        }
      /* take into account C[1] */
      mpz_mul_ui (t, t, 2 * n + 1);
      mpz_fdiv_q_2exp (t, t, 1);
      mpz_sub (b[n], b[n], t);
      mpz_neg (b[n], b[n]);
      mpz_clear (t);
    }
  return b;
}
Пример #22
0
Файл: pow.c Проект: tomi500/MPC
/* Return non-zero iff c+i*d is an exact square (a+i*b)^2,
   with a, b both of the form m*2^e with m, e integers.
   If so, returns in a+i*b the corresponding square root, with a >= 0.
   The variables a, b must not overlap with c, d.

   We have c = a^2 - b^2 and d = 2*a*b.

   If one of a, b is exact, then both are (see algorithms.tex).

   Case 1: a <> 0 and b <> 0.
   Let a = m*2^e and b = n*2^f with m, e, n, f integers, m and n odd
   (we will treat apart the case a = 0 or b = 0).
   Then 2*a*b = m*n*2^(e+f+1), thus necessarily e+f >= -1.
   Assume e < 0, then f >= 0, then a^2 - b^2 = m^2*2^(2e) - n^2*2^(2f) cannot
   be an integer, since n^2*2^(2f) is an integer, and m^2*2^(2e) is not.
   Similarly when f < 0 (and thus e >= 0).
   Thus we have e, f >= 0, and a, b are both integers.
   Let A = 2a^2, then eliminating b between c = a^2 - b^2 and d = 2*a*b
   gives A^2 - 2c*A - d^2 = 0, which has solutions c +/- sqrt(c^2+d^2).
   We thus need c^2+d^2 to be a square, and c + sqrt(c^2+d^2) --- the solution
   we are interested in --- to be two times a square. Then b = d/(2a) is
   necessarily an integer.

   Case 2: a = 0. Then d is necessarily zero, thus it suffices to check
   whether c = -b^2, i.e., if -c is a square.

   Case 3: b = 0. Then d is necessarily zero, thus it suffices to check
   whether c = a^2, i.e., if c is a square.
*/
static int
mpc_perfect_square_p (mpz_t a, mpz_t b, mpz_t c, mpz_t d)
{
  if (mpz_cmp_ui (d, 0) == 0) /* case a = 0 or b = 0 */
    {
      /* necessarily c < 0 here, since we have already considered the case
         where x is real non-negative and y is real */
      MPC_ASSERT (mpz_cmp_ui (c, 0) < 0);
      mpz_neg (b, c);
      if (mpz_perfect_square_p (b)) /* case 2 above */
        {
          mpz_sqrt (b, b);
          mpz_set_ui (a, 0);
          return 1; /* c + i*d = (0 + i*b)^2 */
        }
    }
  else /* both a and b are non-zero */
    {
      if (mpz_divisible_2exp_p (d, 1) == 0)
        return 0; /* d must be even */
      mpz_mul (a, c, c);
      mpz_addmul (a, d, d); /* c^2 + d^2 */
      if (mpz_perfect_square_p (a))
        {
          mpz_sqrt (a, a);
          mpz_add (a, c, a); /* c + sqrt(c^2+d^2) */
          if (mpz_divisible_2exp_p (a, 1))
            {
              mpz_tdiv_q_2exp (a, a, 1);
              if (mpz_perfect_square_p (a))
                {
                  mpz_sqrt (a, a);
                  mpz_tdiv_q_2exp (b, d, 1); /* d/2 */
                  mpz_divexact (b, b, a); /* d/(2a) */
                  return 1;
                }
            }
        }
    }
  return 0; /* not a square */
}
Пример #23
0
/*-------------------------------------------------------------------------*/
static uint32
check_poly(curr_poly_t *c, mpz_t *coeffs, mpz_t lin0, 
		mpz_t gmp_N, uint32 degree) {

	uint32 i;

	mpz_set(c->gmp_help1, coeffs[degree]);
	mpz_set(c->gmp_help2, c->gmp_p);
	for (i = degree; i; i--) {
		mpz_mul(c->gmp_help1, c->gmp_help1, lin0);
		mpz_neg(c->gmp_help1, c->gmp_help1);
		mpz_addmul(c->gmp_help1, coeffs[i-1], c->gmp_help2);
		mpz_mul(c->gmp_help2, c->gmp_help2, c->gmp_p);
	}
	mpz_tdiv_r(c->gmp_help1, c->gmp_help1, gmp_N);
	if (mpz_cmp_ui(c->gmp_help1, (mp_limb_t)0) != 0) {
		printf("error: corrupt polynomial expand\n");
		return 0;
	}
	return 1;
}
Пример #24
0
static void dot_product_enc(Crypto *c, mpz_t dp, const mpz_t *a, const mpz_t *b, int size) {
  mpz_t temp, p;
  mpz_init_set_ui(temp, 0);
  mpz_init_set_ui(p, 0);

  mpz_set_ui(dp, 0);
  for (int i = 0; i < size; i++) {
    mpz_addmul(dp, a[i], b[i]);
    //mpz_add(dp, dp, temp);
  }

  c->elgamal_get_public_modulus(&p);

  mpz_sub_ui(p, p, 1);
  mpz_mod(dp, dp, p);

  encode_plain(c, dp, dp);

  mpz_clear(temp);
  mpz_clear(p);
}
Пример #25
0
/*------------------------------------------------------------------------*/
static void
lift_roots(sieve_fb_t *s, poly_coeff_t *c, uint32 p, uint32 num_roots)
{
	/* we have num_roots arithmetic progressions mod p;
	   convert the progressions to be mod p^2, using
	   Hensel lifting, and then move the origin of the
	   result trans_m0 units to the left. */

	uint32 i;
	unsigned long degree = s->degree;

	mpz_set_ui(s->p, (unsigned long)p);
	mpz_mul(s->pp, s->p, s->p);
	mpz_tdiv_r(s->nmodpp, c->trans_N, s->pp);
	mpz_tdiv_r(s->tmp3, c->trans_m0, s->pp);

	for (i = 0; i < num_roots; i++) {

		uint64_2gmp(s->roots[i], s->gmp_root);

		mpz_powm_ui(s->tmp1, s->gmp_root, degree, s->pp);
		mpz_sub(s->tmp1, s->nmodpp, s->tmp1);
		if (mpz_cmp_ui(s->tmp1, (mp_limb_t)0) < 0)
			mpz_add(s->tmp1, s->tmp1, s->pp);
		mpz_tdiv_q(s->tmp1, s->tmp1, s->p);

		mpz_powm_ui(s->tmp2, s->gmp_root, degree-1, s->p);
		mpz_mul_ui(s->tmp2, s->tmp2, degree);
		mpz_invert(s->tmp2, s->tmp2, s->p);

		mpz_mul(s->tmp1, s->tmp1, s->tmp2);
		mpz_tdiv_r(s->tmp1, s->tmp1, s->p);
		mpz_addmul(s->gmp_root, s->tmp1, s->p);
		mpz_sub(s->gmp_root, s->gmp_root, s->tmp3);
		if (mpz_cmp_ui(s->gmp_root, (unsigned long)0) < 0)
			mpz_add(s->gmp_root, s->gmp_root, s->pp);

		s->roots[i] = gmp2uint64(s->gmp_root);
	}
}
Пример #26
0
void
check_one (mpz_srcptr w, mpz_srcptr x, mpz_srcptr y)
{
  mpz_t  want, got;

  mpz_init (want);
  mpz_init (got);

  mpz_mul (want, x, y);
  mpz_add (want, w, want);
  mpz_set (got, w);
  mpz_addmul (got, x, y);
  MPZ_CHECK_FORMAT (got);
  if (mpz_cmp (want, got) != 0)
    {
      printf ("mpz_addmul fail\n");
    fail:
      mpz_trace ("w", w);
      mpz_trace ("x", x);
      mpz_trace ("y", y);
      mpz_trace ("want", want);
      mpz_trace ("got ", got);
      abort ();
    }

  mpz_mul (want, x, y);
  mpz_sub (want, w, want);
  mpz_set (got, w);
  mpz_submul (got, x, y);
  MPZ_CHECK_FORMAT (got);
  if (mpz_cmp (want, got) != 0)
    {
      printf ("mpz_submul fail\n");
      goto fail;
    }

  mpz_clear (want);
  mpz_clear (got);
}
void
sieve_xy_run_deg6(root_sieve_t *rs)
{
	uint32 i;

	sieve_xyz_t *xyz = &rs->xyzdata;
	int64 z_base = xyz->z_base;

	sieve_xy_t *xy = &rs->xydata;
	sieve_prime_t *lattice_primes = xy->lattice_primes;
	uint32 num_lattice_primes;
	msieve_obj *obj = rs->data->obj;

	double direction[3] = {0, 1, 0};
	double line_min, line_max;
	uint16 cutoff_score;
	xydata_t xydata[MAX_CRT_FACTORS];
	plane_heap_t plane_heap;

	uint64 inv_xy;
	uint64 inv_xyz;

	compute_line_size(rs->max_norm, &rs->apoly,
			rs->dbl_p, rs->dbl_d, direction,
			-10000, 10000, &line_min, &line_max);
	if (line_min > line_max)
		return;

	num_lattice_primes = xy->num_lattice_primes = 
				find_lattice_primes(rs->primes, 
					rs->num_primes, xyz->lattice_size, 
					lattice_primes, &xy->lattice_size,
					line_max - line_min);

	inv_xy = mp_modinv_2(xyz->lattice_size, xy->lattice_size);
	inv_xyz = mp_modinv_2(xy->lattice_size, xyz->lattice_size);
	uint64_2gmp(xy->lattice_size, xy->tmp1);
	uint64_2gmp(inv_xy, xy->tmp2);
	uint64_2gmp(xyz->lattice_size, xy->tmp3);
	uint64_2gmp(inv_xyz, xy->tmp4);
	mpz_mul(xy->mp_lattice_size, xy->tmp1, xy->tmp3);
	mpz_mul(xy->crt0, xy->tmp2, xy->tmp3);
	mpz_mul(xy->crt1, xy->tmp1, xy->tmp4);
	xy->dbl_lattice_size = mpz_get_d(xy->mp_lattice_size);

	xydata_alloc(lattice_primes, num_lattice_primes, 
			xyz->lattice_size, xydata);

	plane_heap.num_entries = 0;

	for (i = 0; i < xyz->num_lattices; i++) {

		lattice_t *curr_lattice_xyz = xyz->lattices + i;

		xydata_init(xydata, num_lattice_primes,
				curr_lattice_xyz, z_base);

		find_hits(rs, xydata, num_lattice_primes, 
				i, &plane_heap);
	}

	xydata_free(xydata, num_lattice_primes);

	qsort(plane_heap.entries, plane_heap.num_entries,
			sizeof(plane_t), compare_planes);
	cutoff_score = 0.9 * plane_heap.entries[0].plane.score;

	for (i = 0; i < plane_heap.num_entries; i++) {

		plane_t *curr_plane = plane_heap.entries + i;
		lattice_t *lattice_xy = &curr_plane->plane;
		lattice_t *lattice_xyz = xyz->lattices + 
					curr_plane->which_lattice_xyz;

		if (lattice_xy->score < cutoff_score)
			break;

		line_min = xyz->y_line_min[curr_plane->which_z_block];
		line_max = xyz->y_line_max[curr_plane->which_z_block];
		z_base = xyz->z_base + curr_plane->which_z_block *
					xyz->lattice_size;

		xy->apoly = rs->apoly;
		xy->apoly.coeff[3] += z_base * rs->dbl_p;
		xy->apoly.coeff[2] -= z_base * rs->dbl_d;

		mpz_set_d(xy->tmp1, line_min);
		mpz_tdiv_q(xy->y_base, xy->tmp1, xy->mp_lattice_size);
		mpz_mul(xy->y_base, xy->y_base, xy->mp_lattice_size);
		xy->y_blocks = (line_max - line_min) / xy->dbl_lattice_size;

		uint64_2gmp(lattice_xy->x, xy->tmp1);
		uint64_2gmp(lattice_xyz->x, xy->tmp2);
		mpz_mul(xy->resclass_x, xy->tmp1, xy->crt0);
		mpz_addmul(xy->resclass_x, xy->tmp2, xy->crt1);

		uint64_2gmp(lattice_xy->y, xy->tmp1);
		uint64_2gmp(lattice_xyz->y, xy->tmp2);
		mpz_mul(xy->resclass_y, xy->tmp1, xy->crt0);
		mpz_addmul(xy->resclass_y, xy->tmp2, xy->crt1);

		mpz_tdiv_r(xy->resclass_x, xy->resclass_x, 
				xy->mp_lattice_size);
		mpz_tdiv_r(xy->resclass_y, xy->resclass_y, 
				xy->mp_lattice_size);

		xy->curr_score = lattice_xyz->score + lattice_xy->score;
		rs->curr_z = z_base + lattice_xyz->z; 

		sieve_x_run_deg6(rs);

		if (obj->flags & MSIEVE_FLAG_STOP_SIEVING)
			break;
	}
}
bool CMTSumCheckVerifier::
doFinalCheck(CMTSumCheckResults& results, const MPZVector& expected)
{
  mpz_t add_predr, mul_predr, fz, betar;

  mpz_init(add_predr);
  mpz_init(mul_predr);
  mpz_init(betar);
  mpz_init(fz);

  requestVs(results.Vs);

  int mi = outLayer.logSize();
  int ni = outLayer.size();
  int mip1 = inLayer.logSize();
  int nip1 = inLayer.size();

  results.setupTime.begin_with_history();
  outLayer.computeWirePredicates(add_predr, mul_predr, results.rand, nip1, prime);
  //outLayer.add_fn(predr, results.rand.raw_vec(), mi, mip1, ni, nip1, prime);
  //outLayer.mul_fn(predr, results.rand.raw_vec(), mi, mip1, ni, nip1, prime);

  evaluate_beta(betar, z.raw_vec(), results.rand.raw_vec(), mi, prime);
  results.setupTime.end();

  // DEBUG
  //gmp_printf("[V] betar: %Zd\n", tmp);

  results.totalCheckTime.begin_with_history();
  bool success = true;
#ifndef CMTGKR_DISABLE_CHECKS
  for (int b = 0; b < conf.batchSize(); b++)
  {
    mpz_set_ui(fz, 0);

    mpz_add(tmp, results.Vs[2 * b], results.Vs[2 * b + 1]);
    mpz_addmul(fz, tmp, add_predr);

    mpz_mul(tmp, results.Vs[2 * b], results.Vs[2 * b + 1]);
    mpz_addmul(fz, tmp, mul_predr);

    modmult(fz, fz, betar, prime);

    success = mpz_cmp(expected[b], fz) == 0;
    if (!success)
    {
      cout << "[Instance " << b << "] [SumCheck] Final check failed!" << endl;
      gmp_printf("fz is: %Zd\n", fz);
      gmp_printf("expected is: %Zd\n", expected[b]);
      cout << endl;
      break;
    }
  }
#endif
  results.totalCheckTime.end();

  mpz_clear(add_predr);
  mpz_clear(mul_predr);
  mpz_clear(fz);

  return success;
}
Пример #29
0
/* binary splitting */
void
bs(unsigned long a,unsigned long b,unsigned long level,mpz_t pstack1,mpz_t qstack1,mpz_t gstack1)
{
  unsigned long mid;
  mpz_t pstack2,qstack2,gstack2;

  if (b-a==1) {

    /*
      g(b-1,b) = (6b-5)(2b-1)(6b-1)
      p(b-1,b) = b^3 * C^3 / 24
      q(b-1,b) = (-1)^b*g(b-1,b)*(A+Bb).
    */

    mpz_set_ui(pstack1,b);
    mpz_mul_ui(pstack1,pstack1,b);
    mpz_mul_ui(pstack1,pstack1,b);
    mpz_mul_ui(pstack1,pstack1,(C/24)*(C/24));
    mpz_mul_ui(pstack1,pstack1,C*24);

    mpz_set_ui(gstack1,2*b-1);
    mpz_mul_ui(gstack1,gstack1,6*b-1);
    mpz_mul_ui(gstack1,gstack1,6*b-5);

    mpz_set_ui(qstack1,b);
    mpz_mul_ui(qstack1,qstack1,B);
    mpz_add_ui(qstack1,qstack1,A);
    mpz_mul   (qstack1,qstack1,gstack1);
    if (b%2)
      mpz_neg(qstack1,qstack1);

  } else {

    mpz_init(pstack2);
    mpz_init(qstack2);
    mpz_init(gstack2);

    if (b-a==2) {
      mpz_set_ui(pstack1,(b-1));
      mpz_mul_ui(pstack1,pstack1,(b-1));
      mpz_mul_ui(pstack1,pstack1,(b-1));
      mpz_mul_ui(pstack1,pstack1,(C/24)*(C/24));
      mpz_mul_ui(pstack1,pstack1,C*24);

      mpz_set_ui(gstack1,2*(b-1)-1);
      mpz_mul_ui(gstack1,gstack1,6*(b-1)-1);
      mpz_mul_ui(gstack1,gstack1,6*(b-1)-5);

      mpz_set_ui(qstack1,(b-1));
      mpz_mul_ui(qstack1,qstack1,B);
      mpz_add_ui(qstack1,qstack1,A);
      mpz_mul   (qstack1,qstack1,gstack1);
      if ((b-1)%2)
        mpz_neg(qstack1,qstack1);

      mpz_set_ui(pstack2,b);
      mpz_mul_ui(pstack2,pstack2,b);
      mpz_mul_ui(pstack2,pstack2,b);
      mpz_mul_ui(pstack2,pstack2,(C/24)*(C/24));
      mpz_mul_ui(pstack2,pstack2,C*24);

      mpz_set_ui(gstack2,2*b-1);
      mpz_mul_ui(gstack2,gstack2,6*b-1);
      mpz_mul_ui(gstack2,gstack2,6*b-5);

      mpz_set_ui(qstack2,b);
      mpz_mul_ui(qstack2,qstack2,B);
      mpz_add_ui(qstack2,qstack2,A);
      mpz_mul   (qstack2,qstack2,gstack2);
      if (b%2)
        mpz_neg(qstack2,qstack2);

    } else {

    /*
      p(a,b) = p(a,m) * p(m,b)
      g(a,b) = g(a,m) * g(m,b)
      q(a,b) = q(a,m) * p(m,b) + q(m,b) * g(a,m)
    */

      mid = a+(b-a)*0.5224;     /* tuning parameter */

#ifdef _OPENMP
  //    #pragma omp task firstprivate(mid,a) shared(pstack1,qstack1,gstack1) if (level < 4) 
      #pragma omp task firstprivate(mid,a) shared(pstack1,qstack1,gstack1)  
         bs(a,mid,level+1,pstack1,qstack1,gstack1);

      // #pragma omp task firstprivate(mid,b) shared(pstack2,qstack2,gstack2)
           bs(mid,b,level+1,pstack2,qstack2,gstack2);
      #pragma omp taskwait 
#else
      bs(a,mid,level+1,pstack1,qstack1,gstack1);
      bs(mid,b,level+1,pstack2,qstack2,gstack2);
#endif

    }

    mpz_mul(pstack1,pstack1,pstack2);
    mpz_mul(qstack1,qstack1,pstack2);
    mpz_addmul(qstack1,qstack2,gstack1);

    if (b < terms) {
      mpz_mul(gstack1,gstack1,gstack2);
    }

    mpz_clear(pstack2);
    mpz_clear(qstack2);
    mpz_clear(gstack2);
  }
}
Пример #30
0
Файл: pow.c Проект: tomi500/MPC
/* If x^y is exactly representable (with maybe a larger precision than z),
   round it in z and return the (mpc) inexact flag in [0, 10].

   If x^y is not exactly representable, return -1.

   If intermediate computations lead to numbers of more than maxprec bits,
   then abort and return -2 (in that case, to avoid loops, mpc_pow_exact
   should be called again with a larger value of maxprec).

   Assume one of Re(x) or Im(x) is non-zero, and y is non-zero (y is real).

   Warning: z and x might be the same variable, same for Re(z) or Im(z) and y.

   In case -1 or -2 is returned, z is not modified.
*/
static int
mpc_pow_exact (mpc_ptr z, mpc_srcptr x, mpfr_srcptr y, mpc_rnd_t rnd,
               mpfr_prec_t maxprec)
{
  mpfr_exp_t ec, ed, ey;
  mpz_t my, a, b, c, d, u;
  unsigned long int t;
  int ret = -2;
  int sign_rex = mpfr_signbit (mpc_realref(x));
  int sign_imx = mpfr_signbit (mpc_imagref(x));
  int x_imag = mpfr_zero_p (mpc_realref(x));
  int z_is_y = 0;
  mpfr_t copy_of_y;

  if (mpc_realref (z) == y || mpc_imagref (z) == y)
    {
      z_is_y = 1;
      mpfr_init2 (copy_of_y, mpfr_get_prec (y));
      mpfr_set (copy_of_y, y, MPFR_RNDN);
    }

  mpz_init (my);
  mpz_init (a);
  mpz_init (b);
  mpz_init (c);
  mpz_init (d);
  mpz_init (u);

  ey = mpfr_get_z_exp (my, y);
  /* normalize so that my is odd */
  t = mpz_scan1 (my, 0);
  ey += (mpfr_exp_t) t;
  mpz_tdiv_q_2exp (my, my, t);
  /* y = my*2^ey with my odd */

  if (x_imag)
    {
      mpz_set_ui (c, 0);
      ec = 0;
    }
  else
    ec = mpfr_get_z_exp (c, mpc_realref(x));
  if (mpfr_zero_p (mpc_imagref(x)))
    {
      mpz_set_ui (d, 0);
      ed = ec;
    }
  else
    {
      ed = mpfr_get_z_exp (d, mpc_imagref(x));
      if (x_imag)
        ec = ed;
    }
  /* x = c*2^ec + I * d*2^ed */
  /* equalize the exponents of x */
  if (ec < ed)
    {
      mpz_mul_2exp (d, d, (unsigned long int) (ed - ec));
      if ((mpfr_prec_t) mpz_sizeinbase (d, 2) > maxprec)
        goto end;
    }
  else if (ed < ec)
    {
      mpz_mul_2exp (c, c, (unsigned long int) (ec - ed));
      if ((mpfr_prec_t) mpz_sizeinbase (c, 2) > maxprec)
        goto end;
      ec = ed;
    }
  /* now ec=ed and x = (c + I * d) * 2^ec */

  /* divide by two if possible */
  if (mpz_cmp_ui (c, 0) == 0)
    {
      t = mpz_scan1 (d, 0);
      mpz_tdiv_q_2exp (d, d, t);
      ec += (mpfr_exp_t) t;
    }
  else if (mpz_cmp_ui (d, 0) == 0)
    {
      t = mpz_scan1 (c, 0);
      mpz_tdiv_q_2exp (c, c, t);
      ec += (mpfr_exp_t) t;
    }
  else /* neither c nor d is zero */
    {
      unsigned long v;
      t = mpz_scan1 (c, 0);
      v = mpz_scan1 (d, 0);
      if (v < t)
        t = v;
      mpz_tdiv_q_2exp (c, c, t);
      mpz_tdiv_q_2exp (d, d, t);
      ec += (mpfr_exp_t) t;
    }

  /* now either one of c, d is odd */

  while (ey < 0)
    {
      /* check if x is a square */
      if (ec & 1)
        {
          mpz_mul_2exp (c, c, 1);
          mpz_mul_2exp (d, d, 1);
          ec --;
        }
      /* now ec is even */
      if (mpc_perfect_square_p (a, b, c, d) == 0)
        break;
      mpz_swap (a, c);
      mpz_swap (b, d);
      ec /= 2;
      ey ++;
    }

  if (ey < 0)
    {
      ret = -1; /* not representable */
      goto end;
    }

  /* Now ey >= 0, it thus suffices to check that x^my is representable.
     If my > 0, this is always true. If my < 0, we first try to invert
     (c+I*d)*2^ec.
  */
  if (mpz_cmp_ui (my, 0) < 0)
    {
      /* If my < 0, 1 / (c + I*d) = (c - I*d)/(c^2 + d^2), thus a sufficient
         condition is that c^2 + d^2 is a power of two, assuming |c| <> |d|.
         Assume a prime p <> 2 divides c^2 + d^2,
         then if p does not divide c or d, 1 / (c + I*d) cannot be exact.
         If p divides both c and d, then we can write c = p*c', d = p*d',
         and 1 / (c + I*d) = 1/p * 1/(c' + I*d'). This shows that if 1/(c+I*d)
         is exact, then 1/(c' + I*d') is exact too, and we are back to the
         previous case. In conclusion, a necessary and sufficient condition
         is that c^2 + d^2 is a power of two.
      */
      /* FIXME: we could first compute c^2+d^2 mod a limb for example */
      mpz_mul (a, c, c);
      mpz_addmul (a, d, d);
      t = mpz_scan1 (a, 0);
      if (mpz_sizeinbase (a, 2) != 1 + t) /* a is not a power of two */
        {
          ret = -1; /* not representable */
          goto end;
        }
      /* replace (c,d) by (c/(c^2+d^2), -d/(c^2+d^2)) */
      mpz_neg (d, d);
      ec = -ec - (mpfr_exp_t) t;
      mpz_neg (my, my);
    }

  /* now ey >= 0 and my >= 0, and we want to compute
     [(c + I * d) * 2^ec] ^ (my * 2^ey).

     We first compute [(c + I * d) * 2^ec]^my, then square ey times. */
  t = mpz_sizeinbase (my, 2) - 1;
  mpz_set (a, c);
  mpz_set (b, d);
  ed = ec;
  /* invariant: (a + I*b) * 2^ed = ((c + I*d) * 2^ec)^trunc(my/2^t) */
  while (t-- > 0)
    {
      unsigned long int v, w;
      /* square a + I*b */
      mpz_mul (u, a, b);
      mpz_mul (a, a, a);
      mpz_submul (a, b, b);
      mpz_mul_2exp (b, u, 1);
      ed *= 2;
      if (mpz_tstbit (my, t)) /* multiply by c + I*d */
        {
          mpz_mul (u, a, c);
          mpz_submul (u, b, d); /* ac-bd */
          mpz_mul (b, b, c);
          mpz_addmul (b, a, d); /* bc+ad */
          mpz_swap (a, u);
          ed += ec;
        }
      /* remove powers of two in (a,b) */
      if (mpz_cmp_ui (a, 0) == 0)
        {
          w = mpz_scan1 (b, 0);
          mpz_tdiv_q_2exp (b, b, w);
          ed += (mpfr_exp_t) w;
        }
      else if (mpz_cmp_ui (b, 0) == 0)
        {
          w = mpz_scan1 (a, 0);
          mpz_tdiv_q_2exp (a, a, w);
          ed += (mpfr_exp_t) w;
        }
      else
        {
          w = mpz_scan1 (a, 0);
          v = mpz_scan1 (b, 0);
          if (v < w)
            w = v;
          mpz_tdiv_q_2exp (a, a, w);
          mpz_tdiv_q_2exp (b, b, w);
          ed += (mpfr_exp_t) w;
        }
      if (   (mpfr_prec_t) mpz_sizeinbase (a, 2) > maxprec
          || (mpfr_prec_t) mpz_sizeinbase (b, 2) > maxprec)
        goto end;
    }
  /* now a+I*b = (c+I*d)^my */

  while (ey-- > 0)
    {
      unsigned long sa, sb;

      /* square a + I*b */
      mpz_mul (u, a, b);
      mpz_mul (a, a, a);
      mpz_submul (a, b, b);
      mpz_mul_2exp (b, u, 1);
      ed *= 2;

      /* divide by largest 2^n possible, to avoid many loops for e.g.,
         (2+2*I)^16777216 */
      sa = mpz_scan1 (a, 0);
      sb = mpz_scan1 (b, 0);
      sa = (sa <= sb) ? sa : sb;
      mpz_tdiv_q_2exp (a, a, sa);
      mpz_tdiv_q_2exp (b, b, sa);
      ed += (mpfr_exp_t) sa;

      if (   (mpfr_prec_t) mpz_sizeinbase (a, 2) > maxprec
          || (mpfr_prec_t) mpz_sizeinbase (b, 2) > maxprec)
        goto end;
    }

  ret = mpfr_set_z (mpc_realref(z), a, MPC_RND_RE(rnd));
  ret = MPC_INEX(ret, mpfr_set_z (mpc_imagref(z), b, MPC_RND_IM(rnd)));
  mpfr_mul_2si (mpc_realref(z), mpc_realref(z), ed, MPC_RND_RE(rnd));
  mpfr_mul_2si (mpc_imagref(z), mpc_imagref(z), ed, MPC_RND_IM(rnd));

 end:
  mpz_clear (my);
  mpz_clear (a);
  mpz_clear (b);
  mpz_clear (c);
  mpz_clear (d);
  mpz_clear (u);

  if (ret >= 0 && x_imag)
    fix_sign (z, sign_rex, sign_imx, (z_is_y) ? copy_of_y : y);

  if (z_is_y)
    mpfr_clear (copy_of_y);

  return ret;
}