Răsfoiți Sursa

Turns out we need to patch bigint...

JC Brand 11 ani în urmă
părinte
comite
ab934b8573
1 a modificat fișierele cu 185 adăugiri și 165 ștergeri
  1. 185 165
      src/bigint.js

+ 185 - 165
src/bigint.js

@@ -1,17 +1,14 @@
 ;(function (root, factory) {
 
-  var Salsa20, crypto
   if (typeof define === 'function' && define.amd) {
-    define(['salsa20'], factory.bind(root, root.crypto))
+    define([], factory.bind(root, root.crypto || root.msCrypto))
   } else if (typeof module !== 'undefined' && module.exports) {
-    Salsa20 = require('./salsa20.js')
-    crypto = require('crypto')
-    module.exports = factory(crypto, Salsa20)
+    module.exports = factory(require('crypto'))
   } else {
-    root.BigInt = factory(root.crypto, root.Salsa20)
+    root.BigInt = factory(root.crypto || root.msCrypto)
   }
 
-}(this, function (crypto, Salsa20) {
+}(this, function (crypto) {
 
   ////////////////////////////////////////////////////////////////////////////////////////
   // Big Integer Library v. 5.5
@@ -151,7 +148,7 @@
   // void linCombShift_(x,y,b,ys) //do x=x+b*(y<<(ys*bpe)) for bigInts x and y, and integers b and ys
   // void mont_(x,y,n,np)         //Montgomery multiplication (see comments where the function is defined)
   // void multInt_(x,n)           //do x=x*n where x is a bigInt and n is an integer.
-  // void rightShift_(x,n)        //right shift bigInt x by n bits.  0 <= n < bpe. (This never overflows its array).
+  // void rightShift_(x,n)        //right shift bigInt x by n bits. (This never overflows its array).
   // void squareMod_(x,n)         //do x=x*x  mod n for bigInts x,n
   // void subShift_(x,y,ys)       //do x=x-(y<<(ys*bpe)). Negative answers will be 2s complement.
   //
@@ -195,18 +192,18 @@
   ////////////////////////////////////////////////////////////////////////////////////////
 
   //globals
-  var bpe = 0        // bits stored per array element
-  var mask=0;        //AND this with an array element to chop it down to bpe bits
-  var radix=mask+1;  //equals 2^bpe.  A single 1 bit to the left of the last bit of mask.
+
+  // The number of significant bits in the fraction of a JavaScript
+  // floating-point number is 52, independent of platform.
+  // See: https://github.com/arlolra/otr/issues/41
+
+  var bpe = 26;          // bits stored per array element
+  var radix = 1 << bpe;  // equals 2^bpe
+  var mask = radix - 1;  // AND this with an array element to chop it down to bpe bits
 
   //the digits for converting to different bases
   var digitsStr='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_=!@#$%^&*()[]{}|;:,.<>/?`~ \\\'\"+-';
 
-  //initialize the global variables
-  for (bpe = 0; (1<<(bpe+1)) > (1<<bpe); bpe++);  // bpe = number of bits in the mantissa on this platform
-  bpe>>=1;                   // bpe = number of bits in one element of the array representing the bigInt
-  mask=(1<<bpe)-1;           //AND the mask with an integer to get its bpe least significant bits
-  radix=mask+1;              //2^bpe.  a single 1 bit to the left of the first bit of mask
   var one=int2bigInt(1,1,1);     //constant used in powMod_()
 
   //the following global variables are scratchpad memory to 
@@ -940,11 +937,13 @@
       //    q[i-ky]--;    
       for (;;) {
         y2=(ky>1 ? y[ky-2] : 0)*q[i-ky];
-        c=y2>>bpe;
+        c=y2;
         y2=y2 & mask;
+        c = (c - y2) / radix;
         y1=c+q[i-ky]*y[ky-1];
-        c=y1>>bpe;
+        c=y1;
         y1=y1 & mask;
+        c = (c - y1) / radix;
 
         if (c==r[i] ? y1==r[i-1] ? y2>(i>1 ? r[i-2] : 0) : y1>r[i-1] : c>r[i]) 
           q[i-ky]--;
@@ -972,11 +971,12 @@
       c+=x[i];
       b=0;
       if (c<0) {
-        b=-(c>>bpe);
+        b = c & mask;
+        b = -((c - b) / radix);
         c+=b*radix;
       }
       x[i]=c & mask;
-      c=(c>>bpe)-b;
+      c = ((c - x[i]) / radix) - b;
     }
   }
 
@@ -1169,16 +1169,17 @@
       c+=x[i];
       b=0;
       if (c<0) {
-        b=-(c>>bpe);
+        b = c & mask;
+        b = -((c - b) / radix);
         c+=b*radix;
       }
       x[i]=c & mask;
-      c=(c>>bpe)-b;
+      c = ((c - x[i]) / radix) - b;
       if (!c) return; //stop carrying as soon as the carry is zero
     }
   }
 
-  //right shift bigInt x by n bits.  0 <= n < bpe.
+  //right shift bigInt x by n bits.
   function rightShift_(x,n) {
     var i;
     var k=Math.floor(n/bpe);
@@ -1235,11 +1236,12 @@
       c+=x[i]*n;
       b=0;
       if (c<0) {
-        b=-(c>>bpe);
+        b = c & mask;
+        b = -((c - b) / radix);
         c+=b*radix;
       }
       x[i]=c & mask;
-      c=(c>>bpe)-b;
+      c = ((c - x[i]) / radix) - b;
     }
   }
 
@@ -1263,12 +1265,12 @@
     for (c=0,i=0;i<k;i++) {
       c+=a*x[i]+b*y[i];
       x[i]=c & mask;
-      c>>=bpe;
+      c = (c - x[i]) / radix;
     }
     for (i=k;i<kk;i++) {
       c+=a*x[i];
       x[i]=c & mask;
-      c>>=bpe;
+      c = (c - x[i]) / radix;
     }
   }
 
@@ -1281,12 +1283,12 @@
     for (c=0,i=ys;i<k;i++) {
       c+=x[i]+b*y[i-ys];
       x[i]=c & mask;
-      c>>=bpe;
+      c = (c - x[i]) / radix;
     }
     for (i=k;c && i<kk;i++) {
       c+=x[i];
       x[i]=c & mask;
-      c>>=bpe;
+      c = (c - x[i]) / radix;
     }
   }
 
@@ -1299,12 +1301,12 @@
     for (c=0,i=ys;i<k;i++) {
       c+=x[i]+y[i-ys];
       x[i]=c & mask;
-      c>>=bpe;
+      c = (c - x[i]) / radix;
     }
     for (i=k;c && i<kk;i++) {
       c+=x[i];
       x[i]=c & mask;
-      c>>=bpe;
+      c = (c - x[i]) / radix;
     }
   }
 
@@ -1317,12 +1319,12 @@
     for (c=0,i=ys;i<k;i++) {
       c+=x[i]-y[i-ys];
       x[i]=c & mask;
-      c>>=bpe;
+      c = (c - x[i]) / radix;
     }
     for (i=k;c && i<kk;i++) {
       c+=x[i];
       x[i]=c & mask;
-      c>>=bpe;
+      c = (c - x[i]) / radix;
     }
   }
 
@@ -1335,12 +1337,12 @@
     for (c=0,i=0;i<k;i++) {
       c+=x[i]-y[i];
       x[i]=c & mask;
-      c>>=bpe;
+      c = (c - x[i]) / radix;
     }
     for (i=k;c && i<x.length;i++) {
       c+=x[i];
       x[i]=c & mask;
-      c>>=bpe;
+      c = (c - x[i]) / radix;
     }
   }
 
@@ -1352,12 +1354,12 @@
     for (c=0,i=0;i<k;i++) {
       c+=x[i]+y[i];
       x[i]=c & mask;
-      c>>=bpe;
+      c = (c - x[i]) / radix;
     }
     for (i=k;c && i<x.length;i++) {
       c+=x[i];
       x[i]=c & mask;
-      c>>=bpe;
+      c = (c - x[i]) / radix;
     }
   }
 
@@ -1409,11 +1411,11 @@
     for (i=0;i<kx;i++) {
       c=s0[2*i]+x[i]*x[i];
       s0[2*i]=c & mask;
-      c>>=bpe;
+      c = (c - s0[2*i]) / radix;
       for (j=i+1;j<kx;j++) {
         c=s0[i+j]+2*x[i]*x[j]+c;
         s0[i+j]=(c & mask);
-        c>>=bpe;
+        c = (c - s0[i+j]) / radix;
       }
       s0[i+kx]=c;
     }
@@ -1497,7 +1499,7 @@
   //  n is odd
   //  np = -(n^(-1)) mod radix
   function mont_(x,y,n,np) {
-    var i,j,c,ui,t,ks;
+    var i,j,c,ui,t,t2,ks;
     var kn=n.length;
     var ky=y.length;
 
@@ -1514,24 +1516,35 @@
     for (i=0; i<kn; i++) {
       t=sa[0]+x[i]*y[0];
       ui=((t & mask) * np) & mask;  //the inner "& mask" was needed on Safari (but not MSIE) at one time
-      c=(t+ui*n[0]) >> bpe;
+      c=(t+ui*n[0]);
+      c = (c - (c & mask)) / radix;
       t=x[i];
       
       //do sa=(sa+x[i]*y+ui*n)/b   where b=2**bpe.  Loop is unrolled 5-fold for speed
       j=1;
-      for (;j<ky-4;) { c+=sa[j]+ui*n[j]+t*y[j];   sa[j-1]=c & mask;   c>>=bpe;   j++;
-                       c+=sa[j]+ui*n[j]+t*y[j];   sa[j-1]=c & mask;   c>>=bpe;   j++;
-                       c+=sa[j]+ui*n[j]+t*y[j];   sa[j-1]=c & mask;   c>>=bpe;   j++;
-                       c+=sa[j]+ui*n[j]+t*y[j];   sa[j-1]=c & mask;   c>>=bpe;   j++;
-                       c+=sa[j]+ui*n[j]+t*y[j];   sa[j-1]=c & mask;   c>>=bpe;   j++; }    
-      for (;j<ky;)   { c+=sa[j]+ui*n[j]+t*y[j];   sa[j-1]=c & mask;   c>>=bpe;   j++; }
-      for (;j<kn-4;) { c+=sa[j]+ui*n[j];          sa[j-1]=c & mask;   c>>=bpe;   j++;
-                       c+=sa[j]+ui*n[j];          sa[j-1]=c & mask;   c>>=bpe;   j++;
-                       c+=sa[j]+ui*n[j];          sa[j-1]=c & mask;   c>>=bpe;   j++;
-                       c+=sa[j]+ui*n[j];          sa[j-1]=c & mask;   c>>=bpe;   j++;
-                       c+=sa[j]+ui*n[j];          sa[j-1]=c & mask;   c>>=bpe;   j++; }  
-      for (;j<kn;)   { c+=sa[j]+ui*n[j];          sa[j-1]=c & mask;   c>>=bpe;   j++; }   
-      for (;j<ks;)   { c+=sa[j];                  sa[j-1]=c & mask;   c>>=bpe;   j++; }  
+      for (;j<ky-4;) {
+        c+=sa[j]+ui*n[j]+t*y[j]; t2=sa[j-1]=c & mask; c=(c-t2)/radix; j++;
+        c+=sa[j]+ui*n[j]+t*y[j]; t2=sa[j-1]=c & mask; c=(c-t2)/radix; j++;
+        c+=sa[j]+ui*n[j]+t*y[j]; t2=sa[j-1]=c & mask; c=(c-t2)/radix; j++;
+        c+=sa[j]+ui*n[j]+t*y[j]; t2=sa[j-1]=c & mask; c=(c-t2)/radix; j++;
+        c+=sa[j]+ui*n[j]+t*y[j]; t2=sa[j-1]=c & mask; c=(c-t2)/radix; j++;
+      }
+      for (;j<ky;)   {
+        c+=sa[j]+ui*n[j]+t*y[j]; t2=sa[j-1]=c & mask; c=(c-t2)/radix; j++;
+      }
+      for (;j<kn-4;) {
+        c+=sa[j]+ui*n[j];        t2=sa[j-1]=c & mask; c=(c-t2)/radix; j++;
+        c+=sa[j]+ui*n[j];        t2=sa[j-1]=c & mask; c=(c-t2)/radix; j++;
+        c+=sa[j]+ui*n[j];        t2=sa[j-1]=c & mask; c=(c-t2)/radix; j++;
+        c+=sa[j]+ui*n[j];        t2=sa[j-1]=c & mask; c=(c-t2)/radix; j++;
+        c+=sa[j]+ui*n[j];        t2=sa[j-1]=c & mask; c=(c-t2)/radix; j++;
+      }
+      for (;j<kn;)   {
+        c+=sa[j]+ui*n[j];        t2=sa[j-1]=c & mask; c=(c-t2)/radix; j++;
+      }
+      for (;j<ks;)   {
+        c+=sa[j];                t2=sa[j-1]=c & mask; c=(c-t2)/radix; j++;
+      }
       sa[j-1]=c & mask;
     }
 
@@ -1541,9 +1554,120 @@
   }
 
 
-  // otr.js stuff
+  // otr.js additions
+
+
+  // computes num / den mod n
+  function divMod(num, den, n) {
+    return multMod(num, inverseMod(den, n), n)
+  }
+
+  // computes one - two mod n
+  function subMod(one, two, n) {
+    one = mod(one, n)
+    two = mod(two, n)
+    if (greater(two, one)) one = add(one, n)
+    return sub(one, two)
+  }
+
+  // computes 2^m as a bigInt
+  function twoToThe(m) {
+    var b = Math.floor(m / bpe) + 2
+    var t = new Array(b)
+    for (var i = 0; i < b; i++) t[i] = 0
+    t[b - 2] = 1 << (m % bpe)
+    return t
+  }
+
+  // cache these results for faster lookup
+  var _num2bin = (function () {
+    var i = 0, _num2bin= {}
+    for (; i < 0x100; ++i) {
+      _num2bin[i] = String.fromCharCode(i)  // 0 -> "\00"
+    }
+    return _num2bin
+  }())
+
+  // serialize a bigInt to an ascii string
+  // padded up to pad length
+  function bigInt2bits(bi, pad) {
+    pad || (pad = 0)
+    bi = dup(bi)
+    var ba = ''
+    while (!isZero(bi)) {
+      ba = _num2bin[bi[0] & 0xff] + ba
+      rightShift_(bi, 8)
+    }
+    while (ba.length < pad) {
+      ba = '\x00' + ba
+    }
+    return ba
+  }
+
+  // converts a byte array to a bigInt
+  function ba2bigInt(data) {
+    var mpi = str2bigInt('0', 10, data.length)
+    data.forEach(function (d, i) {
+      if (i) leftShift_(mpi, 8)
+      mpi[0] |= d
+    })
+    return mpi
+  }
+
+  // returns a function that returns an array of n bytes
+  var randomBytes = (function () {
+
+    // in node
+    if ( typeof crypto !== 'undefined' &&
+      typeof crypto.randomBytes === 'function' ) {
+      return function (n) {
+        try {
+          var buf = crypto.randomBytes(n)
+        } catch (e) { throw e }
+        return Array.prototype.slice.call(buf, 0)
+      }
+    }
+
+    // in browser
+    else if ( typeof crypto !== 'undefined' &&
+      typeof crypto.getRandomValues === 'function' ) {
+      return function (n) {
+        var buf = new Uint8Array(n)
+        crypto.getRandomValues(buf)
+        return Array.prototype.slice.call(buf, 0)
+      }
+    }
+
+    // err
+    else {
+      throw new Error('Keys should not be generated without CSPRNG.')
+    }
+
+  }())
+
+  // Salsa 20 in webworker needs a 40 byte seed
+  function getSeed() {
+    return randomBytes(40)
+  }
+
+  // returns a single random byte
+  function randomByte() {
+    return randomBytes(1)[0]
+  }
+
+  // returns a k-bit random integer
+  function randomBitInt(k) {
+    if (k > 31) throw new Error("Too many bits.")
+    var i = 0, r = 0
+    var b = Math.floor(k / 8)
+    var mask = (1 << (k % 8)) - 1
+    if (mask) r = randomByte() & mask
+    for (; i < b; i++)
+      r = (256 * r) + randomByte()
+    return r
+  }
 
-  var BigInt = {
+  return {
       str2bigInt    : str2bigInt
     , bigInt2str    : bigInt2str
     , int2bigInt    : int2bigInt
@@ -1556,130 +1680,26 @@
     , equalsInt     : equalsInt
     , sub           : sub
     , mod           : mod
-    , mod_          : mod_
     , modInt        : modInt
     , mult          : mult
     , divInt_       : divInt_
     , rightShift_   : rightShift_
-    , leftShift_    : leftShift_
     , dup           : dup
     , greater       : greater
     , add           : add
-    , addInt        : addInt
-    , addInt_       : addInt_
     , isZero        : isZero
     , bitSize       : bitSize
-    , randTruePrime : randTruePrime
     , millerRabin   : millerRabin
     , divide_       : divide_
     , trim          : trim
-    , expand        : expand
-    , bpe           : bpe
     , primes        : primes
     , findPrimes    : findPrimes
     , getSeed       : getSeed
+    , divMod        : divMod
+    , subMod        : subMod
+    , twoToThe      : twoToThe
+    , bigInt2bits   : bigInt2bits
+    , ba2bigInt     : ba2bigInt
   }
 
-  // from http://davidbau.com/encode/seedrandom.js
-
-  var randomBitInt
-
-  function seedRand(buf) {
-
-    var state = new Salsa20([
-      buf[ 0], buf[ 1], buf[ 2], buf[ 3], buf[ 4], buf[ 5], buf[ 6], buf[ 7],
-      buf[ 8], buf[ 9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15],
-      buf[16], buf[17], buf[18], buf[19], buf[20], buf[21], buf[22], buf[23],
-      buf[24], buf[25], buf[26], buf[27], buf[28], buf[29], buf[30], buf[31]
-    ],[
-      buf[32], buf[33], buf[34], buf[35], buf[36], buf[37], buf[38], buf[39]
-    ])
-
-    var width = 256
-      , chunks = 6
-      , significance = Math.pow(2, 52)
-      , overflow = significance * 2
-
-    function numerator() {
-      var bytes = state.getBytes(chunks)
-      var i = 0, r = 0
-      for (; i < chunks; i++) {
-        r = r * width + bytes[i]
-      }
-      return r
-    }
-
-    function randomByte() {
-      return state.getBytes(1)[0]
-    }
-
-    randomBitInt = function (k) {
-      if (k > 31) throw new Error("Too many bits.")
-      var i = 0, r = 0
-      var b = Math.floor(k / 8)
-      var mask = (1 << (k % 8)) - 1
-      if (mask) r = randomByte() & mask
-      for (; i < b; i++)
-        r = (256 * r) + randomByte()
-      return r
-    }
-
-    // This function returns a random double in [0, 1) that contains
-    // randomness in every bit of the mantissa of the IEEE 754 value.
-
-    return function () {               // Closure to return a random double:
-      var n = numerator()              // Start with a numerator n < 2 ^ 48
-        , d = Math.pow(width, chunks)  //   and denominator d = 2 ^ 48.
-        , x = 0                        //   and no 'extra last byte'.
-      while (n < significance) {       // Fill up all significant digits by
-        n = (n + x) * width            //   shifting numerator and
-        d *= width                     //   denominator and generating a
-        x = randomByte()               //   new least-significant-byte.
-      }
-      while (n >= overflow) {          // To avoid rounding up, before adding
-        n /= 2                         //   last byte, shift everything
-        d /= 2                         //   right using integer math until
-        x >>>= 1                       //   we have exactly the desired bits.
-      }
-      return (n + x) / d               // Form the number within [0, 1).
-    }
-
-  }
-
-  function getSeed() {
-    var buf
-    if ( (typeof crypto !== 'undefined') &&
-         (typeof crypto.randomBytes === 'function')
-    ) {
-      try {
-        buf = crypto.randomBytes(40)
-      } catch (e) { throw e }
-    } else if ( (typeof crypto !== 'undefined') &&
-                (typeof crypto.getRandomValues === 'function')
-    ) {
-      buf = new Uint8Array(40)
-      crypto.getRandomValues(buf)
-    } else {
-      throw new Error('Keys should not be generated without CSPRNG.')
-    }
-    return Array.prototype.slice.call(buf, 0)
-  }
-
-  ;(function seed() {
-    var HAS_CSPRNG = ((typeof crypto !== 'undefined') &&
-        ((typeof crypto.randomBytes === 'function') ||
-            (typeof crypto.getRandomValues === 'function')
-    ));
-    if (!HAS_CSPRNG) {
-        return;
-    }
-    Math.random = seedRand(getSeed())
-
-    // reseed every 5 mins (not in ww)
-    if ( typeof setTimeout === 'function' && typeof document !== 'undefined' )
-      setTimeout(seed, 5 * 60 * 1000)
-
-  }())
-
-  return BigInt
 }))