Exemple #1
0
void Garner(long t, verylong *zm, verylong *zv, verylong *zx)
/* solution of the Chinese remaider theorem */
{
  long i, j;
  verylong za = 0, zb = 0, zu = 0, zC[CRT_SIZE];

  for (i = 0; i < CRT_SIZE; i++) zC[i] = 0;
  for (i = 1; i < t; i++) {
    zone(&zC[i]);
    for (j = 0; j <= i - 1; j++) {
      zinvmod(zm[j], zm[i], &zu);
      zmulmod(zu, zC[i], zm[i], &za);
      zcopy(za, &zC[i]);
    }
  }
  zcopy(zv[0], &zu);
  zcopy(zu, zx);
  for (i = 1; i < t; i++) {
    zsub(zv[i], *zx, &za);
    zmulmod(za, zC[i], zm[i], &zu);
    zone(&za);
    for (j = 0; j <= i - 1; j++) {
      zmul(za, zm[j], &zb);
      zcopy(zb, &za);
    }
    zmul(za, zu, &zb);
    zadd(*zx, zb, &za);
    zcopy(za, zx);
  }
  zfree(&za);
  zfree(&zb);
  zfree(&zu);
  for (i = 0; i < CRT_SIZE; i++) zfree(&zC[i]);
}
void Montgomery_exponentiation(char *e, long b, long l, long t,
                               verylong zR, verylong zm,
                               verylong zx, verylong *zA)
{
  long i;
  verylong za = 0, zb = 0, zxp = 0;

  zmulmod(zR, zR, zm, &zb);
  Montgomery_multiplication(b, l, zm, zx, zb, &zxp);
  zmod(zR, zm, zA);
  for (i = t; i >= 0; i--) {
    Montgomery_multiplication(b, l, zm, *zA, *zA, &za);
    zcopy(za, zA);
    if (e[i] == 1) {
      Montgomery_multiplication(b, l, zm , *zA, zxp, &za);
      zcopy(za, zA);
    }
    #ifdef DEBUG
    zwriteln(*zA);
    #endif
  }
  zone(&zxp);
  Montgomery_multiplication(b, l, zm, *zA, zxp, &za);
  zcopy(za, zA);
  zfree(&za);
  zfree(&zb);
  zfree(&zxp);
}
Exemple #3
0
void RSA_exponentiation(verylong zx, verylong zd,
                        verylong zp, verylong zq,
                        verylong *zM)
{
  verylong zdp = 0, zdq = 0, zp1 = 0, zq1 = 0;
  verylong zm[2], zv[2];

  zsadd(zp, - 1l, &zp1);
  zsadd(zq, - 1l, &zq1);
  zmod(zd, zp1, &zdp);
  zmod(zd, zq1, &zdq);
  zm[0] = zm[1] = zv[0] = zv[1] = 0;
  zcopy(zp, &zm[0]);
  zcopy(zq, &zm[1]);
  zexpmod(zx, zdp, zp, &zv[0]);
  zexpmod(zx, zdq, zq, &zv[1]);
  Garner(2l, zm, zv, zM);
  zfree(&zdp);
  zfree(&zdq);
  zfree(&zp1);
  zfree(&zq1);
  zfree(&zm[0]);
  zfree(&zm[1]);
  zfree(&zv[0]);
  zfree(&zv[1]);
}
Exemple #4
0
void srk_exp(long exp, long k, verylong zg, verylong *zA)
{
  long f[32], i, j, l, t;
  verylong za = 0, *zg1;

  l = pow(2, k);
  zg1 = calloc(l, sizeof(verylong));
  assert(zg1 != 0);
  k_ary_string_replacement(exp, k, f, &t);
  zcopy(zg, &zg1[1]);
  for (i = 2; i <= k; i++) {
    j = pow(2, i - 1) - 1;
    l = pow(2, i) - 1;
    zsq(zg1[j], &za);
    zmul(za, zg, &zg1[l]);
  }
  zone(zA);
  for (i = t - 1; i >= 0; i--) {
    zsq(*zA, &za);
    zcopy(za, zA);
    j = f[i];
    if (j != 0) {
      zmul(*zA, zg1[j], &za);
      zcopy(za, zA);
    }
  }
  free(zg1);
  zfree(&za);
}
Exemple #5
0
int BabyStepGiantStep(verylong zalpha, verylong zbeta,
                      verylong zn, verylong zp, verylong *zx)
/* given a generator alpha of a cyclic group G of
   order n and an element beta compute the discrete
   logarithm x returns 0 if not enough memory
   for the problem 1 otherwise */
{
  long i, j, m;
  static verylong za = 0, zd = 0, zg = 0, zm = 0;
  struct Element *element, temp;

  zsqrt(zn, &za, &zd);
  zsadd(za, 1l, &zm);
  m = ztoint(zm);
  element = (struct Element *) malloc(m * sizeof(struct Element));
  if (element == 0) return 0;
  zone(&zd);
  /* construct table */
  for (i = 0; i < m; i++) {
    element[i].index = i;
    element[i].alpha_index = 0;
    zcopy(zd, &element[i].alpha_index);
    zmul(zd, zalpha, &za);
    zmod(za, zp, &zd);
  }
  /* sort on second values */
  for (i = 0; i < m - 1; i++) {
    for (j = i + 1; j < m; j++) {
      if (zcompare(element[i].alpha_index, element[j].alpha_index) > 0) {
        temp = element[i];
        element[i] = element[j];
        element[j] = temp;
      }
    }
  }
  zinvmod(zalpha, zp, &za);
  zexp(za, zm, &zg);
  zmod(zg, zp, &zd);
  zcopy(zbeta, &zg);
  for (i = 0; i < m; i++) {
    printf("%d ", element[i].index);
    zwriteln(element[i].alpha_index);
  }
  for (i = 0; i < m; i++) {
    j = Find(m, zg, element);
    if (j != - 1) {
      zsmul(zm, i, &za);
      zsadd(za, j, zx);
      for (j = 0; j < m; j++)
        zfree(&element[j].alpha_index);
      free(element);
      return 1;
    }
    zmul(zg, zd, &za);
    zmod(za, zp, &zg);
  }
  return 0;
}
void radix_representation(long b, long n, long *a, verylong za)
{
  long i = 0;
  verylong zb = 0, zq = 0, zr = 0, zx = 0;

  zintoz(b, &zb);
  zcopy(za, &zx);
  do {
    zdiv(zx, zb, &zq, &zr);
    a[i++] = ztoint(zr);
    zcopy(zq, &zx);
  } while (zscompare(zq, 0l) != 0);
  while (i < n) a[i++] = 0;
  zfree(&zb);
  zfree(&zq);
  zfree(&zr);
  zfree(&zx);
}
Exemple #7
0
int Miller_Rabin(long t, verylong zn)
{
  int value = 1;
  long i, j, s = 0;
  verylong za = 0, zb = 0, zn1 = 0, zr = 0, zy = 0;

  if (zodd(zn)) {
    if (zscompare(zn, 3l) > 0) {
      zsadd(zn, - 1l, &zn1);
      zcopy(zn1, &zr);
      while (!zodd(zr)) {
        s++;
        zrshift(zr, 1l, &za);
        zcopy(za, &zr);
      }
      for (i = 1; value && i <= t; i++) {
        do zrandomb(zn1, &za); while (zscompare(za, 2l) < 0);
        zexpmod(za, zr, zn, &zy);
        if (zscompare(zy, 1l) != 0 &&
            zcompare(zy, zn1) != 0) {
          j = 1;
          while (value && j <= s - 1 && zcompare(zy, zn1) != 0) {
            zmulmod(zy, zy, zn, &zb);
            zcopy(zb, &zy);
            if (zscompare(zy, 1l) == 0) value = 0;
            j++;
          }
          if (value && zcompare(zy, zn1) != 0) value = 0;
        }
      }
    }
    else value = 1;
  }
  else value = zscompare(zn, 2l) == 0;
  zfree(&za);
  zfree(&zb);
  zfree(&zn1);
  zfree(&zr);
  zfree(&zy);
  return value;
}
Exemple #8
0
/* t_astruct subtype that implements copy. */
static int
z1copy(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;
    int code = zcopy(i_ctx_p);

    if (code >= 0)
	return code;
    if (!r_has_type(op, t_astruct))
	return code;
    return zcopy_gstate(i_ctx_p);
}
Exemple #9
0
void RED(long k, long l, long n,
         verylong *zd, verylong **zb,
         verylong **zh, verylong **zl)
{
  long i;
  verylong zq = 0, zr = 0, zs = 0, zt = 0;

  zlshift(zl[k][l], 1l, &zr);
  zcopy(zr, &zs);
  zabs(&zs);
  if (zcompare(zs, zd[l]) > 0) {
    zadd(zr, zd[l], &zs);
    zlshift(zd[l], 1l, &zr);
    zdiv(zs, zr, &zq, &zt);
    for (i = 1; i <= n; i++) {
      zmul(zq, zh[i][l], &zr);
      zsub(zh[i][k], zr, &zs);
      zcopy(zs, &zh[i][k]);
      zmul(zq, zb[l][i], &zr);
      zsub(zb[k][i], zr, &zs);
      zcopy(zs, &zb[k][i]);
    }
    zmul(zq, zd[l], &zr);
    zsub(zl[k][l], zr, &zs);
    zcopy(zs, &zl[k][l]);
    for (i = 1; i <= l - 1; i++) {
      zmul(zq, zl[l][i], &zr);
      zsub(zl[k][i], zr, &zs);
      zcopy(zs, &zl[k][i]);
    }
  }
  zfree(&zq);
  zfree(&zr);
  zfree(&zs);
  zfree(&zt);
}
Exemple #10
0
void zbi(verylong zb0, verylong zn, verylong zx0, verylong *zb1)
{
  long x = zsmod(zx0, 3l);
  static verylong zb = 0;

  if (x == 1) {
    zsadd(zb0, 1l, &zb);
    zmod(zb, zn, zb1);
  }
  else if (x == 0) {
    zsmul(zb0, 2l, &zb);
    zmod(zb, zn, zb1);
  }
  else
    zcopy(zb0, zb1);
}
Exemple #11
0
void zai(verylong za0, verylong zn, verylong zx0, verylong *za1)
{
  long x = zsmod(zx0, 3l);
  static verylong za = 0;

  if (x == 1)
    zcopy(za0, za1);
  else if (x == 0) {
    zsmul(za0, 2l, &za);
    zmod(za, zn, za1);
  }
  else {
    zsadd(za0, 1l, &za);
    zmod(za, zn, za1);
  }
}
Exemple #12
0
void scalar(long n, verylong *za, verylong *zb,
            verylong *zs)
{
  /* *s = inner_product(a, b) */
  long i;
  verylong zt = 0, zu = 0;

  zzero(zs);
  for (i = 1; i <= n; i++) {
    zmul(za[i], zb[i], &zt);
    zadd(zt, *zs, &zu);
    zcopy(zu, zs);
  }
  zfree(&zt);
  zfree(&zu);
}
void Montgomery_multiplication(long b, long n,
                               verylong zm, verylong zx,
                               verylong zy, verylong *zA)
{
  long i, n1 = n + 1, u, mp, *a, *m, *x, *y;
  verylong za = 0, zb = 0, zc = 0, zd = 0, zs = 0;

  a = calloc(n1, sizeof(long));
  m = calloc(n1, sizeof(long));
  x = calloc(n1, sizeof(long));
  y = calloc(n1, sizeof(long));
  if (a == 0 || m == 0 || x == 0 || y == 0) {
    printf("*error*\ncan't get memory from Montgomery");
    printf(" multiplication");
    exit(1);
  }
  zintoz(b, &zb);
  zinvmod(zm, zb, &za);
  znegate(&za);
  mp = zsmod(za, b);
  radix_representation(b, n1, m, zm);
  radix_representation(b, n1, x, zx);
  radix_representation(b, n1, y, zy);
  zzero(zA);
  for (i = 0; i < n; i++) {
    radix_representation(b, n1, a, *zA);
    u = ((a[0] + x[i] * y[0]) * mp) % b;
    zsmul(zy, x[i], &za);
    zsmul(zm, u, &zc);
    zadd(*zA, za, &zs);
    zadd(zs, zc, &zd);
    zsdiv(zd, b, zA);
  }
  if (zcompare(*zA, zm) >= 0) {
    zsub(*zA, zm, &za);
    zcopy(za, zA);
  }
  free(a);
  free(m);
  free(x);
  free(y);
  zfree(&za);
  zfree(&zb);
  zfree(&zc);
  zfree(&zd);
  zfree(&zs);
}
Exemple #14
0
void SWAP(long k, long k1, long kmax, long n,
          verylong *zd, verylong **zb,
          verylong **zh, verylong **zl)
{
  long i, j;
  verylong zB = 0, zm = 0, zr = 0, zs = 0, zt = 0;
  verylong zu = 0;

  for (i = 1; i <= n; i++) {
    zcopy(zh[i][k], &zt);
    zcopy(zh[i][k1], &zh[i][k]);
    zcopy(zt, &zh[i][k1]);
  }
  for (j = 1; j <= n; j++) {
    zcopy(zb[k][j], &zt);
    zcopy(zb[k1][j], &zb[k][j]);
    zcopy(zt, &zb[k1][j]);
  }
  if (k > 2) {
    for (j = 1; j <= k - 2; j++) {
      zcopy(zl[k][j], &zt);
      zcopy(zl[k1][j], &zl[k][j]);
      zcopy(zt, &zl[k1][j]);
    }
  }
  zcopy(zl[k][k1], &zm);
  zmul(zd[k - 2], zd[k], &zr);
  zsq(zm, &zs);
  zadd(zr, zs, &zt);
  zdiv(zt, zd[k1], &zB, &zr);
  for (i = k + 1; i <= kmax; i++) {
    zcopy(zl[i][k], &zt);
    zmul(zd[k], zl[i][k1], &zr);
    zmul(zm, zt, &zs);
    zsub(zr, zs, &zu);
    zdiv(zu, zd[k1], &zl[i][k], &zr);
    zmul(zB, zt, &zr);
    zmul(zm, zl[i][k], &zs);
    zadd(zr, zs, &zu);
    zdiv(zu, zd[k], &zl[i][k1], &zr);
  }
  zcopy(zB, &zd[k1]);
  zfree(&zB);
  zfree(&zm);
  zfree(&zr);
  zfree(&zs);
  zfree(&zt);
  zfree(&zu);
}
Exemple #15
0
int simultaneous_diophantine(double delta,
                             long n,
                             verylong zQ,
                             verylong *zP,
                             verylong *zp,
                             verylong *zq)
{
  double P, Q, l;
  int equal, found;
  long i, j, n1 = n + 1;
  verylong zd = 0, zl = 0, zr = 0, zs = 0, zt = 0;
  verylong **zA = allocate_very_matrix(1, n1, 1, n1);
  verylong **zh = allocate_very_matrix(1, n1, 1, n1);

  Q = zdoub(zQ);
  zintoz(pow(Q, delta), &zl);
  l = 1.0 / zdoub(zl);
  zmul(zl, zQ, &zd);
  for (i = 1; i <= n; i++)
    zcopy(zd, &zA[i][i]);
  znegate(&zl);
  for (i = 1; i <= n; i++)
    zmul(zl, zq[i], &zA[n1][i]);
  zone(&zA[n1][n1]);
  int_LLL(n1, zA, zh);
  found = 0;
  for (j = 1; !found && j <= n1; j++) {
    zcopy(zA[j][n1], zP);
    if (zcompare(*zP, zQ) != 0) {
      for (i = 1; i <= n; i++) {
        zdiv(zA[j][i], zl, &zr, &zs);
        zmul(*zP, zq[i], &zt);
        zadd(zr, zt, &zs);
        zdiv(zs, zQ, &zp[i], &zr);
      }
      P = zdoub(*zP);
      #ifdef DEBUG
      if (n <= 16) {
        printf("p = ");
        zwrite(*zP);
        printf(" p[i] ");
        for (i = 1; i <= n; i++) {
          zwrite(zp[i]);
          printf(" ");
        }
        printf("\n");
      }
      #endif
      if (zcompare(*zP, 0) != 0) {
        equal = 1;
        for (i = 1; equal && i <= n; i++)
          equal = fabs(P * zdoub(zq[i]) / Q - zdoub(zp[i]))
                <= l;
      }
      else equal = 0;
      found = equal;
    }
  }
  free_very_matrix(zA, 1, n1, 1, n1);
  free_very_matrix(zh, 1, n1, 1, n1);
  zfree(&zd);
  zfree(&zl);
  zfree(&zr);
  zfree(&zs);
  zfree(&zt);
  return found;
}
Exemple #16
0
void PROVABLE_PRIME(long k, verylong *zn)
{
  double c, r, s;
  int success;
  long B, m, n, p, sqrtn;
  verylong zI = 0, zR = 0, za = 0, zb = 0, zc = 0;
  verylong zd = 0, zk = 0, zl = 0, zq = 0, zu = 0;

  if (k <= 20) {
    do {
      n = OddRandom(k);
      sqrtn = sqrt(n);
      zpstart2();
      do p = zpnext(); while (n % p != 0 && p < sqrtn);
    } while (p < sqrtn);
    zintoz(n, zn);
  }
  else {
    c = 0.1;
    m = 20;
    B = c * k * k;
    if (k > 2 * m)
      do {
        s = rand() / (double) RAND_MAX;
        r = pow(2.0, s - 1.0);
      } while (k - r * k <= m);
    else
      r = 0.5;
    PROVABLE_PRIME(r * k + 1, &zq);
    zone(&za);
    zlshift(za, k - 1, &zk);
    zcopy(zq, &za);
    zlshift(za, 1l, &zl);
    zdiv(zk, zl, &zI, &za);
    zsadd(zI, 1l, &zl);
    zlshift(zI, 1l, &zu);
    success = 0;
    while (!success) {
      do zrandomb(zu, &zR); while (zcompare(zR, zl) < 0);
      zmul(zR, zq, &za);
      zlshift(za, 1l, &zb);
      zsadd(zb, 1l, zn);
      zcopy(zR, &za);
      zlshift(za, 1l, &zR);
      zpstart2();
      p = zpnext();
      while (zsmod(*zn, p) != 0 && p < B) p = zpnext();
      if (p >= B) {
        zcopy(*zn, &zc);
        zsadd(zc, - 2l, &zb);
        do
          zrandomb(*zn, &za);
        while (zscompare(za, 2l) < 0 || zcompare(za, zb) > 0);
        zsadd(*zn, - 1l, &zc);
        zexpmod(za, zc, *zn, &zb);
        if (zscompare(zb, 1l) == 0) {
          zexpmod(za, zR, *zn, &zb);
          zcopy(zb, &zd);
          zsadd(zd, - 1l, &zb);
          zgcd(zb, *zn, &zd);
          success = zscompare(zd, 1l) == 0;
        }
      }
    }
  }
  zfree(&zI);
  zfree(&zR);
  zfree(&za);
  zfree(&zb);
  zfree(&zc);
  zfree(&zd);
  zfree(&zk);
  zfree(&zl);
  zfree(&zq);
  zfree(&zu);
}
Exemple #17
0
void int_LLL(long n, verylong **zb, verylong **zh)
{
  double x, y;
  long i, j, k = 2, k1, kmax = 1, l;
  verylong zr = 0, zs = 0, zt = 0, zu = 0;
  verylong *zB = allocate_very_vector(1, n);
  verylong *zd = allocate_very_vector(0, n);
  verylong **zl = allocate_very_matrix(1, n, 1, n);

  zone(&zd[0]);
  scalar(n, zb[1], zb[1], &zd[1]);
  for (i = 1; i <= n; i++) {
    for (j = 1; j <= n; j++)
      zzero(&zh[i][j]);
    zone(&zh[i][i]);
  }
  #ifdef DEBUG
  if (n <= 17) {
    printf("the basis to be reduced is:\n");
    for (i = 1; i <= n; i++) {
      for (j = 1; j <= n; j++) {
        zwrite(zb[i][j]);
        printf(" ");
      }
      printf("\n");
    }
  }
  #endif
  L2:
  if (k <= kmax) goto L3;
  kmax = k;
  for (j = 1; j <= k; j++) {
    scalar(n, zb[k], zb[j], &zu);
    for (i = 1; i <= j - 1; i++) {
      zmul(zd[i], zu, &zr);
      zmul(zl[k][i], zl[j][i], &zs);
      zsub(zr, zs, &zt);
      zdiv(zt, zd[i - 1], &zu, &zr);
    }
    if (j < k) zcopy(zu, &zl[k][j]);
    else if (j == k) {
      zcopy(zu, &zd[k]);
      if (zscompare(zd[k], 0l) == 0)
        system_error("Failure in int_LLL.");
    }
  }
  L3:
  k1 = k - 1;
  RED(k, k1, n, zd, zb, zh, zl);
  zmul(zd[k], zd[k - 2], &zr);
  zsq(zd[k1], &zs);
  zsq(zl[k][k1], &zt);
  x = zdoub(zr);
  y = 3.0 * zdoub(zs) / 4.0 - zdoub(zt);
  if (x < y) {
    SWAP(k, k1, kmax, n, zd, zb, zh, zl);
    k = max(2, k1);
    goto L3;
  }
  for (l = k - 2; l >= 1; l--)
    RED(k, l, n, zd, zb, zh, zl);
  if (++k <= n) goto L2;
  #ifdef DEBUG
  if (n <= 17) {
    printf("the LLL-reduced basis is:\n");
    for (i = 1; i <= n; i++) {
      for (j = 1; j <= n; j++) {
        zwrite(zb[i][j]);
        printf(" ");
      }
      printf("\n");
    }
  }
  #endif
  free_very_matrix(zl, 1, n, 1, n);
  free_very_vector(zB, 1, n);
  free_very_vector(zd, 0, n);
  zfree(&zr);
  zfree(&zs);
  zfree(&zt);
  zfree(&zu);
}
Exemple #18
0
int PollardRho(verylong zalpha, verylong zbeta,
               verylong zn, verylong zp, verylong *zx)
{
  long i = 2, j;
  static verylong za0 = 0, za1 = 0, za2 = 0, za3 = 0;
  static verylong zb0 = 0, zb1 = 0, zb2 = 0, zb3 = 0;
  static verylong zx0 = 0, zx1 = 0, zx2 = 0, zx3 = 0;
  static verylong zr = 0, zri = 0;

  zone(&zx0);
  zzero(&za0);
  zzero(&zb0);
  zfi(zalpha, zbeta, zp, zx0, &zx1);
  zai(za0, zn, zx0, &za1);
  zbi(zb0, zn, zx0, &zb1);
  zfi(zalpha, zbeta, zp, zx1, &zx2);
  zai(za1, zn, zx1, &za2);
  zbi(zb1, zn, zx1, &zb2);
  zcopy(za1, &za0);
  zcopy(zb1, &zb0);
  zcopy(zx1, &zx0);
  for (;;) {
    zfi(zalpha, zbeta, zp, zx0, &zx1);
    zai(za0, zn, zx0, &za1);
    zbi(zb0, zn, zx0, &zb1);
    zcopy(za1, &za2);
    zcopy(zb1, &zb2);
    zcopy(zx1, &zx2);
    i++;
    for (j = 0; j < i; j++) {
      zfi(zalpha, zbeta, zp, zx2, &zx3);
      zai(za2, zn, zx2, &za3);
      zbi(zb2, zn, zx2, &zb3);
      zcopy(za3, &za2);
      zcopy(zb3, &zb2);
      zcopy(zx3, &zx2);
    }
    if (zcompare(zx1, zx3) == 0) {
      zsubmod(zb1, zb3, zn, &zr);
      if (zscompare(zr, 0) == 0) return 0;
      zinvmod(zr, zn, &zri);
      zsub(za3, za1, &za0);
      zmulmod(za0, zri, zn, zx);
      return 1;
    }
    zcopy(za1, &za0);
    zcopy(zb1, &zb0);
    zcopy(zx1, &zx0);
  }
}
Exemple #19
0
void zbinary_ext_gcd(verylong zx, verylong zy,
                     verylong *za, verylong *zb,
                     verylong *zv)
/* returns a * x + b * y = v, v = gcd(x, y) */
{
  verylong zA = 0, zB = 0, zC = 0, zD = 0;
  verylong zX = 0, zY = 0, zc = 0,  zg = 0;
  verylong zu = 0;

  zone(&zg);
  zcopy(zx, &zX);
  zcopy(zy, &zY);
  while (!zodd(zX) && !zodd(zY)) {
    zrshift(zX, 1l, &zc);
    zcopy(zc, &zX);
    zrshift(zY, 1l, &zc);
    zcopy(zc, &zY);
    zlshift(zg, 1l, &zc);
    zcopy(zc, &zg);
  }
  zcopy(zX, &zu);
  zcopy(zY, zv);
  zone(&zA);
  zzero(&zB);
  zzero(&zC);
  zone(&zD);
  do {
    while (!zodd(zu)) {
      zrshift(zu, 1l, &zc);
      zcopy(zc, &zu);
      if (!zodd(zA) && !zodd(zB)) {
        zrshift(zA, 1l, &zc);
        zcopy(zc, &zA);
        zrshift(zB, 1l, &zc);
        zcopy(zc, &zB);
      }
      else {
        zadd(zA, zY, &zc);
        zrshift(zc, 1l, &zA);
        zsub(zB, zX, &zc);
        zrshift(zc, 1l, &zB);
      }
    }
    while (!zodd(*zv)) {
      zrshift(*zv, 1l, &zc);
      zcopy(zc, zv);
      if (!zodd(zC) && !zodd(zD)) {
        zrshift(zC, 1l, &zc);
        zcopy(zc, &zC);
        zrshift(zD, 1l, &zc);
        zcopy(zc, &zD);
      }
      else {
        zadd(zC, zY, &zc);
        zrshift(zc, 1l, &zC);
        zsub(zD, zX, &zc);
        zrshift(zc, 1l, &zD);
      }
    }
    if (zcompare(zu, *zv) >= 0) {
      zsub(zu, *zv, &zc);
      zcopy(zc, &zu);
      zsub(zA, zC, &zc);
      zcopy(zc, &zA);
      zsub(zB, zD, &zc);
      zcopy(zc, &zB);
    }
    else {
      zsub(*zv, zu, &zc);
      zcopy(zc, zv);
      zsub(zC, zA, &zc);
      zcopy(zc, &zC);
      zsub(zD, zB, &zc);
      zcopy(zc, &zD);
    }
    #ifdef DEBUG
    zwrite(zu); printf(" ");
    zwrite(*zv); printf(" ");
    zwrite(zA); printf(" ");
    zwrite(zB); printf(" ");
    zwrite(zC); printf(" ");
    zwriteln(zD);
    #endif
  } while (zscompare(zu, 0l) != 0);
  zcopy(zC, za);
  zcopy(zD, zb);
  zmul(zg, *zv, &zc);
  zcopy(zc, zv);
  zfree(&zA);
  zfree(&zB);
  zfree(&zC);
  zfree(&zD);
  zfree(&zX);
  zfree(&zY);
  zfree(&zc);
  zfree(&zg);
  zfree(&zu);
}