Exemple #1
0
void ECM(ZZ& q, const ZZ& N, long ncurves, long B1, long B2, long D, 
	 bool verbose) {
  // initialize ZZ_p
  ZZ_pBak bak;
  bak.save();
  ZZ_p::init(N);

  PrimeSeq seq;

  for (long i=0; i<ncurves; ++i) {
    if (verbose) {
      if (ncurves<NTL_MAX_LONG)
	std::cout<<"ECM: "<<NumBits(N)<<" bits; "
	    <<i<<"/"<<ncurves<<" curves\r"<<std::flush;
      else
	std::cout<<"ECM: "<<NumBits(N)<<" bits; "
	    <<i<<" curves\r"<<std::flush;
    }

    // try to find a factor
    ECM_one_curve(q,seq,B1,B2,D);
    if (!IsOne(q)) {
      if (verbose) {
	std::cout<<"ECM: "<<NumBits(N)<<" bits; "
             <<(i+1)<<" curves; found "<<q<<"  "<<std::endl;
      }
      return;
    }
  }
  if (verbose)
    std::cout<<"ECM: "<<NumBits(N)<<" bits; FAILED!        "<<std::endl;
  set(q);
}
Exemple #2
0
void div(RR& z, const RR& a, const RR& b)
{
   if (IsZero(b))
      Error("RR: division by zero");

   if (IsZero(a)) {
      clear(z);
      return;
   }

   long la = NumBits(a.x);
   long lb = NumBits(b.x);

   long neg = (sign(a) != sign(b));

   long k = RR::prec - la + lb + 1;
   if (k < 0) k = 0;

   static RR t;
   static ZZ A, B, R;

   abs(A, a.x);
   LeftShift(A, A, k);

   abs(B, b.x);
   DivRem(t.x, R, A, B);

   t.e = a.e - b.e - k;

   normalize(z, t, !IsZero(R));

   if (neg)
      negate(z.x, z.x);
}
void CRSAFactorHintDlg::OnChangeGuessP() 
{
	UpdateData();
	if(m_choice==0){
		int base=(m_base*6+10)%20;
		CString GuessPString;
		if(m_msbLsb==0){
			GetDlgItemText(IDC_EDITGUESSP_LEFT,GuessPString);
			//	SetDlgItemText(IDC_EDITGUESSP_RIGHT,GuessPString);
		}
		else{
			GetDlgItemText(IDC_EDITGUESSP_RIGHT,GuessPString);
			//	SetDlgItemText(IDC_EDITGUESSP_LEFT,GuessPString);
		}
		ZZ tmpGuessP=setToStringValue(GuessPString,base);
		int bitsOfGuess=NumBits(tmpGuessP);
		int z=0;
		for(int i=0; i<GuessPString.GetLength()
			&&(GuessPString.GetAt(i)=='0'
			||GuessPString.GetAt(i)==' '); i++)
			if(GuessPString.GetAt(i)=='0')
				z++;
			int zeroBits=NumBits(power(to_ZZ(base),z)-1);
			bitsOfGuess+=zeroBits;
			m_GuessP=tmpGuessP;
			SetDlgItemInt(IDC_EDITB, bitsOfGuess);
	}
	UpdateData(false);
	//updateDim();
}
Exemple #4
0
long GetPrimeBound(int deg_a, int deg_b, int bitsize_a, int bitsize_b, int num_of_additions){
	long res;
	int log_add;

	log_add = NumBits(num_of_additions)+1;
	res 	= 2 + NumBits(min(deg_a, deg_b)+1) + bitsize_a + bitsize_b + log_add;
	return res;
}
Exemple #5
0
void exp(RR& res, const RR& x)
{
   if (x >= NTL_OVFBND || x <= -NTL_OVFBND)
      Error("RR: overflow");

   long p = RR::precision();

   // step 0: write x = n + f, n an integer and |f| <= 1/2
   //    careful -- we want to compute f to > p bits of precision


   RR f, nn;
   RR::SetPrecision(NTL_BITS_PER_LONG);
   round(nn, x);
   RR::SetPrecision(p + 10);
   sub(f, x, nn);
   long n = to_long(nn);

   // step 1: calculate t1 = e^n by repeated squaring

   RR::SetPrecision(p + NumBits(n) + 10);

   RR e;
   ComputeE(e);

   RR::SetPrecision(p + 10);

   RR t1;
   power(t1, e, n);

   // step 2: calculate t2 = e^f using Taylor series expansion

   RR::SetPrecision(p + NumBits(p) + 10);

   RR t2, s, s1, t;
   long i;

   s = 0;
   t = 1;

   for (i = 1; ; i++) {
      add(s1, s, t);
      if (s == s1) break;
      xcopy(s, s1);
      mul(t, t, f);
      div(t, t, i);
   }

   xcopy(t2, s);

   RR::SetPrecision(p);

   mul(res, t1, t2);
}
Exemple #6
0
void totalSums(const EncryptedArray& ea, Ctxt& ctxt)
{
  long n = ea.size();

  if (n == 1) return;

  Ctxt orig = ctxt;

  long k = NumBits(n);
  long e = 1;

  for (long i = k-2; i >= 0; i--) {
    Ctxt tmp1 = ctxt;
    ea.rotate(tmp1, e);
    ctxt += tmp1; // ctxt = ctxt + (ctxt >>> e)
    e = 2*e;

    if (bit(n, i)) {
      Ctxt tmp2 = orig;
      ea.rotate(tmp2, e);
      ctxt += tmp2; // ctxt = ctxt + (orig >>> e)
                    // NOTE: we could have also computed
                    // ctxt =  (ctxt >>> e) + orig, however,
                    // this would give us greater depth/noise
      e += 1;
    }
  }
}
void RoundToZZ(ZZ& z, const RR& a)
{
   if (a.e >= 0) {
      LeftShift(z, a.x, a.e);
      return;
   }

   long len = NumBits(a.x);

   if (-a.e > len) {
      z = 0;
      return;
   }

   if (-a.e == len) {
      if (len == 1)
         z = 0;
      else
         z = sign(a.x);

      return;
   }

   NTL_TLS_LOCAL(RR, t);

   ConvPrec(t, a, len+a.e);

   LeftShift(z, t.x, t.e);
}
static
void normalize1(RR& z, const ZZ& y_x, long y_e, long prec, long residual)
{
   long len = NumBits(y_x);

   if (len > prec) {
      long correction = ZZ_RoundCorrection(y_x, len - prec, residual);

      RightShift(z.x, y_x, len - prec);

      if (correction) 
         add(z.x, z.x, correction);

      z.e = y_e + len - prec;
   }
   else if (len == 0) {
      clear(z.x);
      z.e = 0;
   }
   else {
      z.x = y_x;
      z.e = y_e;
   }

   if (!IsOdd(z.x))
      z.e += MakeOdd(z.x);

   if (z.e >= NTL_OVFBND)
      ResourceError("RR: overflow");

   if (z.e <= -NTL_OVFBND)
      ResourceError("RR: underflow");
}
void SqrRoot(RR& z, const RR& a)
{
   if (sign(a) < 0)
      ArithmeticError("RR: attempt to take square root of negative number");

   if (IsZero(a)) {
      clear(z);
      return;
   }

   RR t;
   ZZ T1, T2;
   long k;

   k = 2*RR::prec - NumBits(a.x) + 1;

   if (k < 0) k = 0;

   if ((a.e - k) & 1) k++;

   LeftShift(T1, a.x, k);
   // since k >= 2*prec - bits(a) + 1, T1 has at least 2*prec+1 bits,           
   // thus T1 >= 2^(2*prec)                                                     

   SqrRoot(t.x, T1); // t.x >= 2^prec thus t.x contains the round bit           
   t.e = (a.e - k)/2;
   sqr(T2, t.x);  

   // T1-T2 is the (lower part of the) sticky bit                               
   normalize(z, t, T2 < T1);
}
Exemple #10
0
NTL_CLIENT
#include "FHE.h"
#include "timing.h"
#include "EncryptedArray.h"

#include <cassert>
#include <cstdio>


// computes ctxt^{2^d-1} using a method that takes
// O(log d) automorphisms and multiplications
void fastPower(Ctxt& ctxt, long d) 
{
  if (d == 1) return;

  Ctxt orig = ctxt;

  long k = NumBits(d);
  long e = 1;

  for (long i = k-2; i >= 0; i--) {
    Ctxt tmp1 = ctxt;
    tmp1.smartAutomorph(1L << e);
    ctxt.multiplyBy(tmp1);
    e = 2*e;

    if (bit(d, i)) {
      ctxt.smartAutomorph(2);
      ctxt.multiplyBy(orig);
      e += 1;
    }
  }
}
NTL_START_IMPL

static
long CharPolyBound(const mat_ZZ& a)
// This bound is computed via interpolation
// through complex roots of unity.

{
   long n = a.NumRows();
   long i;
   ZZ res, t1, t2;

   set(res);

   for (i = 0; i < n; i++) {
      InnerProduct(t1, a[i], a[i]);
      abs(t2, a[i][i]);
      mul(t2, t2, 2);
      add(t2, t2, 1);
      add(t1, t1, t2);
      if (t1 > 1) {
         SqrRoot(t1, t1);
         add(t1, t1, 1);
      }
      mul(res, res, t1);
   }

   return NumBits(res);
}
Exemple #12
0
void power(mat_ZZ& X, const mat_ZZ& A, const ZZ& e)
{
    if (A.NumRows() != A.NumCols()) Error("power: non-square matrix");

    if (e == 0) {
        ident(X, A.NumRows());
        return;
    }

    mat_ZZ T1, T2;
    long i, k;

    k = NumBits(e);
    T1 = A;

    for (i = k-2; i >= 0; i--) {
        sqr(T2, T1);
        if (bit(e, i))
            mul(T1, T2, A);
        else
            T1 = T2;
    }

    if (e < 0)
        inv(X, T1);
    else
        X = T1;
}
Exemple #13
0
void replicate0(const EncryptedArray& ea, Ctxt& ctxt, long pos)
{
  long dim = ea.dimension();

  for (long d = 0; d < dim; d++) {
    if (!ea.nativeDimension(d)) {
      long shamt = -ea.coordinate(d, pos);
      ea.rotate1D(ctxt, d, shamt, true); // "don't care"
    }

    Ctxt ctxt_orig = ctxt; 

    long sz = ea.sizeOfDimension(d);
    long k = NumBits(sz);
    long e = 1;

    // now process bits k-2 down to 0
    for (long j = k-2; j >= 0; j--) {
      // e -> 2*e
      Ctxt tmp = ctxt;
      ea.rotate1D(tmp, d, e, true); // "don't care"
      ctxt += tmp;
      e = 2*e;
      
      long b = bit(sz, j); // bit j of sz
      // e -> e+b
      if (b) {
        ea.rotate1D(ctxt, d, 1, true); // "don't care"
        ctxt += ctxt_orig;
        e++;
      }
    }
  }
}
Exemple #14
0
void power(RR& z, const RR& a, long e)
{
   RR b, res;

   long n = NumBits(e);

   RRPush push;
   long p = RR::precision();
   RR::SetPrecision(p + n + 10);

   xcopy(b, a);

   set(res);
   long i;

   for (i = n-1; i >= 0; i--) {
      sqr(res, res);
      if (bit(e, i))
         mul(res, res, b);
   }

   RR::SetPrecision(p);

   if (e < 0) 
      inv(z, res);
   else
      xcopy(z, res);
}
Exemple #15
0
void round(RR& z, const RR& a)
{
   if (a.e >= 0) {
      xcopy(z, a);
      return;
   }

   long len = NumBits(a.x);

   if (-a.e > len) {
      z = 0;
      return;
   }

   if (-a.e == len) {
      if (len == 1)
         z = 0;
      else
         z = sign(a.x);

      return;
   }

   NTL_TLS_LOCAL(RR, t);
   ConvPrec(t, a, len+a.e);
   xcopy(z, t);
}
Exemple #16
0
void log(RR& res, const RR& x)
{
   if (x <= 0) Error("argument to log must be positive");

   long p = RR::precision();

   RR::SetPrecision(p + NumBits(p) + 10);

   RR y;
   long n;

   // re-write x = 2^n * (1 - y), where -1/2 < y < 1/4  (so 3/4 < 1-y < 3/2)

   if (x > 0.75 && x < 1.5) {
      n = 0;
      sub(y, 1, x);
   }
   else {
      n = Lg2(x) - 1;
      RR t;
      power2(t, -n);
      mul(t, t, x);
      while (t > 1.5) {
         mul(t, t, 0.5);
         n++;
      }

      sub(y, 1, t);
   }

   // compute s = - ln(1-y) by power series expansion

   RR s, s1, t, t1;

   s = 0;
   xcopy(t, y);
   xcopy(t1, y);

   long i;

   for (i = 2; ; i++) {
      add(s1, s, t);
      if (s == s1) break;
      xcopy(s, s1);
      mul(t1, t1, y);
      div(t, t1, i);
   }

   if (n == 0)
      t = 0;
   else {
      ComputeLn2(t);
      mul(t, t, n);
   }

   RR::SetPrecision(p);

   sub(res, t, s);
}
zz_pInfoT::zz_pInfoT(long NewP, long maxroot)
{
   if (maxroot < 0) LogicError("zz_pContext: maxroot may not be negative");

   if (NewP <= 1) LogicError("zz_pContext: p must be > 1");
   if (NumBits(NewP) > NTL_SP_NBITS) ResourceError("zz_pContext: modulus too big");

   ZZ P, B, M, M1, MinusM;
   long n, i;
   long q, t;

   p = NewP;

   pinv = 1/double(p);

   p_info = 0;

   conv(P, p);

   sqr(B, P);
   LeftShift(B, B, maxroot+NTL_FFTFudge);

   set(M);
   n = 0;
   while (M <= B) {
      UseFFTPrime(n);
      q = GetFFTPrime(n);
      n++;
      mul(M, M, q);
   }

   if (n > 4) LogicError("zz_pInit: too many primes");

   NumPrimes = n;
   PrimeCnt = n;
   MaxRoot = CalcMaxRoot(q);

   if (maxroot < MaxRoot)
      MaxRoot = maxroot;

   negate(MinusM, M);
   MinusMModP = rem(MinusM, p);

   CoeffModP.SetLength(n);
   x.SetLength(n);
   u.SetLength(n);

   for (i = 0; i < n; i++) {
      q = GetFFTPrime(i);

      div(M1, M, q);
      t = rem(M1, q);
      t = InvMod(t, q);
      if (NTL_zz_p_QUICK_CRT) mul(M1, M1, t);
      CoeffModP[i] = rem(M1, p);
      x[i] = ((double) t)/((double) q);
      u[i] = t;
   }
}
Exemple #18
0
void KarSqr(ZZX& c, const ZZX& a)
{
   if (IsZero(a)) {
      clear(c);
      return;
   }

   vec_ZZ mem;

   const ZZ *ap;
   ZZ *cp;

   long sa = a.rep.length();

   if (&a == &c) {
      mem = a.rep;
      ap = mem.elts();
   }
   else
      ap = a.rep.elts();

   c.rep.SetLength(sa+sa-1);
   cp = c.rep.elts();

   long maxa, xover;

   maxa = MaxBits(a);

   xover = 2;

   if (sa < xover)
      PlainSqr(cp, ap, sa);
   else {
      /* karatsuba */

      long n, hn, sp, depth;

      n = sa;
      sp = 0;
      depth = 0;
      do {
         hn = (n+1) >> 1;
         sp += hn+hn+hn - 1;
         n = hn;
         depth++;
      } while (n >= xover);

      ZZVec stk;
      stk.SetSize(sp,
         ((2*maxa + NumBits(sa) + 2*depth + 10)
          + NTL_ZZ_NBITS-1)/NTL_ZZ_NBITS);

      KarSqr(cp, ap, sa, stk.elts());
   }

   c.normalize();
}
Exemple #19
0
void pow(RR& res, const RR& x, const RR& y)
{
   if (y == 0) {
      res = 1;
      return;
   }

   if (x == 0) {
      res = 0;
      return;
   }

   if (x == 1) {
      res = 1;
      return;
   }

   if (x < 0) {
      Error("pow: sorry...first argument to pow must be nonnegative");
   }

   long p = RR::precision();

   // calculate working precison...one could use p + NTL_BITS_PER_LONG + 10,
   // for example, but we want the behaviour to be machine independent.
   // so we calculate instead a rough approximation to log |y log(x)|

   RR t1, t2;
   long k;

   if (x > 0.5 && x < 1.5) {
      xcopy(t1, x - 1);
      k = Lg2(t1);
   }
   else {
      k = NumBits(Lg2(x));
   }

   k += Lg2(y);

   if (k > NTL_BITS_PER_LONG+10) Error("RR: overflow");

   if (k < 0) k = 0;


   RR::SetPrecision(p + k + 10);

   t1 = y*log(x);

   RR::SetPrecision(p);

   t2 = exp(t1);

   res = t2;
}
Exemple #20
0
void sub(RR& z, const RR& a, const RR& b)
{
   NTL_TLS_LOCAL(RR, t);

   if (IsZero(a.x)) {
      negate(z, b);
      return;
   }

   if (IsZero(b.x)) {
      xcopy(z, a);
      return;
   }

   if (a.e > b.e) {
      if (a.e-b.e - max(RR::prec-NumBits(a.x),0) >= NumBits(b.x) + 2)
         normalize(z, a, -sign(b));
      else {
         LeftShift(t.x, a.x, a.e-b.e);
         sub(t.x, t.x, b.x);
         t.e = b.e;
         xcopy(z, t);
      }
   }
   else if (a.e < b.e) {
      if (b.e-a.e - max(RR::prec-NumBits(b.x),0) >= NumBits(a.x) + 2) {
         normalize(z, b, -sign(a));
         negate(z.x, z.x);
      }
      else {
         LeftShift(t.x, b.x, b.e-a.e);
         sub(t.x, a.x, t.x);
         t.e = a.e;
         xcopy(z, t);
      }
   }
   else {
      sub(t.x, a.x, b.x);
      t.e = a.e;
      normalize(z, t);
   }
}
Exemple #21
0
static
long MaxBits(const mat_ZZ& A)
{
    long m = 0;
    long i, j;
    for (i = 0; i < A.NumRows(); i++)
        for (j = 0; j < A.NumCols(); j++)
            m = max(m, NumBits(A[i][j]));

    return m;
}
Exemple #22
0
long MaxBits(const ZZX& f)
{
   long i, m;
   m = 0;

   for (i = 0; i <= deg(f); i++) {
      m = max(m, NumBits(f.rep[i]));
   }

   return m;
}
Exemple #23
0
long GetPrimeNumber(long bound, ZZ &prod){

	long nprimes;
	zz_pBak bak;
	bak.save();
	for (nprimes = 0; NumBits(prod) <= bound; nprimes++) {
		UseFFTPrime(nprimes);
		      mul(prod, prod, GetFFTPrime(nprimes));
   }
	bak.restore();
	return nprimes;
}
Exemple #24
0
// ECM primitive
void ECM(ZZ& q, const ZZ& n, const ZZ& _bnd, double failure_prob,
	 bool verbose) {
  ZZ bnd;
  SqrRoot(bnd,n);
  if (_bnd>0 && _bnd<bnd)
    bnd=_bnd;

  long B1,B2,D;
  double prob;
  ECM_parameters(B1,B2,prob,D,NumBits(bnd),NumBits(n));
  if (verbose)
    std::cout<<"ECM: bnd="<<NumBits(bnd)<<"bits  B1="<<B1<<"  B2="<<B2
             <<"  D="<<D<<"  prob="<<prob<<std::endl;
  
  if (failure_prob<=0) {
    // run "forever"
    if (verbose)
      std::cout<<"ECM: expected ncurves="<<(1/prob)<<std::endl;
    ECM(q,n,NTL_MAX_LONG,B1,B2,D,verbose); 
  }
  else if (failure_prob>=1) {
    // run on one curve
    ECM(q,n,1,B1,B2,D,verbose); 
  }
  else {
    // run just the right number of times
    // failure_prob = (1-prob)^ncurves;
    double ncurves_d;
    if (prob<0.1)
      ncurves_d = to_double(log(failure_prob)/log1p(to_RR(-prob)));
    else
      ncurves_d = log(failure_prob)/log(1-prob);
    long ncurves = ncurves_d<=1 ? 1 :
      (ncurves_d>=NTL_MAX_LONG ? NTL_MAX_LONG : (long)ncurves_d);
    if (verbose)
      std::cout<<"ECM: good_prob="<<prob<<"  failure_prob="<<failure_prob
               <<"  ncurves="<<ncurves<<std::endl;
    ECM(q,n,ncurves,B1,B2,D,verbose); 
  }
}
Exemple #25
0
void add(RR& z, const RR& a, const RR& b)
{
   static RR t;

   if (IsZero(a.x)) {
      xcopy(z, b);
      return;
   }

   if (IsZero(b.x)) {
      xcopy(z, a);
      return;
   }

   if (a.e > b.e) {
      if (a.e-b.e - max(RR::prec-NumBits(a.x),0) >= NumBits(b.x) + 2)
         normalize(z, a, sign(b));
      else {
         LeftShift(t.x, a.x, a.e-b.e);
         add(t.x, t.x, b.x);
         t.e = b.e;
         normalize(z, t);
      }
   }
   else if (a.e < b.e) {
      if (b.e-a.e - max(RR::prec-NumBits(b.x),0) >= NumBits(a.x) + 2)
         normalize(z, b, sign(a));
      else {
         LeftShift(t.x, b.x, b.e-a.e);
         add(t.x, t.x, a.x);
         t.e = a.e;
         normalize(z, t);
      }
   }
   else {
      add(t.x, a.x, b.x);
      t.e = a.e;
      normalize(z, t);
   }
}
Exemple #26
0
void ReallyComputePi(RR& res)
{
   long p = RR::precision();
   RR::SetPrecision(p + NumBits(p) + 10);


   RR sum1;

   RR s, s1, t, t1;

   s = 0;
   t = 0.5;
   t1 = 0.5;

   long i;

   for (i = 3; ; i+=2) {
      add(s1, s, t);
      if (s == s1) break;
      xcopy(s, s1);
      mul(t1, t1, -0.25);
      div(t, t1, i);
   }

   xcopy(sum1, s);


   RR g;

   inv(g, to_RR(3)); // g = 1/3

   s = 0;
   xcopy(t, g);
   xcopy(t1, g);

   sqr(g, g);
   negate(g, g); // g = -1/9

   for (i = 3; ; i+=2) {
      add(s1, s, t);
      if (s == s1) break;
      xcopy(s, s1);
      mul(t1, t1, g);
      div(t, t1, i);
   }

   add(s, s, sum1);
   mul(s, s, 4);

   RR::SetPrecision(p);
   xcopy(res, s);
}
void CRSAFactorHintDlg::OnChangeEditn() 
{
	updateDim();
	ZZ N;
	if(m_base==0){
		NTLExpPars myPars;
		CString tmp;
		GetDlgItemText(IDC_EDITN, tmp);
		N = myPars.parseExp(tmp);
	}else
		N=GetDlgItemZZ(IDC_EDITN,(m_base*6+10)%20);
	m_bitsOfN=(int)NumBits(N);
	UpdateData(false);
}
Exemple #28
0
   explicit
   FlintZZ(const ZZ& a)
   {
      long n = NumBits(a);
   
      fmpz_init(value);
   
      for (long i = 0; i < n; i++)
         if (bit(a, i)) fmpz_setbit(value, i);
   
      if (a < 0)
         fmpz_neg(value, value);

   }
Exemple #29
0
void div(RR& z, const RR& a, const RR& b)
{
   if (IsZero(b))
      ArithmeticError("RR: division by zero");

   if (IsZero(a)) {
      clear(z);
      return;
   }

   long la = NumBits(a.x);
   long lb = NumBits(b.x);

   long neg = (sign(a) != sign(b));

   long k = RR::prec - la + lb + 1;
   if (k < 0) k = 0;

   NTL_TLS_LOCAL(RR, t);
   NTL_ZZRegister(A);
   NTL_ZZRegister(B);
   NTL_ZZRegister(R);

   abs(A, a.x);
   LeftShift(A, A, k);

   abs(B, b.x);
   DivRem(t.x, R, A, B);

   t.e = a.e - b.e - k;

   normalize(z, t, !IsZero(R));

   if (neg)
      negate(z.x, z.x);
}
Exemple #30
0
bool_t ML(divisor& x, const divisor& a, const ZZ& n)
// Montgomery's ladder: used to defend side channel attacks
// cf. Alg. 13.35 of HOEHCC
{
  assert(a.is_valid_divisor());

  bool_t OK = TRUE;

  long nbits = NumBits(n);

  divisor b1, b2;


  if ( !nbits ) { // n = 0
    x.set_unit();
    return OK;
  }

  if ( n < 0) {
    OK = OK && ML(x, a, -n);
    OK = OK && dnegate(x, x);
    return OK;
  }

  // Case n > 0
  b1 = a; b2 = a + a;     
  for ( --nbits; OK && nbits > 0; --nbits) {
    if ( !bit(n, nbits - 1) ) {
      OK = OK && add(b2, b1, b2); // b2 = b1 + b2
      OK = OK && add(b1, b1, b1); // b1 = [2]*b1

    } else { 
      OK = OK && add(b1, b1, b2); // b1 = b1 + b2;
      OK = OK && add(b2, b2, b2); // b2 = [2]*b2;

      assert(OK);  

    }

  }

  assert(b1.is_valid_divisor());
  x = b1;

  return OK;

}