content: package im.actor.crypto.primitives.curve25519;
  
  public class ge_double_scalarmult {
  
  //CONVERT #include "ge.h"
  
  static public void slide(byte[] r,byte[] a)
  {
    int i;
    int b;
    int k;
  
    for (i = 0;i < 256;++i) {
      //CONVERT r[i] = 1 & (a[i >> 3] >> (i & 7));
      r[i] = (byte)(1 & (a[i >> 3] >>> (i & 7)));
      }
  
    for (i = 0;i < 256;++i)
      if (r[i] != 0) {
        for (b = 1;b <= 6 && i + b < 256;++b) {
          if (r[i + b] != 0) {
            if (r[i] + (r[i + b] << b) <= 15) {
              r[i] += r[i + b] << b; r[i + b] = 0;
            } else if (r[i] - (r[i + b] << b) >= -15) {
              r[i] -= r[i + b] << b;
              for (k = i + b;k < 256;++k) {
                if (r[k] == 0) {
                  r[k] = 1;
                  break;
                }
                r[k] = 0;
              }
            } else
              break;
          }
        }
      }
  
  }
  
  static ge_precomp Bi[];
  
  static {
      Bi = new ge_precomp[8];
      Bi[0] = new ge_precomp(
      new int[]{ 25967493,-14356035,29566456,3660896,-12694345,4014787,27544626,-11754271,-6079156,2047605 },
      new int[]{ -12545711,934262,-2722910,3049990,-727428,9406986,12720692,5043384,19500929,-15469378 },
      new int[]{ -8738181,4489570,9688441,-14785194,10184609,-12363380,29287919,11864899,-24514362,-4438546 }
      );
      Bi[1] = new ge_precomp(
      new int[]{ 15636291,-9688557,24204773,-7912398,616977,-16685262,27787600,-14772189,28944400,-1550024 },
      new int[]{ 16568933,4717097,-11556148,-1102322,15682896,-11807043,16354577,-11775962,7689662,11199574 },
      new int[]{ 30464156,-5976125,-11779434,-15670865,23220365,15915852,7512774,10017326,-17749093,-9920357 }
      );
      Bi[2] = new ge_precomp(
      new int[]{ 10861363,11473154,27284546,1981175,-30064349,12577861,32867885,14515107,-15438304,10819380 },
      new int[]{ 4708026,6336745,20377586,9066809,-11272109,6594696,-25653668,12483688,-12668491,5581306 },
      new int[]{ 19563160,16186464,-29386857,4097519,10237984,-4348115,28542350,13850243,-23678021,-15815942 }
      );
      Bi[3] = new ge_precomp(
      new int[]{ 5153746,9909285,1723747,-2777874,30523605,5516873,19480852,5230134,-23952439,-15175766 },
      new int[]{ -30269007,-3463509,7665486,10083793,28475525,1649722,20654025,16520125,30598449,7715701 },
      new int[]{ 28881845,14381568,9657904,3680757,-20181635,7843316,-31400660,1370708,29794553,-1409300 }
      );
      Bi[4] = new ge_precomp(
      new int[]{ -22518993,-6692182,14201702,-8745502,-23510406,8844726,18474211,-1361450,-13062696,13821877 },
      new int[]{ -6455177,-7839871,3374702,-4740862,-27098617,-10571707,31655028,-7212327,18853322,-14220951 },
      new int[]{ 4566830,-12963868,-28974889,-12240689,-7602672,-2830569,-8514358,-10431137,2207753,-3209784 }
      );
      Bi[5] = new ge_precomp(
      new int[]{ -25154831,-4185821,29681144,7868801,-6854661,-9423865,-12437364,-663000,-31111463,-16132436 },
      new int[]{ 25576264,-2703214,7349804,-11814844,16472782,9300885,3844789,15725684,171356,6466918 },
      new int[]{ 23103977,13316479,9739013,-16149481,817875,-15038942,8965339,-14088058,-30714912,16193877 }
      );
      Bi[6] = new ge_precomp(
      new int[]{ -33521811,3180713,-2394130,14003687,-16903474,-16270840,17238398,4729455,-18074513,9256800 },
      new int[]{ -25182317,-4174131,32336398,5036987,-21236817,11360617,22616405,9761698,-19827198,630305 },
      new int[]{ -13720693,2639453,-24237460,-7406481,9494427,-5774029,-6554551,-15960994,-2449256,-14291300 }
      );
      Bi[7] = new ge_precomp(
      new int[]{ -3151181,-5046075,9282714,6866145,-31907062,-863023,-18940575,15033784,25105118,-7894876 },
      new int[]{ -24326370,15950226,-31801215,-14592823,-11662737,-5090925,1573892,-2625887,2198790,-15804619 },
      new int[]{ -3099351,10324967,-2241613,7453183,-5446979,-2735503,-13812022,-16236442,-32461234,-12290683 }
      );
  }
  
  /*
  r = a * A + b * B
  where a = a[0]+256*a[1]+...+256^31 a[31].
  and b = b[0]+256*b[1]+...+256^31 b[31].
  B is the Ed25519 base point (x,4/5) with x positive.
  */
  
  public static void ge_double_scalarmult_vartime(ge_p2 r,byte[] a,ge_p3 A,byte[] b)
  {
    byte[] aslide = new byte[256];
    byte[] bslide = new byte[256];
    ge_cached Ai[] = new ge_cached[8]; /* A,3A,5A,7A,9A,11A,13A,15A */
    for (int count=0; count < 8; count++)
      Ai[count] = new ge_cached();
    ge_p1p1 t = new ge_p1p1();
    ge_p3 u = new ge_p3();
    ge_p3 A2 = new ge_p3();
    int i;
  
    slide(aslide,a);
    slide(bslide,b);
  
    ge_p3_to_cached.ge_p3_to_cached(Ai[0],A);
    ge_p3_dbl.ge_p3_dbl(t,A); ge_p1p1_to_p3.ge_p1p1_to_p3(A2,t);
    ge_add.ge_add(t,A2,Ai[0]); ge_p1p1_to_p3.ge_p1p1_to_p3(u,t); ge_p3_to_cached.ge_p3_to_cached(Ai[1],u);
    ge_add.ge_add(t,A2,Ai[1]); ge_p1p1_to_p3.ge_p1p1_to_p3(u,t); ge_p3_to_cached.ge_p3_to_cached(Ai[2],u);
    ge_add.ge_add(t,A2,Ai[2]); ge_p1p1_to_p3.ge_p1p1_to_p3(u,t); ge_p3_to_cached.ge_p3_to_cached(Ai[3],u);
    ge_add.ge_add(t,A2,Ai[3]); ge_p1p1_to_p3.ge_p1p1_to_p3(u,t); ge_p3_to_cached.ge_p3_to_cached(Ai[4],u);
    ge_add.ge_add(t,A2,Ai[4]); ge_p1p1_to_p3.ge_p1p1_to_p3(u,t); ge_p3_to_cached.ge_p3_to_cached(Ai[5],u);
    ge_add.ge_add(t,A2,Ai[5]); ge_p1p1_to_p3.ge_p1p1_to_p3(u,t); ge_p3_to_cached.ge_p3_to_cached(Ai[6],u);
    ge_add.ge_add(t,A2,Ai[6]); ge_p1p1_to_p3.ge_p1p1_to_p3(u,t); ge_p3_to_cached.ge_p3_to_cached(Ai[7],u);
  
    ge_p2_0.ge_p2_0(r);
  
    for (i = 255;i >= 0;--i) {
      if (aslide[i] !=0 || bslide[i] != 0) break;
    }
  
    for (;i >= 0;--i) {
      ge_p2_dbl.ge_p2_dbl(t,r);
  
      if (aslide[i] > 0) {
        ge_p1p1_to_p3.ge_p1p1_to_p3(u,t);
        ge_add.ge_add(t,u,Ai[aslide[i]/2]);
      } else if (aslide[i] < 0) {
        ge_p1p1_to_p3.ge_p1p1_to_p3(u,t);
        ge_sub.ge_sub(t,u,Ai[(-aslide[i])/2]);
      }
  
      if (bslide[i] > 0) {
        ge_p1p1_to_p3.ge_p1p1_to_p3(u,t);
        ge_madd.ge_madd(t,u,Bi[bslide[i]/2]);
      } else if (bslide[i] < 0) {
        ge_p1p1_to_p3.ge_p1p1_to_p3(u,t);
        ge_msub.ge_msub(t,u,Bi[(-bslide[i])/2]);
      }
  
      ge_p1p1_to_p2.ge_p1p1_to_p2(r,t);
    }
  }
  
  
  }
  