Browse Source

Use AMD-aware cryptojs from NPM. Update to 0.2.16

JC Brand 8 years ago
parent
commit
70d385bc28
6 changed files with 27 additions and 4362 deletions
  1. 0 1707
      3rdparty/bigint.js
  2. 0 22
      3rdparty/crypto.js
  3. 0 2606
      3rdparty/otr.js
  4. 16 25
      config.js
  5. 2 0
      src/converse-chatview.js
  6. 9 2
      src/converse-otr.js

+ 0 - 1707
3rdparty/bigint.js

@@ -1,1707 +0,0 @@
-;(function (root, factory) {
-
-  if (typeof define === 'function' && define.amd) {
-    define([], factory.bind(root, root.crypto || root.msCrypto))
-  } else if (typeof module !== 'undefined' && module.exports) {
-    module.exports = factory(require('crypto'))
-  } else {
-    root.BigInt = factory(root.crypto || root.msCrypto)
-  }
-
-}(this, function (crypto) {
-
-  ////////////////////////////////////////////////////////////////////////////////////////
-  // Big Integer Library v. 5.5
-  // Created 2000, last modified 2013
-  // Leemon Baird
-  // www.leemon.com
-  //
-  // Version history:
-  // v 5.5  17 Mar 2013
-  //   - two lines of a form like "if (x<0) x+=n" had the "if" changed to "while" to
-  //     handle the case when x<-n. (Thanks to James Ansell for finding that bug)
-  // v 5.4  3 Oct 2009
-  //   - added "var i" to greaterShift() so i is not global. (Thanks to Péter Szabó for finding that bug)
-  //
-  // v 5.3  21 Sep 2009
-  //   - added randProbPrime(k) for probable primes
-  //   - unrolled loop in mont_ (slightly faster)
-  //   - millerRabin now takes a bigInt parameter rather than an int
-  //
-  // v 5.2  15 Sep 2009
-  //   - fixed capitalization in call to int2bigInt in randBigInt
-  //     (thanks to Emili Evripidou, Reinhold Behringer, and Samuel Macaleese for finding that bug)
-  //
-  // v 5.1  8 Oct 2007 
-  //   - renamed inverseModInt_ to inverseModInt since it doesn't change its parameters
-  //   - added functions GCD and randBigInt, which call GCD_ and randBigInt_
-  //   - fixed a bug found by Rob Visser (see comment with his name below)
-  //   - improved comments
-  //
-  // This file is public domain.   You can use it for any purpose without restriction.
-  // I do not guarantee that it is correct, so use it at your own risk.  If you use 
-  // it for something interesting, I'd appreciate hearing about it.  If you find 
-  // any bugs or make any improvements, I'd appreciate hearing about those too.
-  // It would also be nice if my name and URL were left in the comments.  But none 
-  // of that is required.
-  //
-  // This code defines a bigInt library for arbitrary-precision integers.
-  // A bigInt is an array of integers storing the value in chunks of bpe bits, 
-  // little endian (buff[0] is the least significant word).
-  // Negative bigInts are stored two's complement.  Almost all the functions treat
-  // bigInts as nonnegative.  The few that view them as two's complement say so
-  // in their comments.  Some functions assume their parameters have at least one 
-  // leading zero element. Functions with an underscore at the end of the name put
-  // their answer into one of the arrays passed in, and have unpredictable behavior 
-  // in case of overflow, so the caller must make sure the arrays are big enough to 
-  // hold the answer.  But the average user should never have to call any of the 
-  // underscored functions.  Each important underscored function has a wrapper function 
-  // of the same name without the underscore that takes care of the details for you.  
-  // For each underscored function where a parameter is modified, that same variable 
-  // must not be used as another argument too.  So, you cannot square x by doing 
-  // multMod_(x,x,n).  You must use squareMod_(x,n) instead, or do y=dup(x); multMod_(x,y,n).
-  // Or simply use the multMod(x,x,n) function without the underscore, where
-  // such issues never arise, because non-underscored functions never change
-  // their parameters; they always allocate new memory for the answer that is returned.
-  //
-  // These functions are designed to avoid frequent dynamic memory allocation in the inner loop.
-  // For most functions, if it needs a BigInt as a local variable it will actually use
-  // a global, and will only allocate to it only when it's not the right size.  This ensures
-  // that when a function is called repeatedly with same-sized parameters, it only allocates
-  // memory on the first call.
-  //
-  // Note that for cryptographic purposes, the calls to Math.random() must 
-  // be replaced with calls to a better pseudorandom number generator.
-  //
-  // In the following, "bigInt" means a bigInt with at least one leading zero element,
-  // and "integer" means a nonnegative integer less than radix.  In some cases, integer 
-  // can be negative.  Negative bigInts are 2s complement.
-  // 
-  // The following functions do not modify their inputs.
-  // Those returning a bigInt, string, or Array will dynamically allocate memory for that value.
-  // Those returning a boolean will return the integer 0 (false) or 1 (true).
-  // Those returning boolean or int will not allocate memory except possibly on the first 
-  // time they're called with a given parameter size.
-  // 
-  // bigInt  add(x,y)               //return (x+y) for bigInts x and y.  
-  // bigInt  addInt(x,n)            //return (x+n) where x is a bigInt and n is an integer.
-  // string  bigInt2str(x,base)     //return a string form of bigInt x in a given base, with 2 <= base <= 95
-  // int     bitSize(x)             //return how many bits long the bigInt x is, not counting leading zeros
-  // bigInt  dup(x)                 //return a copy of bigInt x
-  // boolean equals(x,y)            //is the bigInt x equal to the bigint y?
-  // boolean equalsInt(x,y)         //is bigint x equal to integer y?
-  // bigInt  expand(x,n)            //return a copy of x with at least n elements, adding leading zeros if needed
-  // Array   findPrimes(n)          //return array of all primes less than integer n
-  // bigInt  GCD(x,y)               //return greatest common divisor of bigInts x and y (each with same number of elements).
-  // boolean greater(x,y)           //is x>y?  (x and y are nonnegative bigInts)
-  // boolean greaterShift(x,y,shift)//is (x <<(shift*bpe)) > y?
-  // bigInt  int2bigInt(t,n,m)      //return a bigInt equal to integer t, with at least n bits and m array elements
-  // bigInt  inverseMod(x,n)        //return (x**(-1) mod n) for bigInts x and n.  If no inverse exists, it returns null
-  // int     inverseModInt(x,n)     //return x**(-1) mod n, for integers x and n.  Return 0 if there is no inverse
-  // boolean isZero(x)              //is the bigInt x equal to zero?
-  // boolean millerRabin(x,b)       //does one round of Miller-Rabin base integer b say that bigInt x is possibly prime? (b is bigInt, 1<b<x)
-  // boolean millerRabinInt(x,b)    //does one round of Miller-Rabin base integer b say that bigInt x is possibly prime? (b is int,    1<b<x)
-  // bigInt  mod(x,n)               //return a new bigInt equal to (x mod n) for bigInts x and n.
-  // int     modInt(x,n)            //return x mod n for bigInt x and integer n.
-  // bigInt  mult(x,y)              //return x*y for bigInts x and y. This is faster when y<x.
-  // bigInt  multMod(x,y,n)         //return (x*y mod n) for bigInts x,y,n.  For greater speed, let y<x.
-  // boolean negative(x)            //is bigInt x negative?
-  // bigInt  powMod(x,y,n)          //return (x**y mod n) where x,y,n are bigInts and ** is exponentiation.  0**0=1. Faster for odd n.
-  // bigInt  randBigInt(n,s)        //return an n-bit random BigInt (n>=1).  If s=1, then the most significant of those n bits is set to 1.
-  // bigInt  randTruePrime(k)       //return a new, random, k-bit, true prime bigInt using Maurer's algorithm.
-  // bigInt  randProbPrime(k)       //return a new, random, k-bit, probable prime bigInt (probability it's composite less than 2^-80).
-  // bigInt  str2bigInt(s,b,n,m)    //return a bigInt for number represented in string s in base b with at least n bits and m array elements
-  // bigInt  sub(x,y)               //return (x-y) for bigInts x and y.  Negative answers will be 2s complement
-  // bigInt  trim(x,k)              //return a copy of x with exactly k leading zero elements
-  //
-  //
-  // The following functions each have a non-underscored version, which most users should call instead.
-  // These functions each write to a single parameter, and the caller is responsible for ensuring the array 
-  // passed in is large enough to hold the result. 
-  //
-  // void    addInt_(x,n)          //do x=x+n where x is a bigInt and n is an integer
-  // void    add_(x,y)             //do x=x+y for bigInts x and y
-  // void    copy_(x,y)            //do x=y on bigInts x and y
-  // void    copyInt_(x,n)         //do x=n on bigInt x and integer n
-  // void    GCD_(x,y)             //set x to the greatest common divisor of bigInts x and y, (y is destroyed).  (This never overflows its array).
-  // boolean inverseMod_(x,n)      //do x=x**(-1) mod n, for bigInts x and n. Returns 1 (0) if inverse does (doesn't) exist
-  // void    mod_(x,n)             //do x=x mod n for bigInts x and n. (This never overflows its array).
-  // void    mult_(x,y)            //do x=x*y for bigInts x and y.
-  // void    multMod_(x,y,n)       //do x=x*y  mod n for bigInts x,y,n.
-  // void    powMod_(x,y,n)        //do x=x**y mod n, where x,y,n are bigInts (n is odd) and ** is exponentiation.  0**0=1.
-  // void    randBigInt_(b,n,s)    //do b = an n-bit random BigInt. if s=1, then nth bit (most significant bit) is set to 1. n>=1.
-  // void    randTruePrime_(ans,k) //do ans = a random k-bit true random prime (not just probable prime) with 1 in the msb.
-  // void    sub_(x,y)             //do x=x-y for bigInts x and y. Negative answers will be 2s complement.
-  //
-  // The following functions do NOT have a non-underscored version. 
-  // They each write a bigInt result to one or more parameters.  The caller is responsible for
-  // ensuring the arrays passed in are large enough to hold the results. 
-  //
-  // void addShift_(x,y,ys)       //do x=x+(y<<(ys*bpe))
-  // void carry_(x)               //do carries and borrows so each element of the bigInt x fits in bpe bits.
-  // void divide_(x,y,q,r)        //divide x by y giving quotient q and remainder r
-  // int  divInt_(x,n)            //do x=floor(x/n) for bigInt x and integer n, and return the remainder. (This never overflows its array).
-  // int  eGCD_(x,y,d,a,b)        //sets a,b,d to positive bigInts such that d = GCD_(x,y) = a*x-b*y
-  // void halve_(x)               //do x=floor(|x|/2)*sgn(x) for bigInt x in 2's complement.  (This never overflows its array).
-  // void leftShift_(x,n)         //left shift bigInt x by n bits.  n<bpe.
-  // void linComb_(x,y,a,b)       //do x=a*x+b*y for bigInts x and y and integers a and b
-  // 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. (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.
-  //
-  // The following functions are based on algorithms from the _Handbook of Applied Cryptography_
-  //    powMod_()           = algorithm 14.94, Montgomery exponentiation
-  //    eGCD_,inverseMod_() = algorithm 14.61, Binary extended GCD_
-  //    GCD_()              = algorothm 14.57, Lehmer's algorithm
-  //    mont_()             = algorithm 14.36, Montgomery multiplication
-  //    divide_()           = algorithm 14.20  Multiple-precision division
-  //    squareMod_()        = algorithm 14.16  Multiple-precision squaring
-  //    randTruePrime_()    = algorithm  4.62, Maurer's algorithm
-  //    millerRabin()       = algorithm  4.24, Miller-Rabin algorithm
-  //
-  // Profiling shows:
-  //     randTruePrime_() spends:
-  //         10% of its time in calls to powMod_()
-  //         85% of its time in calls to millerRabin()
-  //     millerRabin() spends:
-  //         99% of its time in calls to powMod_()   (always with a base of 2)
-  //     powMod_() spends:
-  //         94% of its time in calls to mont_()  (almost always with x==y)
-  //
-  // This suggests there are several ways to speed up this library slightly:
-  //     - convert powMod_ to use a Montgomery form of k-ary window (or maybe a Montgomery form of sliding window)
-  //         -- this should especially focus on being fast when raising 2 to a power mod n
-  //     - convert randTruePrime_() to use a minimum r of 1/3 instead of 1/2 with the appropriate change to the test
-  //     - tune the parameters in randTruePrime_(), including c, m, and recLimit
-  //     - speed up the single loop in mont_() that takes 95% of the runtime, perhaps by reducing checking
-  //       within the loop when all the parameters are the same length.
-  //
-  // There are several ideas that look like they wouldn't help much at all:
-  //     - replacing trial division in randTruePrime_() with a sieve (that speeds up something taking almost no time anyway)
-  //     - increase bpe from 15 to 30 (that would help if we had a 32*32->64 multiplier, but not with JavaScript's 32*32->32)
-  //     - speeding up mont_(x,y,n,np) when x==y by doing a non-modular, non-Montgomery square
-  //       followed by a Montgomery reduction.  The intermediate answer will be twice as long as x, so that
-  //       method would be slower.  This is unfortunate because the code currently spends almost all of its time
-  //       doing mont_(x,x,...), both for randTruePrime_() and powMod_().  A faster method for Montgomery squaring
-  //       would have a large impact on the speed of randTruePrime_() and powMod_().  HAC has a couple of poorly-worded
-  //       sentences that seem to imply it's faster to do a non-modular square followed by a single
-  //       Montgomery reduction, but that's obviously wrong.
-  ////////////////////////////////////////////////////////////////////////////////////////
-
-  //globals
-
-  // 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_=!@#$%^&*()[]{}|;:,.<>/?`~ \\\'\"+-';
-
-  var one=int2bigInt(1,1,1);     //constant used in powMod_()
-
-  //the following global variables are scratchpad memory to 
-  //reduce dynamic memory allocation in the inner loop
-  var t=new Array(0);
-  var ss=t;       //used in mult_()
-  var s0=t;       //used in multMod_(), squareMod_()
-  var s1=t;       //used in powMod_(), multMod_(), squareMod_()
-  var s2=t;       //used in powMod_(), multMod_()
-  var s3=t;       //used in powMod_()
-  var s4=t, s5=t; //used in mod_()
-  var s6=t;       //used in bigInt2str()
-  var s7=t;       //used in powMod_()
-  var T=t;        //used in GCD_()
-  var sa=t;       //used in mont_()
-  var mr_x1=t, mr_r=t, mr_a=t;                                      //used in millerRabin()
-  var eg_v=t, eg_u=t, eg_A=t, eg_B=t, eg_C=t, eg_D=t;               //used in eGCD_(), inverseMod_()
-  var md_q1=t, md_q2=t, md_q3=t, md_r=t, md_r1=t, md_r2=t, md_tt=t; //used in mod_()
-
-  var primes=t, pows=t, s_i=t, s_i2=t, s_R=t, s_rm=t, s_q=t, s_n1=t;
-  var s_a=t, s_r2=t, s_n=t, s_b=t, s_d=t, s_x1=t, s_x2=t, s_aa=t; //used in randTruePrime_()
-    
-  var rpprb=t; //used in randProbPrimeRounds() (which also uses "primes")
-
-  ////////////////////////////////////////////////////////////////////////////////////////
-
-
-  //return array of all primes less than integer n
-  function findPrimes(n) {
-    var i,s,p,ans;
-    s=new Array(n);
-    for (i=0;i<n;i++)
-      s[i]=0;
-    s[0]=2;
-    p=0;    //first p elements of s are primes, the rest are a sieve
-    for(;s[p]<n;) {                  //s[p] is the pth prime
-      for(i=s[p]*s[p]; i<n; i+=s[p]) //mark multiples of s[p]
-        s[i]=1;
-      p++;
-      s[p]=s[p-1]+1;
-      for(; s[p]<n && s[s[p]]; s[p]++); //find next prime (where s[p]==0)
-    }
-    ans=new Array(p);
-    for(i=0;i<p;i++)
-      ans[i]=s[i];
-    return ans;
-  }
-
-
-  //does a single round of Miller-Rabin base b consider x to be a possible prime?
-  //x is a bigInt, and b is an integer, with b<x
-  function millerRabinInt(x,b) {
-    if (mr_x1.length!=x.length) {
-      mr_x1=dup(x);
-      mr_r=dup(x);
-      mr_a=dup(x);
-    }
-
-    copyInt_(mr_a,b);
-    return millerRabin(x,mr_a);
-  }
-
-  //does a single round of Miller-Rabin base b consider x to be a possible prime?
-  //x and b are bigInts with b<x
-  function millerRabin(x,b) {
-    var i,j,k,s;
-
-    if (mr_x1.length!=x.length) {
-      mr_x1=dup(x);
-      mr_r=dup(x);
-      mr_a=dup(x);
-    }
-
-    copy_(mr_a,b);
-    copy_(mr_r,x);
-    copy_(mr_x1,x);
-
-    addInt_(mr_r,-1);
-    addInt_(mr_x1,-1);
-
-    //s=the highest power of two that divides mr_r
-
-    /*
-    k=0;
-    for (i=0;i<mr_r.length;i++)
-      for (j=1;j<mask;j<<=1)
-        if (x[i] & j) {
-          s=(k<mr_r.length+bpe ? k : 0); 
-           i=mr_r.length;
-           j=mask;
-        } else
-          k++;
-    */
-
-    /* http://www.javascripter.net/math/primes/millerrabinbug-bigint54.htm */
-    if (isZero(mr_r)) return 0;
-    for (k=0; mr_r[k]==0; k++);
-    for (i=1,j=2; mr_r[k]%j==0; j*=2,i++ );
-    s = k*bpe + i - 1;
-    /* end */
-
-    if (s)                
-      rightShift_(mr_r,s);
-
-    powMod_(mr_a,mr_r,x);
-
-    if (!equalsInt(mr_a,1) && !equals(mr_a,mr_x1)) {
-      j=1;
-      while (j<=s-1 && !equals(mr_a,mr_x1)) {
-        squareMod_(mr_a,x);
-        if (equalsInt(mr_a,1)) {
-          return 0;
-        }
-        j++;
-      }
-      if (!equals(mr_a,mr_x1)) {
-        return 0;
-      }
-    }
-    return 1;  
-  }
-
-  //returns how many bits long the bigInt is, not counting leading zeros.
-  function bitSize(x) {
-    var j,z,w;
-    for (j=x.length-1; (x[j]==0) && (j>0); j--);
-    for (z=0,w=x[j]; w; (w>>=1),z++);
-    z+=bpe*j;
-    return z;
-  }
-
-  //return a copy of x with at least n elements, adding leading zeros if needed
-  function expand(x,n) {
-    var ans=int2bigInt(0,(x.length>n ? x.length : n)*bpe,0);
-    copy_(ans,x);
-    return ans;
-  }
-
-  //return a k-bit true random prime using Maurer's algorithm.
-  function randTruePrime(k) {
-    var ans=int2bigInt(0,k,0);
-    randTruePrime_(ans,k);
-    return trim(ans,1);
-  }
-
-  //return a k-bit random probable prime with probability of error < 2^-80
-  function randProbPrime(k) {
-    if (k>=600) return randProbPrimeRounds(k,2); //numbers from HAC table 4.3
-    if (k>=550) return randProbPrimeRounds(k,4);
-    if (k>=500) return randProbPrimeRounds(k,5);
-    if (k>=400) return randProbPrimeRounds(k,6);
-    if (k>=350) return randProbPrimeRounds(k,7);
-    if (k>=300) return randProbPrimeRounds(k,9);
-    if (k>=250) return randProbPrimeRounds(k,12); //numbers from HAC table 4.4
-    if (k>=200) return randProbPrimeRounds(k,15);
-    if (k>=150) return randProbPrimeRounds(k,18);
-    if (k>=100) return randProbPrimeRounds(k,27);
-                return randProbPrimeRounds(k,40); //number from HAC remark 4.26 (only an estimate)
-  }
-
-  //return a k-bit probable random prime using n rounds of Miller Rabin (after trial division with small primes)
-  function randProbPrimeRounds(k,n) {
-    var ans, i, divisible, B; 
-    B=30000;  //B is largest prime to use in trial division
-    ans=int2bigInt(0,k,0);
-    
-    //optimization: try larger and smaller B to find the best limit.
-    
-    if (primes.length==0)
-      primes=findPrimes(30000);  //check for divisibility by primes <=30000
-
-    if (rpprb.length!=ans.length)
-      rpprb=dup(ans);
-
-    for (;;) { //keep trying random values for ans until one appears to be prime
-      //optimization: pick a random number times L=2*3*5*...*p, plus a 
-      //   random element of the list of all numbers in [0,L) not divisible by any prime up to p.
-      //   This can reduce the amount of random number generation.
-      
-      randBigInt_(ans,k,0); //ans = a random odd number to check
-      ans[0] |= 1; 
-      divisible=0;
-    
-      //check ans for divisibility by small primes up to B
-      for (i=0; (i<primes.length) && (primes[i]<=B); i++)
-        if (modInt(ans,primes[i])==0 && !equalsInt(ans,primes[i])) {
-          divisible=1;
-          break;
-        }      
-      
-      //optimization: change millerRabin so the base can be bigger than the number being checked, then eliminate the while here.
-      
-      //do n rounds of Miller Rabin, with random bases less than ans
-      for (i=0; i<n && !divisible; i++) {
-        randBigInt_(rpprb,k,0);
-        while(!greater(ans,rpprb)) //pick a random rpprb that's < ans
-          randBigInt_(rpprb,k,0);
-        if (!millerRabin(ans,rpprb))
-          divisible=1;
-      }
-      
-      if(!divisible)
-        return ans;
-    }  
-  }
-
-  //return a new bigInt equal to (x mod n) for bigInts x and n.
-  function mod(x,n) {
-    var ans=dup(x);
-    mod_(ans,n);
-    return trim(ans,1);
-  }
-
-  //return (x+n) where x is a bigInt and n is an integer.
-  function addInt(x,n) {
-    var ans=expand(x,x.length+1);
-    addInt_(ans,n);
-    return trim(ans,1);
-  }
-
-  //return x*y for bigInts x and y. This is faster when y<x.
-  function mult(x,y) {
-    var ans=expand(x,x.length+y.length);
-    mult_(ans,y);
-    return trim(ans,1);
-  }
-
-  //return (x**y mod n) where x,y,n are bigInts and ** is exponentiation.  0**0=1. Faster for odd n.
-  function powMod(x,y,n) {
-    var ans=expand(x,n.length);  
-    powMod_(ans,trim(y,2),trim(n,2),0);  //this should work without the trim, but doesn't
-    return trim(ans,1);
-  }
-
-  //return (x-y) for bigInts x and y.  Negative answers will be 2s complement
-  function sub(x,y) {
-    var ans=expand(x,(x.length>y.length ? x.length+1 : y.length+1)); 
-    sub_(ans,y);
-    return trim(ans,1);
-  }
-
-  //return (x+y) for bigInts x and y.  
-  function add(x,y) {
-    var ans=expand(x,(x.length>y.length ? x.length+1 : y.length+1)); 
-    add_(ans,y);
-    return trim(ans,1);
-  }
-
-  //return (x**(-1) mod n) for bigInts x and n.  If no inverse exists, it returns null
-  function inverseMod(x,n) {
-    var ans=expand(x,n.length); 
-    var s;
-    s=inverseMod_(ans,n);
-    return s ? trim(ans,1) : null;
-  }
-
-  //return (x*y mod n) for bigInts x,y,n.  For greater speed, let y<x.
-  function multMod(x,y,n) {
-    var ans=expand(x,n.length);
-    multMod_(ans,y,n);
-    return trim(ans,1);
-  }
-
-  //generate a k-bit true random prime using Maurer's algorithm,
-  //and put it into ans.  The bigInt ans must be large enough to hold it.
-  function randTruePrime_(ans,k) {
-    var c,w,m,pm,dd,j,r,B,divisible,z,zz,recSize,recLimit;
-
-    if (primes.length==0)
-      primes=findPrimes(30000);  //check for divisibility by primes <=30000
-
-    if (pows.length==0) {
-      pows=new Array(512);
-      for (j=0;j<512;j++) {
-        pows[j]=Math.pow(2,j/511.0-1.0);
-      }
-    }
-
-    //c and m should be tuned for a particular machine and value of k, to maximize speed
-    c=0.1;  //c=0.1 in HAC
-    m=20;   //generate this k-bit number by first recursively generating a number that has between k/2 and k-m bits
-    recLimit=20; //stop recursion when k <=recLimit.  Must have recLimit >= 2
-
-    if (s_i2.length!=ans.length) {
-      s_i2=dup(ans);
-      s_R =dup(ans);
-      s_n1=dup(ans);
-      s_r2=dup(ans);
-      s_d =dup(ans);
-      s_x1=dup(ans);
-      s_x2=dup(ans);
-      s_b =dup(ans);
-      s_n =dup(ans);
-      s_i =dup(ans);
-      s_rm=dup(ans);
-      s_q =dup(ans);
-      s_a =dup(ans);
-      s_aa=dup(ans);
-    }
-
-    if (k <= recLimit) {  //generate small random primes by trial division up to its square root
-      pm=(1<<((k+2)>>1))-1; //pm is binary number with all ones, just over sqrt(2^k)
-      copyInt_(ans,0);
-      for (dd=1;dd;) {
-        dd=0;
-        ans[0]= 1 | (1<<(k-1)) | randomBitInt(k);  //random, k-bit, odd integer, with msb 1
-        for (j=1;(j<primes.length) && ((primes[j]&pm)==primes[j]);j++) { //trial division by all primes 3...sqrt(2^k)
-          if (0==(ans[0]%primes[j])) {
-            dd=1;
-            break;
-          }
-        }
-      }
-      carry_(ans);
-      return;
-    }
-
-    B=c*k*k;    //try small primes up to B (or all the primes[] array if the largest is less than B).
-    if (k>2*m)  //generate this k-bit number by first recursively generating a number that has between k/2 and k-m bits
-      for (r=1; k-k*r<=m; )
-        r=pows[randomBitInt(9)];   //r=Math.pow(2,Math.random()-1);
-    else
-      r=0.5;
-
-    //simulation suggests the more complex algorithm using r=.333 is only slightly faster.
-
-    recSize=Math.floor(r*k)+1;
-
-    randTruePrime_(s_q,recSize);
-    copyInt_(s_i2,0);
-    s_i2[Math.floor((k-2)/bpe)] |= (1<<((k-2)%bpe));   //s_i2=2^(k-2)
-    divide_(s_i2,s_q,s_i,s_rm);                        //s_i=floor((2^(k-1))/(2q))
-
-    z=bitSize(s_i);
-
-    for (;;) {
-      for (;;) {  //generate z-bit numbers until one falls in the range [0,s_i-1]
-        randBigInt_(s_R,z,0);
-        if (greater(s_i,s_R))
-          break;
-      }                //now s_R is in the range [0,s_i-1]
-      addInt_(s_R,1);  //now s_R is in the range [1,s_i]
-      add_(s_R,s_i);   //now s_R is in the range [s_i+1,2*s_i]
-
-      copy_(s_n,s_q);
-      mult_(s_n,s_R); 
-      multInt_(s_n,2);
-      addInt_(s_n,1);    //s_n=2*s_R*s_q+1
-      
-      copy_(s_r2,s_R);
-      multInt_(s_r2,2);  //s_r2=2*s_R
-
-      //check s_n for divisibility by small primes up to B
-      for (divisible=0,j=0; (j<primes.length) && (primes[j]<B); j++)
-        if (modInt(s_n,primes[j])==0 && !equalsInt(s_n,primes[j])) {
-          divisible=1;
-          break;
-        }      
-
-      if (!divisible)    //if it passes small primes check, then try a single Miller-Rabin base 2
-        if (!millerRabinInt(s_n,2)) //this line represents 75% of the total runtime for randTruePrime_ 
-          divisible=1;
-
-      if (!divisible) {  //if it passes that test, continue checking s_n
-        addInt_(s_n,-3);
-        for (j=s_n.length-1;(s_n[j]==0) && (j>0); j--);  //strip leading zeros
-        for (zz=0,w=s_n[j]; w; (w>>=1),zz++);
-        zz+=bpe*j;                             //zz=number of bits in s_n, ignoring leading zeros
-        for (;;) {  //generate z-bit numbers until one falls in the range [0,s_n-1]
-          randBigInt_(s_a,zz,0);
-          if (greater(s_n,s_a))
-            break;
-        }                //now s_a is in the range [0,s_n-1]
-        addInt_(s_n,3);  //now s_a is in the range [0,s_n-4]
-        addInt_(s_a,2);  //now s_a is in the range [2,s_n-2]
-        copy_(s_b,s_a);
-        copy_(s_n1,s_n);
-        addInt_(s_n1,-1);
-        powMod_(s_b,s_n1,s_n);   //s_b=s_a^(s_n-1) modulo s_n
-        addInt_(s_b,-1);
-        if (isZero(s_b)) {
-          copy_(s_b,s_a);
-          powMod_(s_b,s_r2,s_n);
-          addInt_(s_b,-1);
-          copy_(s_aa,s_n);
-          copy_(s_d,s_b);
-          GCD_(s_d,s_n);  //if s_b and s_n are relatively prime, then s_n is a prime
-          if (equalsInt(s_d,1)) {
-            copy_(ans,s_aa);
-            return;     //if we've made it this far, then s_n is absolutely guaranteed to be prime
-          }
-        }
-      }
-    }
-  }
-
-  //Return an n-bit random BigInt (n>=1).  If s=1, then the most significant of those n bits is set to 1.
-  function randBigInt(n,s) {
-    var a,b;
-    a=Math.floor((n-1)/bpe)+2; //# array elements to hold the BigInt with a leading 0 element
-    b=int2bigInt(0,0,a);
-    randBigInt_(b,n,s);
-    return b;
-  }
-
-  //Set b to an n-bit random BigInt.  If s=1, then the most significant of those n bits is set to 1.
-  //Array b must be big enough to hold the result. Must have n>=1
-  function randBigInt_(b,n,s) {
-    var i,a;
-    for (i=0;i<b.length;i++)
-      b[i]=0;
-    a=Math.floor((n-1)/bpe)+1; //# array elements to hold the BigInt
-    for (i=0;i<a;i++) {
-      b[i]=randomBitInt(bpe);
-    }
-    b[a-1] &= (2<<((n-1)%bpe))-1;
-    if (s==1)
-      b[a-1] |= (1<<((n-1)%bpe));
-  }
-
-  //Return the greatest common divisor of bigInts x and y (each with same number of elements).
-  function GCD(x,y) {
-    var xc,yc;
-    xc=dup(x);
-    yc=dup(y);
-    GCD_(xc,yc);
-    return xc;
-  }
-
-  //set x to the greatest common divisor of bigInts x and y (each with same number of elements).
-  //y is destroyed.
-  function GCD_(x,y) {
-    var i,xp,yp,A,B,C,D,q,sing,qp;
-    if (T.length!=x.length)
-      T=dup(x);
-
-    sing=1;
-    while (sing) { //while y has nonzero elements other than y[0]
-      sing=0;
-      for (i=1;i<y.length;i++) //check if y has nonzero elements other than 0
-        if (y[i]) {
-          sing=1;
-          break;
-        }
-      if (!sing) break; //quit when y all zero elements except possibly y[0]
-
-      for (i=x.length;!x[i] && i>=0;i--);  //find most significant element of x
-      xp=x[i];
-      yp=y[i];
-      A=1; B=0; C=0; D=1;
-      while ((yp+C) && (yp+D)) {
-        q =Math.floor((xp+A)/(yp+C));
-        qp=Math.floor((xp+B)/(yp+D));
-        if (q!=qp)
-          break;
-        t= A-q*C;   A=C;   C=t;    //  do (A,B,xp, C,D,yp) = (C,D,yp, A,B,xp) - q*(0,0,0, C,D,yp)      
-        t= B-q*D;   B=D;   D=t;
-        t=xp-q*yp; xp=yp; yp=t;
-      }
-      if (B) {
-        copy_(T,x);
-        linComb_(x,y,A,B); //x=A*x+B*y
-        linComb_(y,T,D,C); //y=D*y+C*T
-      } else {
-        mod_(x,y);
-        copy_(T,x);
-        copy_(x,y);
-        copy_(y,T);
-      } 
-    }
-    if (y[0]==0)
-      return;
-    t=modInt(x,y[0]);
-    copyInt_(x,y[0]);
-    y[0]=t;
-    while (y[0]) {
-      x[0]%=y[0];
-      t=x[0]; x[0]=y[0]; y[0]=t;
-    }
-  }
-
-  //do x=x**(-1) mod n, for bigInts x and n.
-  //If no inverse exists, it sets x to zero and returns 0, else it returns 1.
-  //The x array must be at least as large as the n array.
-  function inverseMod_(x,n) {
-    var k=1+2*Math.max(x.length,n.length);
-
-    if(!(x[0]&1)  && !(n[0]&1)) {  //if both inputs are even, then inverse doesn't exist
-      copyInt_(x,0);
-      return 0;
-    }
-
-    if (eg_u.length!=k) {
-      eg_u=new Array(k);
-      eg_v=new Array(k);
-      eg_A=new Array(k);
-      eg_B=new Array(k);
-      eg_C=new Array(k);
-      eg_D=new Array(k);
-    }
-
-    copy_(eg_u,x);
-    copy_(eg_v,n);
-    copyInt_(eg_A,1);
-    copyInt_(eg_B,0);
-    copyInt_(eg_C,0);
-    copyInt_(eg_D,1);
-    for (;;) {
-      while(!(eg_u[0]&1)) {  //while eg_u is even
-        halve_(eg_u);
-        if (!(eg_A[0]&1) && !(eg_B[0]&1)) { //if eg_A==eg_B==0 mod 2
-          halve_(eg_A);
-          halve_(eg_B);      
-        } else {
-          add_(eg_A,n);  halve_(eg_A);
-          sub_(eg_B,x);  halve_(eg_B);
-        }
-      }
-
-      while (!(eg_v[0]&1)) {  //while eg_v is even
-        halve_(eg_v);
-        if (!(eg_C[0]&1) && !(eg_D[0]&1)) { //if eg_C==eg_D==0 mod 2
-          halve_(eg_C);
-          halve_(eg_D);      
-        } else {
-          add_(eg_C,n);  halve_(eg_C);
-          sub_(eg_D,x);  halve_(eg_D);
-        }
-      }
-
-      if (!greater(eg_v,eg_u)) { //eg_v <= eg_u
-        sub_(eg_u,eg_v);
-        sub_(eg_A,eg_C);
-        sub_(eg_B,eg_D);
-      } else {                   //eg_v > eg_u
-        sub_(eg_v,eg_u);
-        sub_(eg_C,eg_A);
-        sub_(eg_D,eg_B);
-      }
-
-      if (equalsInt(eg_u,0)) {
-        while (negative(eg_C)) //make sure answer is nonnegative
-          add_(eg_C,n);
-        copy_(x,eg_C);
-
-        if (!equalsInt(eg_v,1)) { //if GCD_(x,n)!=1, then there is no inverse
-          copyInt_(x,0);
-          return 0;
-        }
-        return 1;
-      }
-    }
-  }
-
-  //return x**(-1) mod n, for integers x and n.  Return 0 if there is no inverse
-  function inverseModInt(x,n) {
-    var a=1,b=0,t;
-    for (;;) {
-      if (x==1) return a;
-      if (x==0) return 0;
-      b-=a*Math.floor(n/x);
-      n%=x;
-
-      if (n==1) return b; //to avoid negatives, change this b to n-b, and each -= to +=
-      if (n==0) return 0;
-      a-=b*Math.floor(x/n);
-      x%=n;
-    }
-  }
-
-  //this deprecated function is for backward compatibility only. 
-  function inverseModInt_(x,n) {
-     return inverseModInt(x,n);
-  }
-
-
-  //Given positive bigInts x and y, change the bigints v, a, and b to positive bigInts such that:
-  //     v = GCD_(x,y) = a*x-b*y
-  //The bigInts v, a, b, must have exactly as many elements as the larger of x and y.
-  function eGCD_(x,y,v,a,b) {
-    var g=0;
-    var k=Math.max(x.length,y.length);
-    if (eg_u.length!=k) {
-      eg_u=new Array(k);
-      eg_A=new Array(k);
-      eg_B=new Array(k);
-      eg_C=new Array(k);
-      eg_D=new Array(k);
-    }
-    while(!(x[0]&1)  && !(y[0]&1)) {  //while x and y both even
-      halve_(x);
-      halve_(y);
-      g++;
-    }
-    copy_(eg_u,x);
-    copy_(v,y);
-    copyInt_(eg_A,1);
-    copyInt_(eg_B,0);
-    copyInt_(eg_C,0);
-    copyInt_(eg_D,1);
-    for (;;) {
-      while(!(eg_u[0]&1)) {  //while u is even
-        halve_(eg_u);
-        if (!(eg_A[0]&1) && !(eg_B[0]&1)) { //if A==B==0 mod 2
-          halve_(eg_A);
-          halve_(eg_B);      
-        } else {
-          add_(eg_A,y);  halve_(eg_A);
-          sub_(eg_B,x);  halve_(eg_B);
-        }
-      }
-
-      while (!(v[0]&1)) {  //while v is even
-        halve_(v);
-        if (!(eg_C[0]&1) && !(eg_D[0]&1)) { //if C==D==0 mod 2
-          halve_(eg_C);
-          halve_(eg_D);      
-        } else {
-          add_(eg_C,y);  halve_(eg_C);
-          sub_(eg_D,x);  halve_(eg_D);
-        }
-      }
-
-      if (!greater(v,eg_u)) { //v<=u
-        sub_(eg_u,v);
-        sub_(eg_A,eg_C);
-        sub_(eg_B,eg_D);
-      } else {                //v>u
-        sub_(v,eg_u);
-        sub_(eg_C,eg_A);
-        sub_(eg_D,eg_B);
-      }
-      if (equalsInt(eg_u,0)) {
-        while (negative(eg_C)) {   //make sure a (C) is nonnegative
-          add_(eg_C,y);
-          sub_(eg_D,x);
-        }
-        multInt_(eg_D,-1);  ///make sure b (D) is nonnegative
-        copy_(a,eg_C);
-        copy_(b,eg_D);
-        leftShift_(v,g);
-        return;
-      }
-    }
-  }
-
-
-  //is bigInt x negative?
-  function negative(x) {
-    return ((x[x.length-1]>>(bpe-1))&1);
-  }
-
-
-  //is (x << (shift*bpe)) > y?
-  //x and y are nonnegative bigInts
-  //shift is a nonnegative integer
-  function greaterShift(x,y,shift) {
-    var i, kx=x.length, ky=y.length;
-    var k=((kx+shift)<ky) ? (kx+shift) : ky;
-    for (i=ky-1-shift; i<kx && i>=0; i++) 
-      if (x[i]>0)
-        return 1; //if there are nonzeros in x to the left of the first column of y, then x is bigger
-    for (i=kx-1+shift; i<ky; i++)
-      if (y[i]>0)
-        return 0; //if there are nonzeros in y to the left of the first column of x, then x is not bigger
-    for (i=k-1; i>=shift; i--)
-      if      (x[i-shift]>y[i]) return 1;
-      else if (x[i-shift]<y[i]) return 0;
-    return 0;
-  }
-
-  //is x > y? (x and y both nonnegative)
-  function greater(x,y) {
-    var i;
-    var k=(x.length<y.length) ? x.length : y.length;
-
-    for (i=x.length;i<y.length;i++)
-      if (y[i])
-        return 0;  //y has more digits
-
-    for (i=y.length;i<x.length;i++)
-      if (x[i])
-        return 1;  //x has more digits
-
-    for (i=k-1;i>=0;i--)
-      if (x[i]>y[i])
-        return 1;
-      else if (x[i]<y[i])
-        return 0;
-    return 0;
-  }
-
-  //divide x by y giving quotient q and remainder r.  (q=floor(x/y),  r=x mod y).  All 4 are bigints.
-  //x must have at least one leading zero element.
-  //y must be nonzero.
-  //q and r must be arrays that are exactly the same length as x. (Or q can have more).
-  //Must have x.length >= y.length >= 2.
-  function divide_(x,y,q,r) {
-    var kx, ky;
-    var i,j,y1,y2,c,a,b;
-    copy_(r,x);
-    for (ky=y.length;y[ky-1]==0;ky--); //ky is number of elements in y, not including leading zeros
-
-    //normalize: ensure the most significant element of y has its highest bit set  
-    b=y[ky-1];
-    for (a=0; b; a++)
-      b>>=1;  
-    a=bpe-a;  //a is how many bits to shift so that the high order bit of y is leftmost in its array element
-    leftShift_(y,a);  //multiply both by 1<<a now, then divide both by that at the end
-    leftShift_(r,a);
-
-    //Rob Visser discovered a bug: the following line was originally just before the normalization.
-    for (kx=r.length;r[kx-1]==0 && kx>ky;kx--); //kx is number of elements in normalized x, not including leading zeros
-
-    copyInt_(q,0);                      // q=0
-    while (!greaterShift(y,r,kx-ky)) {  // while (leftShift_(y,kx-ky) <= r) {
-      subShift_(r,y,kx-ky);             //   r=r-leftShift_(y,kx-ky)
-      q[kx-ky]++;                       //   q[kx-ky]++;
-    }                                   // }
-
-    for (i=kx-1; i>=ky; i--) {
-      if (r[i]==y[ky-1])
-        q[i-ky]=mask;
-      else
-        q[i-ky]=Math.floor((r[i]*radix+r[i-1])/y[ky-1]);
-
-      //The following for(;;) loop is equivalent to the commented while loop, 
-      //except that the uncommented version avoids overflow.
-      //The commented loop comes from HAC, which assumes r[-1]==y[-1]==0
-      //  while (q[i-ky]*(y[ky-1]*radix+y[ky-2]) > r[i]*radix*radix+r[i-1]*radix+r[i-2])
-      //    q[i-ky]--;    
-      for (;;) {
-        y2=(ky>1 ? y[ky-2] : 0)*q[i-ky];
-        c=y2;
-        y2=y2 & mask;
-        c = (c - y2) / radix;
-        y1=c+q[i-ky]*y[ky-1];
-        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]--;
-        else
-          break;
-      }
-
-      linCombShift_(r,y,-q[i-ky],i-ky);    //r=r-q[i-ky]*leftShift_(y,i-ky)
-      if (negative(r)) {
-        addShift_(r,y,i-ky);         //r=r+leftShift_(y,i-ky)
-        q[i-ky]--;
-      }
-    }
-
-    rightShift_(y,a);  //undo the normalization step
-    rightShift_(r,a);  //undo the normalization step
-  }
-
-  //do carries and borrows so each element of the bigInt x fits in bpe bits.
-  function carry_(x) {
-    var i,k,c,b;
-    k=x.length;
-    c=0;
-    for (i=0;i<k;i++) {
-      c+=x[i];
-      b=0;
-      if (c<0) {
-        b = c & mask;
-        b = -((c - b) / radix);
-        c+=b*radix;
-      }
-      x[i]=c & mask;
-      c = ((c - x[i]) / radix) - b;
-    }
-  }
-
-  //return x mod n for bigInt x and integer n.
-  function modInt(x,n) {
-    var i,c=0;
-    for (i=x.length-1; i>=0; i--)
-      c=(c*radix+x[i])%n;
-    return c;
-  }
-
-  //convert the integer t into a bigInt with at least the given number of bits.
-  //the returned array stores the bigInt in bpe-bit chunks, little endian (buff[0] is least significant word)
-  //Pad the array with leading zeros so that it has at least minSize elements.
-  //There will always be at least one leading 0 element.
-  function int2bigInt(t,bits,minSize) {   
-    var i,k, buff;
-    k=Math.ceil(bits/bpe)+1;
-    k=minSize>k ? minSize : k;
-    buff=new Array(k);
-    copyInt_(buff,t);
-    return buff;
-  }
-
-  //return the bigInt given a string representation in a given base.  
-  //Pad the array with leading zeros so that it has at least minSize elements.
-  //If base=-1, then it reads in a space-separated list of array elements in decimal.
-  //The array will always have at least one leading zero, unless base=-1.
-  function str2bigInt(s,base,minSize) {
-    var d, i, j, x, y, kk;
-    var k=s.length;
-    if (base==-1) { //comma-separated list of array elements in decimal
-      x=new Array(0);
-      for (;;) {
-        y=new Array(x.length+1);
-        for (i=0;i<x.length;i++)
-          y[i+1]=x[i];
-        y[0]=parseInt(s,10);
-        x=y;
-        d=s.indexOf(',',0);
-        if (d<1) 
-          break;
-        s=s.substring(d+1);
-        if (s.length==0)
-          break;
-      }
-      if (x.length<minSize) {
-        y=new Array(minSize);
-        copy_(y,x);
-        return y;
-      }
-      return x;
-    }
-
-    // log2(base)*k
-    var bb = base, p = 0;
-    var b = base == 1 ? k : 0;
-    while (bb > 1) {
-      if (bb & 1) p = 1;
-      b += k;
-      bb >>= 1;
-    }
-    b += p*k;
-
-    x=int2bigInt(0,b,0);
-    for (i=0;i<k;i++) {
-      d=digitsStr.indexOf(s.substring(i,i+1),0);
-      if (base<=36 && d>=36)  //convert lowercase to uppercase if base<=36
-        d-=26;
-      if (d>=base || d<0) {   //stop at first illegal character
-        break;
-      }
-      multInt_(x,base);
-      addInt_(x,d);
-    }
-
-    for (k=x.length;k>0 && !x[k-1];k--); //strip off leading zeros
-    k=minSize>k+1 ? minSize : k+1;
-    y=new Array(k);
-    kk=k<x.length ? k : x.length;
-    for (i=0;i<kk;i++)
-      y[i]=x[i];
-    for (;i<k;i++)
-      y[i]=0;
-    return y;
-  }
-
-  //is bigint x equal to integer y?
-  //y must have less than bpe bits
-  function equalsInt(x,y) {
-    var i;
-    if (x[0]!=y)
-      return 0;
-    for (i=1;i<x.length;i++)
-      if (x[i])
-        return 0;
-    return 1;
-  }
-
-  //are bigints x and y equal?
-  //this works even if x and y are different lengths and have arbitrarily many leading zeros
-  function equals(x,y) {
-    var i;
-    var k=x.length<y.length ? x.length : y.length;
-    for (i=0;i<k;i++)
-      if (x[i]!=y[i])
-        return 0;
-    if (x.length>y.length) {
-      for (;i<x.length;i++)
-        if (x[i])
-          return 0;
-    } else {
-      for (;i<y.length;i++)
-        if (y[i])
-          return 0;
-    }
-    return 1;
-  }
-
-  //is the bigInt x equal to zero?
-  function isZero(x) {
-    var i;
-    for (i=0;i<x.length;i++)
-      if (x[i])
-        return 0;
-    return 1;
-  }
-
-  //convert a bigInt into a string in a given base, from base 2 up to base 95.
-  //Base -1 prints the contents of the array representing the number.
-  function bigInt2str(x,base) {
-    var i,t,s="";
-
-    if (s6.length!=x.length) 
-      s6=dup(x);
-    else
-      copy_(s6,x);
-
-    if (base==-1) { //return the list of array contents
-      for (i=x.length-1;i>0;i--)
-        s+=x[i]+',';
-      s+=x[0];
-    }
-    else { //return it in the given base
-      while (!isZero(s6)) {
-        t=divInt_(s6,base);  //t=s6 % base; s6=floor(s6/base);
-        s=digitsStr.substring(t,t+1)+s;
-      }
-    }
-    if (s.length==0)
-      s="0";
-    return s;
-  }
-
-  //returns a duplicate of bigInt x
-  function dup(x) {
-    var i, buff;
-    buff=new Array(x.length);
-    copy_(buff,x);
-    return buff;
-  }
-
-  //do x=y on bigInts x and y.  x must be an array at least as big as y (not counting the leading zeros in y).
-  function copy_(x,y) {
-    var i;
-    var k=x.length<y.length ? x.length : y.length;
-    for (i=0;i<k;i++)
-      x[i]=y[i];
-    for (i=k;i<x.length;i++)
-      x[i]=0;
-  }
-
-  //do x=y on bigInt x and integer y.  
-  function copyInt_(x,n) {
-    var i,c;
-    for (c=n,i=0;i<x.length;i++) {
-      x[i]=c & mask;
-      c>>=bpe;
-    }
-  }
-
-  //do x=x+n where x is a bigInt and n is an integer.
-  //x must be large enough to hold the result.
-  function addInt_(x,n) {
-    var i,k,c,b;
-    x[0]+=n;
-    k=x.length;
-    c=0;
-    for (i=0;i<k;i++) {
-      c+=x[i];
-      b=0;
-      if (c<0) {
-        b = c & mask;
-        b = -((c - b) / radix);
-        c+=b*radix;
-      }
-      x[i]=c & mask;
-      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.
-  function rightShift_(x,n) {
-    var i;
-    var k=Math.floor(n/bpe);
-    if (k) {
-      for (i=0;i<x.length-k;i++) //right shift x by k elements
-        x[i]=x[i+k];
-      for (;i<x.length;i++)
-        x[i]=0;
-      n%=bpe;
-    }
-    for (i=0;i<x.length-1;i++) {
-      x[i]=mask & ((x[i+1]<<(bpe-n)) | (x[i]>>n));
-    }
-    x[i]>>=n;
-  }
-
-  //do x=floor(|x|/2)*sgn(x) for bigInt x in 2's complement
-  function halve_(x) {
-    var i;
-    for (i=0;i<x.length-1;i++) {
-      x[i]=mask & ((x[i+1]<<(bpe-1)) | (x[i]>>1));
-    }
-    x[i]=(x[i]>>1) | (x[i] & (radix>>1));  //most significant bit stays the same
-  }
-
-  //left shift bigInt x by n bits.
-  function leftShift_(x,n) {
-    var i;
-    var k=Math.floor(n/bpe);
-    if (k) {
-      for (i=x.length; i>=k; i--) //left shift x by k elements
-        x[i]=x[i-k];
-      for (;i>=0;i--)
-        x[i]=0;  
-      n%=bpe;
-    }
-    if (!n)
-      return;
-    for (i=x.length-1;i>0;i--) {
-      x[i]=mask & ((x[i]<<n) | (x[i-1]>>(bpe-n)));
-    }
-    x[i]=mask & (x[i]<<n);
-  }
-
-  //do x=x*n where x is a bigInt and n is an integer.
-  //x must be large enough to hold the result.
-  function multInt_(x,n) {
-    var i,k,c,b;
-    if (!n)
-      return;
-    k=x.length;
-    c=0;
-    for (i=0;i<k;i++) {
-      c+=x[i]*n;
-      b=0;
-      if (c<0) {
-        b = c & mask;
-        b = -((c - b) / radix);
-        c+=b*radix;
-      }
-      x[i]=c & mask;
-      c = ((c - x[i]) / radix) - b;
-    }
-  }
-
-  //do x=floor(x/n) for bigInt x and integer n, and return the remainder
-  function divInt_(x,n) {
-    var i,r=0,s;
-    for (i=x.length-1;i>=0;i--) {
-      s=r*radix+x[i];
-      x[i]=Math.floor(s/n);
-      r=s%n;
-    }
-    return r;
-  }
-
-  //do the linear combination x=a*x+b*y for bigInts x and y, and integers a and b.
-  //x must be large enough to hold the answer.
-  function linComb_(x,y,a,b) {
-    var i,c,k,kk;
-    k=x.length<y.length ? x.length : y.length;
-    kk=x.length;
-    for (c=0,i=0;i<k;i++) {
-      c+=a*x[i]+b*y[i];
-      x[i]=c & mask;
-      c = (c - x[i]) / radix;
-    }
-    for (i=k;i<kk;i++) {
-      c+=a*x[i];
-      x[i]=c & mask;
-      c = (c - x[i]) / radix;
-    }
-  }
-
-  //do the linear combination x=a*x+b*(y<<(ys*bpe)) for bigInts x and y, and integers a, b and ys.
-  //x must be large enough to hold the answer.
-  function linCombShift_(x,y,b,ys) {
-    var i,c,k,kk;
-    k=x.length<ys+y.length ? x.length : ys+y.length;
-    kk=x.length;
-    for (c=0,i=ys;i<k;i++) {
-      c+=x[i]+b*y[i-ys];
-      x[i]=c & mask;
-      c = (c - x[i]) / radix;
-    }
-    for (i=k;c && i<kk;i++) {
-      c+=x[i];
-      x[i]=c & mask;
-      c = (c - x[i]) / radix;
-    }
-  }
-
-  //do x=x+(y<<(ys*bpe)) for bigInts x and y, and integers a,b and ys.
-  //x must be large enough to hold the answer.
-  function addShift_(x,y,ys) {
-    var i,c,k,kk;
-    k=x.length<ys+y.length ? x.length : ys+y.length;
-    kk=x.length;
-    for (c=0,i=ys;i<k;i++) {
-      c+=x[i]+y[i-ys];
-      x[i]=c & mask;
-      c = (c - x[i]) / radix;
-    }
-    for (i=k;c && i<kk;i++) {
-      c+=x[i];
-      x[i]=c & mask;
-      c = (c - x[i]) / radix;
-    }
-  }
-
-  //do x=x-(y<<(ys*bpe)) for bigInts x and y, and integers a,b and ys.
-  //x must be large enough to hold the answer.
-  function subShift_(x,y,ys) {
-    var i,c,k,kk;
-    k=x.length<ys+y.length ? x.length : ys+y.length;
-    kk=x.length;
-    for (c=0,i=ys;i<k;i++) {
-      c+=x[i]-y[i-ys];
-      x[i]=c & mask;
-      c = (c - x[i]) / radix;
-    }
-    for (i=k;c && i<kk;i++) {
-      c+=x[i];
-      x[i]=c & mask;
-      c = (c - x[i]) / radix;
-    }
-  }
-
-  //do x=x-y for bigInts x and y.
-  //x must be large enough to hold the answer.
-  //negative answers will be 2s complement
-  function sub_(x,y) {
-    var i,c,k,kk;
-    k=x.length<y.length ? x.length : y.length;
-    for (c=0,i=0;i<k;i++) {
-      c+=x[i]-y[i];
-      x[i]=c & mask;
-      c = (c - x[i]) / radix;
-    }
-    for (i=k;c && i<x.length;i++) {
-      c+=x[i];
-      x[i]=c & mask;
-      c = (c - x[i]) / radix;
-    }
-  }
-
-  //do x=x+y for bigInts x and y.
-  //x must be large enough to hold the answer.
-  function add_(x,y) {
-    var i,c,k,kk;
-    k=x.length<y.length ? x.length : y.length;
-    for (c=0,i=0;i<k;i++) {
-      c+=x[i]+y[i];
-      x[i]=c & mask;
-      c = (c - x[i]) / radix;
-    }
-    for (i=k;c && i<x.length;i++) {
-      c+=x[i];
-      x[i]=c & mask;
-      c = (c - x[i]) / radix;
-    }
-  }
-
-  //do x=x*y for bigInts x and y.  This is faster when y<x.
-  function mult_(x,y) {
-    var i;
-    if (ss.length!=2*x.length)
-      ss=new Array(2*x.length);
-    copyInt_(ss,0);
-    for (i=0;i<y.length;i++)
-      if (y[i])
-        linCombShift_(ss,x,y[i],i);   //ss=1*ss+y[i]*(x<<(i*bpe))
-    copy_(x,ss);
-  }
-
-  //do x=x mod n for bigInts x and n.
-  function mod_(x,n) {
-    if (s4.length!=x.length)
-      s4=dup(x);
-    else
-      copy_(s4,x);
-    if (s5.length!=x.length)
-      s5=dup(x);  
-    divide_(s4,n,s5,x);  //x = remainder of s4 / n
-  }
-
-  //do x=x*y mod n for bigInts x,y,n.
-  //for greater speed, let y<x.
-  function multMod_(x,y,n) {
-    var i;
-    if (s0.length!=2*x.length)
-      s0=new Array(2*x.length);
-    copyInt_(s0,0);
-    for (i=0;i<y.length;i++)
-      if (y[i])
-        linCombShift_(s0,x,y[i],i);   //s0=1*s0+y[i]*(x<<(i*bpe))
-    mod_(s0,n);
-    copy_(x,s0);
-  }
-
-  //do x=x*x mod n for bigInts x,n.
-  function squareMod_(x,n) {
-    var i,j,d,c,kx,kn,k;
-    for (kx=x.length; kx>0 && !x[kx-1]; kx--);  //ignore leading zeros in x
-    k=kx>n.length ? 2*kx : 2*n.length; //k=# elements in the product, which is twice the elements in the larger of x and n
-    if (s0.length!=k) 
-      s0=new Array(k);
-    copyInt_(s0,0);
-    for (i=0;i<kx;i++) {
-      c=s0[2*i]+x[i]*x[i];
-      s0[2*i]=c & mask;
-      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 = (c - s0[i+j]) / radix;
-      }
-      s0[i+kx]=c;
-    }
-    mod_(s0,n);
-    copy_(x,s0);
-  }
-
-  //return x with exactly k leading zero elements
-  function trim(x,k) {
-    var i,y;
-    for (i=x.length; i>0 && !x[i-1]; i--);
-    y=new Array(i+k);
-    copy_(y,x);
-    return y;
-  }
-
-  //do x=x**y mod n, where x,y,n are bigInts and ** is exponentiation.  0**0=1.
-  //this is faster when n is odd.  x usually needs to have as many elements as n.
-  function powMod_(x,y,n) {
-    var k1,k2,kn,np;
-    if(s7.length!=n.length)
-      s7=dup(n);
-
-    //for even modulus, use a simple square-and-multiply algorithm,
-    //rather than using the more complex Montgomery algorithm.
-    if ((n[0]&1)==0) {
-      copy_(s7,x);
-      copyInt_(x,1);
-      while(!equalsInt(y,0)) {
-        if (y[0]&1)
-          multMod_(x,s7,n);
-        divInt_(y,2);
-        squareMod_(s7,n); 
-      }
-      return;
-    }
-
-    //calculate np from n for the Montgomery multiplications
-    copyInt_(s7,0);
-    for (kn=n.length;kn>0 && !n[kn-1];kn--);
-    np=radix-inverseModInt(modInt(n,radix),radix);
-    s7[kn]=1;
-    multMod_(x ,s7,n);   // x = x * 2**(kn*bp) mod n
-
-    if (s3.length!=x.length)
-      s3=dup(x);
-    else
-      copy_(s3,x);
-
-    for (k1=y.length-1;k1>0 & !y[k1]; k1--);  //k1=first nonzero element of y
-    if (y[k1]==0) {  //anything to the 0th power is 1
-      copyInt_(x,1);
-      return;
-    }
-    for (k2=1<<(bpe-1);k2 && !(y[k1] & k2); k2>>=1);  //k2=position of first 1 bit in y[k1]
-    for (;;) {
-      if (!(k2>>=1)) {  //look at next bit of y
-        k1--;
-        if (k1<0) {
-          mont_(x,one,n,np);
-          return;
-        }
-        k2=1<<(bpe-1);
-      }    
-      mont_(x,x,n,np);
-
-      if (k2 & y[k1]) //if next bit is a 1
-        mont_(x,s3,n,np);
-    }
-  }
-
-
-  //do x=x*y*Ri mod n for bigInts x,y,n, 
-  //  where Ri = 2**(-kn*bpe) mod n, and kn is the 
-  //  number of elements in the n array, not 
-  //  counting leading zeros.  
-  //x array must have at least as many elemnts as the n array
-  //It's OK if x and y are the same variable.
-  //must have:
-  //  x,y < n
-  //  n is odd
-  //  np = -(n^(-1)) mod radix
-  function mont_(x,y,n,np) {
-    var i,j,c,ui,t,t2,ks;
-    var kn=n.length;
-    var ky=y.length;
-
-    if (sa.length!=kn)
-      sa=new Array(kn);
-      
-    copyInt_(sa,0);
-
-    for (;kn>0 && n[kn-1]==0;kn--); //ignore leading zeros of n
-    for (;ky>0 && y[ky-1]==0;ky--); //ignore leading zeros of y
-    ks=sa.length-1; //sa will never have more than this many nonzero elements.  
-
-    //the following loop consumes 95% of the runtime for randTruePrime_() and powMod_() for large numbers
-    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]);
-      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]; 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;
-    }
-
-    if (!greater(n,sa))
-      sub_(sa,n);
-    copy_(x,sa);
-  }
-
-
-  // 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 {
-      console.log('Keys should not be generated without CSPRNG.');
-      return;
-      // 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
-  }
-
-  return {
-      str2bigInt    : str2bigInt
-    , bigInt2str    : bigInt2str
-    , int2bigInt    : int2bigInt
-    , multMod       : multMod
-    , powMod        : powMod
-    , inverseMod    : inverseMod
-    , randBigInt    : randBigInt
-    , randBigInt_   : randBigInt_
-    , equals        : equals
-    , equalsInt     : equalsInt
-    , sub           : sub
-    , mod           : mod
-    , modInt        : modInt
-    , mult          : mult
-    , divInt_       : divInt_
-    , rightShift_   : rightShift_
-    , dup           : dup
-    , greater       : greater
-    , add           : add
-    , isZero        : isZero
-    , bitSize       : bitSize
-    , millerRabin   : millerRabin
-    , divide_       : divide_
-    , trim          : trim
-    , primes        : primes
-    , findPrimes    : findPrimes
-    , getSeed       : getSeed
-    , divMod        : divMod
-    , subMod        : subMod
-    , twoToThe      : twoToThe
-    , bigInt2bits   : bigInt2bits
-    , ba2bigInt     : ba2bigInt
-  }
-
-}))

+ 0 - 22
3rdparty/crypto.js

@@ -1,22 +0,0 @@
-;(function (root, factory) {
-    if (typeof define === "function" && define.amd) {
-        define([
-            "crypto.core",
-            "crypto.enc-base64",
-            "crypto.md5",
-            "crypto.evpkdf",
-            "crypto.cipher-core",
-            "crypto.aes",
-            "crypto.sha1",
-            "crypto.sha256",
-            "crypto.hmac",
-            "crypto.pad-nopadding",
-            "crypto.mode-ctr"
-            ], function() {
-                return CryptoJS;
-            }
-        );
-    } else {
-        root.CryptoJS = factory();
-    }
-}(this));

+ 0 - 2606
3rdparty/otr.js

@@ -1,2606 +0,0 @@
-/*!
-
-  otr.js v0.2.12 - 2014-04-15
-  (c) 2014 - Arlo Breault <arlolra@gmail.com>
-  Freely distributed under the MPL v2.0 license.
-
-  This file is concatenated for the browser.
-  Please see: https://github.com/arlolra/otr
-
-*/
-
-;(function (root, factory) {
-
-  if (typeof define === 'function' && define.amd) {
-    define([
-        "jquery",
-        "jquery.browser",
-        "bigint",
-        "crypto",
-        "eventemitter"
-    ], function ($, dummy, BigInt, CryptoJS, EventEmitter) {
-      if ($.browser.msie) {
-          return undefined;
-      }
-      var root = {
-          BigInt: BigInt
-        , CryptoJS: CryptoJS
-        , EventEmitter: EventEmitter
-        , OTR: {}
-        , DSA: {}
-      }
-      return factory.call(root)
-    })
-  } else {
-    root.OTR = {}
-    root.DSA = {}
-    factory.call(root)
-  }
-
-}(this, function () {
-
-;(function () {
-  "use strict";
-
-  var root = this
-
-  var CONST = {
-
-    // diffie-heilman
-      N : 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF'
-    , G : '2'
-
-    // otr message states
-    , MSGSTATE_PLAINTEXT : 0
-    , MSGSTATE_ENCRYPTED : 1
-    , MSGSTATE_FINISHED  : 2
-
-    // otr auth states
-    , AUTHSTATE_NONE               : 0
-    , AUTHSTATE_AWAITING_DHKEY     : 1
-    , AUTHSTATE_AWAITING_REVEALSIG : 2
-    , AUTHSTATE_AWAITING_SIG       : 3
-
-    // whitespace tags
-    , WHITESPACE_TAG    : '\x20\x09\x20\x20\x09\x09\x09\x09\x20\x09\x20\x09\x20\x09\x20\x20'
-    , WHITESPACE_TAG_V2 : '\x20\x20\x09\x09\x20\x20\x09\x20'
-    , WHITESPACE_TAG_V3 : '\x20\x20\x09\x09\x20\x20\x09\x09'
-
-    // otr tags
-    , OTR_TAG       : '?OTR'
-    , OTR_VERSION_1 : '\x00\x01'
-    , OTR_VERSION_2 : '\x00\x02'
-    , OTR_VERSION_3 : '\x00\x03'
-
-    // smp machine states
-    , SMPSTATE_EXPECT0 : 0
-    , SMPSTATE_EXPECT1 : 1
-    , SMPSTATE_EXPECT2 : 2
-    , SMPSTATE_EXPECT3 : 3
-    , SMPSTATE_EXPECT4 : 4
-
-    // unstandard status codes
-    , STATUS_SEND_QUERY  : 0
-    , STATUS_AKE_INIT    : 1
-    , STATUS_AKE_SUCCESS : 2
-    , STATUS_END_OTR     : 3
-
-  }
-
-  if (typeof module !== 'undefined' && module.exports) {
-    module.exports = CONST
-  } else {
-    root.OTR.CONST = CONST
-  }
-
-}).call(this)
-;(function () {
-  "use strict";
-
-  var root = this
-
-  var HLP = {}, CryptoJS, BigInt
-  if (typeof module !== 'undefined' && module.exports) {
-    module.exports = HLP = {}
-    CryptoJS = require('../vendor/crypto.js')
-    BigInt = require('../vendor/bigint.js')
-  } else {
-    if (root.OTR) root.OTR.HLP = HLP
-    if (root.DSA) root.DSA.HLP = HLP
-    CryptoJS = root.CryptoJS
-    BigInt = root.BigInt
-  }
-
-  // data types (byte lengths)
-  var DTS = {
-      BYTE  : 1
-    , SHORT : 2
-    , INT   : 4
-    , CTR   : 8
-    , MAC   : 20
-    , SIG   : 40
-  }
-
-  // otr message wrapper begin and end
-  var WRAPPER_BEGIN = "?OTR"
-    , WRAPPER_END   = "."
-
-  var TWO = BigInt.str2bigInt('2', 10)
-
-  HLP.debug = function (msg) {
-    // used as HLP.debug.call(ctx, msg)
-    if ( this.debug &&
-         typeof this.debug !== 'function' &&
-         typeof console !== 'undefined'
-    ) console.log(msg)
-  }
-
-  HLP.extend = function (child, parent) {
-    for (var key in parent) {
-      if (Object.hasOwnProperty.call(parent, key))
-        child[key] = parent[key]
-    }
-    function Ctor() { this.constructor = child }
-    Ctor.prototype = parent.prototype
-    child.prototype = new Ctor()
-    child.__super__ = parent.prototype
-  }
-
-  // constant-time string comparison
-  HLP.compare = function (str1, str2) {
-    if (str1.length !== str2.length)
-      return false
-    var i = 0, result = 0
-    for (; i < str1.length; i++)
-      result |= str1[i].charCodeAt(0) ^ str2[i].charCodeAt(0)
-    return result === 0
-  }
-
-  HLP.randomExponent = function () {
-    return BigInt.randBigInt(1536)
-  }
-
-  HLP.smpHash = function (version, fmpi, smpi) {
-    var sha256 = CryptoJS.algo.SHA256.create()
-    sha256.update(CryptoJS.enc.Latin1.parse(HLP.packBytes(version, DTS.BYTE)))
-    sha256.update(CryptoJS.enc.Latin1.parse(HLP.packMPI(fmpi)))
-    if (smpi) sha256.update(CryptoJS.enc.Latin1.parse(HLP.packMPI(smpi)))
-    var hash = sha256.finalize()
-    return HLP.bits2bigInt(hash.toString(CryptoJS.enc.Latin1))
-  }
-
-  HLP.makeMac = function (aesctr, m) {
-    var pass = CryptoJS.enc.Latin1.parse(m)
-    var mac = CryptoJS.HmacSHA256(CryptoJS.enc.Latin1.parse(aesctr), pass)
-    return HLP.mask(mac.toString(CryptoJS.enc.Latin1), 0, 160)
-  }
-
-  HLP.make1Mac = function (aesctr, m) {
-    var pass = CryptoJS.enc.Latin1.parse(m)
-    var mac = CryptoJS.HmacSHA1(CryptoJS.enc.Latin1.parse(aesctr), pass)
-    return mac.toString(CryptoJS.enc.Latin1)
-  }
-
-  HLP.encryptAes = function (msg, c, iv) {
-    var opts = {
-        mode: CryptoJS.mode.CTR
-      , iv: CryptoJS.enc.Latin1.parse(iv)
-      , padding: CryptoJS.pad.NoPadding
-    }
-    var aesctr = CryptoJS.AES.encrypt(
-        msg
-      , CryptoJS.enc.Latin1.parse(c)
-      , opts
-    )
-    var aesctr_decoded = CryptoJS.enc.Base64.parse(aesctr.toString())
-    return CryptoJS.enc.Latin1.stringify(aesctr_decoded)
-  }
-
-  HLP.decryptAes = function (msg, c, iv) {
-    msg = CryptoJS.enc.Latin1.parse(msg)
-    var opts = {
-        mode: CryptoJS.mode.CTR
-      , iv: CryptoJS.enc.Latin1.parse(iv)
-      , padding: CryptoJS.pad.NoPadding
-    }
-    return CryptoJS.AES.decrypt(
-        CryptoJS.enc.Base64.stringify(msg)
-      , CryptoJS.enc.Latin1.parse(c)
-      , opts
-    )
-  }
-
-  HLP.multPowMod = function (a, b, c, d, e) {
-    return BigInt.multMod(BigInt.powMod(a, b, e), BigInt.powMod(c, d, e), e)
-  }
-
-  HLP.ZKP = function (v, c, d, e) {
-    return BigInt.equals(c, HLP.smpHash(v, d, e))
-  }
-
-  // greater than, or equal
-  HLP.GTOE = function (a, b) {
-    return (BigInt.equals(a, b) || BigInt.greater(a, b))
-  }
-
-  HLP.between = function (x, a, b) {
-    return (BigInt.greater(x, a) && BigInt.greater(b, x))
-  }
-
-  HLP.checkGroup = function (g, N_MINUS_2) {
-    return HLP.GTOE(g, TWO) && HLP.GTOE(N_MINUS_2, g)
-  }
-
-  HLP.h1 = function (b, secbytes) {
-    var sha1 = CryptoJS.algo.SHA1.create()
-    sha1.update(CryptoJS.enc.Latin1.parse(b))
-    sha1.update(CryptoJS.enc.Latin1.parse(secbytes))
-    return (sha1.finalize()).toString(CryptoJS.enc.Latin1)
-  }
-
-  HLP.h2 = function (b, secbytes) {
-    var sha256 = CryptoJS.algo.SHA256.create()
-    sha256.update(CryptoJS.enc.Latin1.parse(b))
-    sha256.update(CryptoJS.enc.Latin1.parse(secbytes))
-    return (sha256.finalize()).toString(CryptoJS.enc.Latin1)
-  }
-
-  HLP.mask = function (bytes, start, n) {
-    return bytes.substr(start / 8, n / 8)
-  }
-
-  var _toString = String.fromCharCode;
-  HLP.packBytes = function (val, bytes) {
-    val = val.toString(16)
-    var nex, res = ''  // big-endian, unsigned long
-    for (; bytes > 0; bytes--) {
-      nex = val.length ? val.substr(-2, 2) : '0'
-      val = val.substr(0, val.length - 2)
-      res = _toString(parseInt(nex, 16)) + res
-    }
-    return res
-  }
-
-  HLP.packINT = function (d) {
-    return HLP.packBytes(d, DTS.INT)
-  }
-
-  HLP.packCtr = function (d) {
-    return HLP.padCtr(HLP.packBytes(d, DTS.CTR))
-  }
-
-  HLP.padCtr = function (ctr) {
-    return ctr + '\x00\x00\x00\x00\x00\x00\x00\x00'
-  }
-
-  HLP.unpackCtr = function (d) {
-    d = HLP.toByteArray(d.substring(0, 8))
-    return HLP.unpack(d)
-  }
-
-  HLP.unpack = function (arr) {
-    var val = 0, i = 0, len = arr.length
-    for (; i < len; i++) {
-      val = (val * 256) + arr[i]
-    }
-    return val
-  }
-
-  HLP.packData = function (d) {
-    return HLP.packINT(d.length) + d
-  }
-
-  HLP.bits2bigInt = function (bits) {
-    bits = HLP.toByteArray(bits)
-    return BigInt.ba2bigInt(bits)
-  }
-
-  HLP.packMPI = function (mpi) {
-    return HLP.packData(BigInt.bigInt2bits(BigInt.trim(mpi, 0)))
-  }
-
-  HLP.packSHORT = function (short) {
-    return HLP.packBytes(short, DTS.SHORT)
-  }
-
-  HLP.unpackSHORT = function (short) {
-    short = HLP.toByteArray(short)
-    return HLP.unpack(short)
-  }
-
-  HLP.packTLV = function (type, value) {
-    return HLP.packSHORT(type) + HLP.packSHORT(value.length) + value
-  }
-
-  HLP.readLen = function (msg) {
-    msg = HLP.toByteArray(msg.substring(0, 4))
-    return HLP.unpack(msg)
-  }
-
-  HLP.readData = function (data) {
-    var n = HLP.unpack(data.splice(0, 4))
-    return [n, data]
-  }
-
-  HLP.readMPI = function (data) {
-    data = HLP.toByteArray(data)
-    data = HLP.readData(data)
-    return BigInt.ba2bigInt(data[1])
-  }
-
-  HLP.packMPIs = function (arr) {
-    return arr.reduce(function (prv, cur) {
-      return prv + HLP.packMPI(cur)
-    }, '')
-  }
-
-  HLP.unpackMPIs = function (num, mpis) {
-    var i = 0, arr = []
-    for (; i < num; i++) arr.push('MPI')
-    return (HLP.splitype(arr, mpis)).map(function (m) {
-      return HLP.readMPI(m)
-    })
-  }
-
-  HLP.wrapMsg = function (msg, fs, v3, our_it, their_it) {
-    msg = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Latin1.parse(msg))
-    msg = WRAPPER_BEGIN + ":" + msg + WRAPPER_END
-
-    var its
-    if (v3) {
-      its = '|'
-      its += (HLP.readLen(our_it)).toString(16)
-      its += '|'
-      its += (HLP.readLen(their_it)).toString(16)
-    }
-
-    if (!fs) return [null, msg]
-
-    var n = Math.ceil(msg.length / fs)
-    if (n > 65535) return ['Too many fragments']
-    if (n == 1) return [null, msg]
-
-    var k, bi, ei, frag, mf, mfs = []
-    for (k = 1; k <= n; k++) {
-      bi = (k - 1) * fs
-      ei = k * fs
-      frag = msg.slice(bi, ei)
-      mf = WRAPPER_BEGIN
-      if (v3) mf += its
-      mf += ',' + k + ','
-      mf += n + ','
-      mf += frag + ','
-      mfs.push(mf)
-    }
-
-    return [null, mfs]
-  }
-
-  HLP.splitype = function splitype(arr, msg) {
-    var data = []
-    arr.forEach(function (a) {
-      var str
-      switch (a) {
-        case 'PUBKEY':
-          str = splitype(['SHORT', 'MPI', 'MPI', 'MPI', 'MPI'], msg).join('')
-          break
-        case 'DATA':  // falls through
-        case 'MPI':
-          str = msg.substring(0, HLP.readLen(msg) + 4)
-          break
-        default:
-          str = msg.substring(0, DTS[a])
-      }
-      data.push(str)
-      msg = msg.substring(str.length)
-    })
-    return data
-  }
-
-  // https://github.com/msgpack/msgpack-javascript/blob/master/msgpack.js
-
-  var _bin2num = (function () {
-    var i = 0, _bin2num = {}
-    for (; i < 0x100; ++i) {
-      _bin2num[String.fromCharCode(i)] = i  // "\00" -> 0x00
-    }
-    for (i = 0x80; i < 0x100; ++i) {  // [Webkit][Gecko]
-      _bin2num[String.fromCharCode(0xf700 + i)] = i  // "\f780" -> 0x80
-    }
-    return _bin2num
-  }())
-
-  HLP.toByteArray = function (data) {
-    var rv = []
-      , ary = data.split("")
-      , i = -1
-      , iz = ary.length
-      , remain = iz % 8
-
-    while (remain--) {
-      ++i
-      rv[i] = _bin2num[ary[i]]
-    }
-    remain = iz >> 3
-    while (remain--) {
-      rv.push(_bin2num[ary[++i]], _bin2num[ary[++i]],
-              _bin2num[ary[++i]], _bin2num[ary[++i]],
-              _bin2num[ary[++i]], _bin2num[ary[++i]],
-              _bin2num[ary[++i]], _bin2num[ary[++i]])
-    }
-    return rv
-  }
-
-}).call(this)
-;(function () {
-  "use strict";
-
-  var root = this
-
-  var CryptoJS, BigInt, Worker, WWPath, HLP
-  if (typeof module !== 'undefined' && module.exports) {
-    module.exports = DSA
-    CryptoJS = require('../vendor/crypto.js')
-    BigInt = require('../vendor/bigint.js')
-    WWPath = require('path').join(__dirname, '/dsa-webworker.js')
-    HLP = require('./helpers.js')
-  } else {
-    // copy over and expose internals
-    Object.keys(root.DSA).forEach(function (k) {
-      DSA[k] = root.DSA[k]
-    })
-    root.DSA = DSA
-    CryptoJS = root.CryptoJS
-    BigInt = root.BigInt
-    Worker = root.Worker
-    WWPath = 'dsa-webworker.js'
-    HLP = DSA.HLP
-  }
-
-  var ZERO = BigInt.str2bigInt('0', 10)
-    , ONE = BigInt.str2bigInt('1', 10)
-    , TWO = BigInt.str2bigInt('2', 10)
-    , KEY_TYPE = '\x00\x00'
-
-  var DEBUG = false
-  function timer() {
-    var start = (new Date()).getTime()
-    return function (s) {
-      if (!DEBUG || typeof console === 'undefined') return
-      var t = (new Date()).getTime()
-      console.log(s + ': ' + (t - start))
-      start = t
-    }
-  }
-
-  function makeRandom(min, max) {
-    var c = BigInt.randBigInt(BigInt.bitSize(max))
-    if (!HLP.between(c, min, max)) return makeRandom(min, max)
-    return c
-  }
-
-  // altered BigInt.randProbPrime()
-  // n rounds of Miller Rabin (after trial division with small primes)
-  var rpprb = []
-  function isProbPrime(k, n) {
-    var i, B = 30000, l = BigInt.bitSize(k)
-    var primes = BigInt.primes
-
-    if (primes.length === 0)
-      primes = BigInt.findPrimes(B)
-
-    if (rpprb.length != k.length)
-      rpprb = BigInt.dup(k)
-
-    // check ans for divisibility by small primes up to B
-    for (i = 0; (i < primes.length) && (primes[i] <= B); i++)
-      if (BigInt.modInt(k, primes[i]) === 0 && !BigInt.equalsInt(k, primes[i]))
-        return 0
-
-    // do n rounds of Miller Rabin, with random bases less than k
-    for (i = 0; i < n; i++) {
-      BigInt.randBigInt_(rpprb, l, 0)
-      while(!BigInt.greater(k, rpprb))  // pick a random rpprb that's < k
-        BigInt.randBigInt_(rpprb, l, 0)
-      if (!BigInt.millerRabin(k, rpprb))
-        return 0
-    }
-
-    return 1
-  }
-
-  var bit_lengths = {
-      '1024': { N: 160, repeat: 40 }  // 40x should give 2^-80 confidence
-    , '2048': { N: 224, repeat: 56 }
-  }
-
-  var primes = {}
-
-  // follows go lang http://golang.org/src/pkg/crypto/dsa/dsa.go
-  // fips version was removed in 0c99af0df3e7
-  function generatePrimes(bit_length) {
-
-    var t = timer()  // for debugging
-
-    // number of MR tests to perform
-    var repeat = bit_lengths[bit_length].repeat
-
-    var N = bit_lengths[bit_length].N
-
-    var LM1 = BigInt.twoToThe(bit_length - 1)
-    var bl4 = 4 * bit_length
-    var brk = false
-
-    var q, p, rem, counter
-    for (;;) {
-
-      q = BigInt.randBigInt(N, 1)
-      q[0] |= 1
-
-      if (!isProbPrime(q, repeat)) continue
-      t('q')
-
-      for (counter = 0; counter < bl4; counter++) {
-        p = BigInt.randBigInt(bit_length, 1)
-        p[0] |= 1
-
-        rem = BigInt.mod(p, q)
-        rem = BigInt.sub(rem, ONE)
-        p = BigInt.sub(p, rem)
-
-        if (BigInt.greater(LM1, p)) continue
-        if (!isProbPrime(p, repeat)) continue
-
-        t('p')
-        primes[bit_length] = { p: p, q: q }
-        brk = true
-        break
-      }
-
-      if (brk) break
-    }
-
-    var h = BigInt.dup(TWO)
-    var pm1 = BigInt.sub(p, ONE)
-    var e = BigInt.multMod(pm1, BigInt.inverseMod(q, p), p)
-
-    var g
-    for (;;) {
-      g = BigInt.powMod(h, e, p)
-      if (BigInt.equals(g, ONE)) {
-        h = BigInt.add(h, ONE)
-        continue
-      }
-      primes[bit_length].g = g
-      t('g')
-      return
-    }
-
-    throw new Error('Unreachable!')
-  }
-
-  function DSA(obj, opts) {
-    if (!(this instanceof DSA)) return new DSA(obj, opts)
-
-    // options
-    opts = opts || {}
-
-    // inherit
-    if (obj) {
-      var self = this
-      ;['p', 'q', 'g', 'y', 'x'].forEach(function (prop) {
-        self[prop] = obj[prop]
-      })
-      this.type = obj.type || KEY_TYPE
-      return
-    }
-
-    // default to 1024
-    var bit_length = parseInt(opts.bit_length ? opts.bit_length : 1024, 10)
-
-    if (!bit_lengths[bit_length])
-      throw new Error('Unsupported bit length.')
-
-    // set primes
-    if (!primes[bit_length])
-      generatePrimes(bit_length)
-
-    this.p = primes[bit_length].p
-    this.q = primes[bit_length].q
-    this.g = primes[bit_length].g
-
-    // key type
-    this.type = KEY_TYPE
-
-    // private key
-    this.x = makeRandom(ZERO, this.q)
-
-    // public keys (p, q, g, y)
-    this.y = BigInt.powMod(this.g, this.x, this.p)
-
-    // nocache?
-    if (opts.nocache) primes[bit_length] = null
-  }
-
-  DSA.prototype = {
-
-    constructor: DSA,
-
-    packPublic: function () {
-      var str = this.type
-      str += HLP.packMPI(this.p)
-      str += HLP.packMPI(this.q)
-      str += HLP.packMPI(this.g)
-      str += HLP.packMPI(this.y)
-      return str
-    },
-
-    packPrivate: function () {
-      var str = this.packPublic() + HLP.packMPI(this.x)
-      str = CryptoJS.enc.Latin1.parse(str)
-      return str.toString(CryptoJS.enc.Base64)
-    },
-
-    // http://www.imperialviolet.org/2013/06/15/suddendeathentropy.html
-    generateNonce: function (m) {
-      var priv = BigInt.bigInt2bits(BigInt.trim(this.x, 0))
-      var rand = BigInt.bigInt2bits(BigInt.randBigInt(256))
-
-      var sha256 = CryptoJS.algo.SHA256.create()
-      sha256.update(CryptoJS.enc.Latin1.parse(priv))
-      sha256.update(m)
-      sha256.update(CryptoJS.enc.Latin1.parse(rand))
-
-      var hash = sha256.finalize()
-      hash = HLP.bits2bigInt(hash.toString(CryptoJS.enc.Latin1))
-      BigInt.rightShift_(hash, 256 - BigInt.bitSize(this.q))
-
-      return HLP.between(hash, ZERO, this.q) ? hash : this.generateNonce(m)
-    },
-
-    sign: function (m) {
-      m = CryptoJS.enc.Latin1.parse(m)
-      var b = BigInt.str2bigInt(m.toString(CryptoJS.enc.Hex), 16)
-      var k, r = ZERO, s = ZERO
-      while (BigInt.isZero(s) || BigInt.isZero(r)) {
-        k = this.generateNonce(m)
-        r = BigInt.mod(BigInt.powMod(this.g, k, this.p), this.q)
-        if (BigInt.isZero(r)) continue
-        s = BigInt.inverseMod(k, this.q)
-        s = BigInt.mult(s, BigInt.add(b, BigInt.mult(this.x, r)))
-        s = BigInt.mod(s, this.q)
-      }
-      return [r, s]
-    },
-
-    fingerprint: function () {
-      var pk = this.packPublic()
-      if (this.type === KEY_TYPE) pk = pk.substring(2)
-      pk = CryptoJS.enc.Latin1.parse(pk)
-      return CryptoJS.SHA1(pk).toString(CryptoJS.enc.Hex)
-    }
-
-  }
-
-  DSA.parsePublic = function (str, priv) {
-    var fields = ['SHORT', 'MPI', 'MPI', 'MPI', 'MPI']
-    if (priv) fields.push('MPI')
-    str = HLP.splitype(fields, str)
-    var obj = {
-        type: str[0]
-      , p: HLP.readMPI(str[1])
-      , q: HLP.readMPI(str[2])
-      , g: HLP.readMPI(str[3])
-      , y: HLP.readMPI(str[4])
-    }
-    if (priv) obj.x = HLP.readMPI(str[5])
-    return new DSA(obj)
-  }
-
-  function tokenizeStr(str) {
-    var start, end
-
-    start = str.indexOf("(")
-    end = str.lastIndexOf(")")
-
-    if (start < 0 || end < 0)
-      throw new Error("Malformed S-Expression")
-
-    str = str.substring(start + 1, end)
-
-    var splt = str.search(/\s/)
-    var obj = {
-        type: str.substring(0, splt)
-      , val: []
-    }
-
-    str = str.substring(splt + 1, end)
-    start = str.indexOf("(")
-
-    if (start < 0) obj.val.push(str)
-    else {
-
-      var i, len, ss, es
-      while (start > -1) {
-        i = start + 1
-        len = str.length
-        for (ss = 1, es = 0; i < len && es < ss; i++) {
-          if (str[i] === "(") ss++
-          if (str[i] === ")") es++
-        }
-        obj.val.push(tokenizeStr(str.substring(start, ++i)))
-        str = str.substring(++i)
-        start = str.indexOf("(")
-      }
-
-    }
-    return obj
-  }
-
-  function parseLibotr(obj) {
-    if (!obj.type) throw new Error("Parse error.")
-
-    var o, val
-    if (obj.type === "privkeys") {
-      o = []
-      obj.val.forEach(function (i) {
-        o.push(parseLibotr(i))
-      })
-      return o
-    }
-
-    o = {}
-    obj.val.forEach(function (i) {
-
-      val = i.val[0]
-      if (typeof val === "string") {
-
-        if (val.indexOf("#") === 0) {
-          val = val.substring(1, val.lastIndexOf("#"))
-          val = BigInt.str2bigInt(val, 16)
-        }
-
-      } else {
-        val = parseLibotr(i)
-      }
-
-      o[i.type] = val
-    })
-
-    return o
-  }
-
-  DSA.parsePrivate = function (str, libotr) {
-    if (!libotr) {
-      str = CryptoJS.enc.Base64.parse(str)
-      str = str.toString(CryptoJS.enc.Latin1)
-      return DSA.parsePublic(str, true)
-    }
-    // only returning the first key found
-    return parseLibotr(tokenizeStr(str))[0]["private-key"].dsa
-  }
-
-  DSA.verify = function (key, m, r, s) {
-    if (!HLP.between(r, ZERO, key.q) || !HLP.between(s, ZERO, key.q))
-      return false
-
-    var hm = CryptoJS.enc.Latin1.parse(m)  // CryptoJS.SHA1(m)
-    hm = BigInt.str2bigInt(hm.toString(CryptoJS.enc.Hex), 16)
-
-    var w = BigInt.inverseMod(s, key.q)
-    var u1 = BigInt.multMod(hm, w, key.q)
-    var u2 = BigInt.multMod(r, w, key.q)
-
-    u1 = BigInt.powMod(key.g, u1, key.p)
-    u2 = BigInt.powMod(key.y, u2, key.p)
-
-    var v = BigInt.mod(BigInt.multMod(u1, u2, key.p), key.q)
-
-    return BigInt.equals(v, r)
-  }
-
-  DSA.createInWebWorker = function (options, cb) {
-    var opts = {
-        path: WWPath
-      , seed: BigInt.getSeed
-    }
-    if (options && typeof options === 'object')
-      Object.keys(options).forEach(function (k) {
-        opts[k] = options[k]
-      })
-
-    // load optional dep. in node
-    if (typeof module !== 'undefined' && module.exports)
-      Worker = require('webworker-threads').Worker
-
-    var worker = new Worker(opts.path)
-    worker.onmessage = function (e) {
-      var data = e.data
-      switch (data.type) {
-        case "debug":
-          if (!DEBUG || typeof console === 'undefined') return
-          console.log(data.val)
-          break;
-        case "data":
-          worker.terminate()
-          cb(DSA.parsePrivate(data.val))
-          break;
-        default:
-          throw new Error("Unrecognized type.")
-      }
-    }
-    worker.postMessage({
-        seed: opts.seed()
-      , imports: opts.imports
-      , debug: DEBUG
-    })
-  }
-
-}).call(this)
-;(function () {
-  "use strict";
-
-  var root = this
-
-  var Parse = {}, CryptoJS, CONST, HLP
-  if (typeof module !== 'undefined' && module.exports) {
-    module.exports = Parse
-    CryptoJS = require('../vendor/crypto.js')
-    CONST = require('./const.js')
-    HLP = require('./helpers.js')
-  } else {
-    root.OTR.Parse = Parse
-    CryptoJS = root.CryptoJS
-    CONST = root.OTR.CONST
-    HLP = root.OTR.HLP
-  }
-
-  // whitespace tags
-  var tags = {}
-  tags[CONST.WHITESPACE_TAG_V2] = CONST.OTR_VERSION_2
-  tags[CONST.WHITESPACE_TAG_V3] = CONST.OTR_VERSION_3
-
-  Parse.parseMsg = function (otr, msg) {
-
-    var ver = []
-
-    // is this otr?
-    var start = msg.indexOf(CONST.OTR_TAG)
-    if (!~start) {
-
-      // restart fragments
-      this.initFragment(otr)
-
-      // whitespace tags
-      ind = msg.indexOf(CONST.WHITESPACE_TAG)
-
-      if (~ind) {
-
-        msg = msg.split('')
-        msg.splice(ind, 16)
-
-        var tag, len = msg.length
-        for (; ind < len;) {
-          tag = msg.slice(ind, ind + 8).join('')
-          if (Object.hasOwnProperty.call(tags, tag)) {
-            msg.splice(ind, 8)
-            ver.push(tags[tag])
-            continue
-          }
-          ind += 8
-        }
-
-        msg = msg.join('')
-
-      }
-
-      return { msg: msg, ver: ver }
-    }
-
-    var ind = start + CONST.OTR_TAG.length
-    var com = msg[ind]
-
-    // message fragment
-    if (com === ',' || com === '|') {
-      return this.msgFragment(otr, msg.substring(ind + 1), (com === '|'))
-    }
-
-    this.initFragment(otr)
-
-    // query message
-    if (~['?', 'v'].indexOf(com)) {
-
-      // version 1
-      if (msg[ind] === '?') {
-        ver.push(CONST.OTR_VERSION_1)
-        ind += 1
-      }
-
-      // other versions
-      var vers = {
-          '2': CONST.OTR_VERSION_2
-        , '3': CONST.OTR_VERSION_3
-      }
-      var qs = msg.substring(ind + 1)
-      var qi = qs.indexOf('?')
-
-      if (qi >= 1) {
-        qs = qs.substring(0, qi).split('')
-        if (msg[ind] === 'v') {
-          qs.forEach(function (q) {
-            if (Object.hasOwnProperty.call(vers, q)) ver.push(vers[q])
-          })
-        }
-      }
-
-      return { cls: 'query', ver: ver }
-    }
-
-    // otr message
-    if (com === ':') {
-
-      ind += 1
-
-      var info = msg.substring(ind, ind + 4)
-      if (info.length < 4) return { msg: msg }
-      info = CryptoJS.enc.Base64.parse(info).toString(CryptoJS.enc.Latin1)
-
-      var version = info.substring(0, 2)
-      var type = info.substring(2)
-
-      // supporting otr versions 2 and 3
-      if (!otr['ALLOW_V' + HLP.unpackSHORT(version)]) return { msg: msg }
-
-      ind += 4
-
-      var end = msg.substring(ind).indexOf('.')
-      if (!~end) return { msg: msg }
-
-      msg = CryptoJS.enc.Base64.parse(msg.substring(ind, ind + end))
-      msg = CryptoJS.enc.Latin1.stringify(msg)
-
-      // instance tags
-      var instance_tags
-      if (version === CONST.OTR_VERSION_3) {
-        instance_tags = msg.substring(0, 8)
-        msg = msg.substring(8)
-      }
-
-      var cls
-      if (~['\x02', '\x0a', '\x11', '\x12'].indexOf(type)) {
-        cls = 'ake'
-      } else if (type === '\x03') {
-        cls = 'data'
-      }
-
-      return {
-          version: version
-        , type: type
-        , msg: msg
-        , cls: cls
-        , instance_tags: instance_tags
-      }
-    }
-
-    // error message
-    if (msg.substring(ind, ind + 7) === ' Error:') {
-      if (otr.ERROR_START_AKE) {
-        otr.sendQueryMsg()
-      }
-      return { msg: msg.substring(ind + 7), cls: 'error' }
-    }
-
-    return { msg: msg }
-  }
-
-  Parse.initFragment = function (otr) {
-    otr.fragment = { s: '', j: 0, k: 0 }
-  }
-
-  Parse.msgFragment = function (otr, msg, v3) {
-
-    msg = msg.split(',')
-
-    // instance tags
-    if (v3) {
-      var its = msg.shift().split('|')
-      var their_it = HLP.packINT(parseInt(its[0], 16))
-      var our_it = HLP.packINT(parseInt(its[1], 16))
-      if (otr.checkInstanceTags(their_it + our_it)) return  // ignore
-    }
-
-    if (msg.length < 4 ||
-      isNaN(parseInt(msg[0], 10)) ||
-      isNaN(parseInt(msg[1], 10))
-    ) return
-
-    var k = parseInt(msg[0], 10)
-    var n = parseInt(msg[1], 10)
-    msg = msg[2]
-
-    if (n < k || n === 0 || k === 0) {
-      this.initFragment(otr)
-      return
-    }
-
-    if (k === 1) {
-      this.initFragment(otr)
-      otr.fragment = { k: 1, n: n, s: msg }
-    } else if (n === otr.fragment.n && k === (otr.fragment.k + 1)) {
-      otr.fragment.s += msg
-      otr.fragment.k += 1
-    } else {
-      this.initFragment(otr)
-    }
-
-    if (n === k) {
-      msg = otr.fragment.s
-      this.initFragment(otr)
-      return this.parseMsg(otr, msg)
-    }
-
-    return
-  }
-
-}).call(this)
-;(function () {
-  "use strict";
-
-  var root = this
-
-  var CryptoJS, BigInt, CONST, HLP, DSA
-  if (typeof module !== 'undefined' && module.exports) {
-    module.exports = AKE
-    CryptoJS = require('../vendor/crypto.js')
-    BigInt = require('../vendor/bigint.js')
-    CONST = require('./const.js')
-    HLP = require('./helpers.js')
-    DSA = require('./dsa.js')
-  } else {
-    root.OTR.AKE = AKE
-    CryptoJS = root.CryptoJS
-    BigInt = root.BigInt
-    CONST = root.OTR.CONST
-    HLP = root.OTR.HLP
-    DSA = root.DSA
-  }
-
-  // diffie-hellman modulus
-  // see group 5, RFC 3526
-  var N = BigInt.str2bigInt(CONST.N, 16)
-  var N_MINUS_2 = BigInt.sub(N, BigInt.str2bigInt('2', 10))
-
-  function hMac(gx, gy, pk, kid, m) {
-    var pass = CryptoJS.enc.Latin1.parse(m)
-    var hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, pass)
-    hmac.update(CryptoJS.enc.Latin1.parse(HLP.packMPI(gx)))
-    hmac.update(CryptoJS.enc.Latin1.parse(HLP.packMPI(gy)))
-    hmac.update(CryptoJS.enc.Latin1.parse(pk))
-    hmac.update(CryptoJS.enc.Latin1.parse(kid))
-    return (hmac.finalize()).toString(CryptoJS.enc.Latin1)
-  }
-
-  // AKE constructor
-  function AKE(otr) {
-    if (!(this instanceof AKE)) return new AKE(otr)
-
-    // otr instance
-    this.otr = otr
-
-    // our keys
-    this.our_dh = otr.our_old_dh
-    this.our_keyid = otr.our_keyid - 1
-
-    // their keys
-    this.their_y = null
-    this.their_keyid = null
-    this.their_priv_pk = null
-
-    // state
-    this.ssid = null
-    this.transmittedRS = false
-    this.r = null
-
-    // bind methods
-    var self = this
-    ;['sendMsg'].forEach(function (meth) {
-      self[meth] = self[meth].bind(self)
-    })
-  }
-
-  AKE.prototype = {
-
-    constructor: AKE,
-
-    createKeys: function(g) {
-      var s = BigInt.powMod(g, this.our_dh.privateKey, N)
-      var secbytes = HLP.packMPI(s)
-      this.ssid = HLP.mask(HLP.h2('\x00', secbytes), 0, 64)  // first 64-bits
-      var tmp = HLP.h2('\x01', secbytes)
-      this.c = HLP.mask(tmp, 0, 128)  // first 128-bits
-      this.c_prime = HLP.mask(tmp, 128, 128)  // second 128-bits
-      this.m1 = HLP.h2('\x02', secbytes)
-      this.m2 = HLP.h2('\x03', secbytes)
-      this.m1_prime = HLP.h2('\x04', secbytes)
-      this.m2_prime = HLP.h2('\x05', secbytes)
-    },
-
-    verifySignMac: function (mac, aesctr, m2, c, their_y, our_dh_pk, m1, ctr) {
-      // verify mac
-      var vmac = HLP.makeMac(aesctr, m2)
-      if (!HLP.compare(mac, vmac))
-        return ['MACs do not match.']
-
-      // decrypt x
-      var x = HLP.decryptAes(aesctr.substring(4), c, ctr)
-      x = HLP.splitype(['PUBKEY', 'INT', 'SIG'], x.toString(CryptoJS.enc.Latin1))
-
-      var m = hMac(their_y, our_dh_pk, x[0], x[1], m1)
-      var pub = DSA.parsePublic(x[0])
-
-      var r = HLP.bits2bigInt(x[2].substring(0, 20))
-      var s = HLP.bits2bigInt(x[2].substring(20))
-
-      // verify sign m
-      if (!DSA.verify(pub, m, r, s)) return ['Cannot verify signature of m.']
-
-      return [null, HLP.readLen(x[1]), pub]
-    },
-
-    makeM: function (their_y, m1, c, m2) {
-      var pk = this.otr.priv.packPublic()
-      var kid = HLP.packINT(this.our_keyid)
-      var m = hMac(this.our_dh.publicKey, their_y, pk, kid, m1)
-      m = this.otr.priv.sign(m)
-      var msg = pk + kid
-      msg += BigInt.bigInt2bits(m[0], 20)  // pad to 20 bytes
-      msg += BigInt.bigInt2bits(m[1], 20)
-      msg = CryptoJS.enc.Latin1.parse(msg)
-      var aesctr = HLP.packData(HLP.encryptAes(msg, c, HLP.packCtr(0)))
-      var mac = HLP.makeMac(aesctr, m2)
-      return aesctr + mac
-    },
-
-    akeSuccess: function (version) {
-      HLP.debug.call(this.otr, 'success')
-
-      if (BigInt.equals(this.their_y, this.our_dh.publicKey))
-        return this.otr.error('equal keys - we have a problem.', true)
-
-      this.otr.our_old_dh = this.our_dh
-      this.otr.their_priv_pk = this.their_priv_pk
-
-      if (!(
-        (this.their_keyid === this.otr.their_keyid &&
-         BigInt.equals(this.their_y, this.otr.their_y)) ||
-        (this.their_keyid === (this.otr.their_keyid - 1) &&
-         BigInt.equals(this.their_y, this.otr.their_old_y))
-      )) {
-
-        this.otr.their_y = this.their_y
-        this.otr.their_old_y = null
-        this.otr.their_keyid = this.their_keyid
-
-        // rotate keys
-        this.otr.sessKeys[0] = [ new this.otr.DHSession(
-            this.otr.our_dh
-          , this.otr.their_y
-        ), null ]
-        this.otr.sessKeys[1] = [ new this.otr.DHSession(
-            this.otr.our_old_dh
-          , this.otr.their_y
-        ), null ]
-
-      }
-
-      // ake info
-      this.otr.ssid = this.ssid
-      this.otr.transmittedRS = this.transmittedRS
-      this.otr_version = version
-
-      // go encrypted
-      this.otr.authstate = CONST.AUTHSTATE_NONE
-      this.otr.msgstate = CONST.MSGSTATE_ENCRYPTED
-
-      // null out values
-      this.r = null
-      this.myhashed = null
-      this.dhcommit = null
-      this.encrypted = null
-      this.hashed = null
-
-      this.otr.trigger('status', [CONST.STATUS_AKE_SUCCESS])
-
-      // send stored msgs
-      this.otr.sendStored()
-    },
-
-    handleAKE: function (msg) {
-      var send, vsm, type
-      var version = msg.version
-
-      switch (msg.type) {
-
-        case '\x02':
-          HLP.debug.call(this.otr, 'd-h key message')
-
-          msg = HLP.splitype(['DATA', 'DATA'], msg.msg)
-
-          if (this.otr.authstate === CONST.AUTHSTATE_AWAITING_DHKEY) {
-            var ourHash = HLP.readMPI(this.myhashed)
-            var theirHash = HLP.readMPI(msg[1])
-            if (BigInt.greater(ourHash, theirHash)) {
-              type = '\x02'
-              send = this.dhcommit
-              break  // ignore
-            } else {
-              // forget
-              this.our_dh = this.otr.dh()
-              this.otr.authstate = CONST.AUTHSTATE_NONE
-              this.r = null
-              this.myhashed = null
-            }
-          } else if (
-            this.otr.authstate === CONST.AUTHSTATE_AWAITING_SIG
-          ) this.our_dh = this.otr.dh()
-
-          this.otr.authstate = CONST.AUTHSTATE_AWAITING_REVEALSIG
-
-          this.encrypted = msg[0].substring(4)
-          this.hashed = msg[1].substring(4)
-
-          type = '\x0a'
-          send = HLP.packMPI(this.our_dh.publicKey)
-          break
-
-        case '\x0a':
-          HLP.debug.call(this.otr, 'reveal signature message')
-
-          msg = HLP.splitype(['MPI'], msg.msg)
-
-          if (this.otr.authstate !== CONST.AUTHSTATE_AWAITING_DHKEY) {
-            if (this.otr.authstate === CONST.AUTHSTATE_AWAITING_SIG) {
-              if (!BigInt.equals(this.their_y, HLP.readMPI(msg[0]))) return
-            } else {
-              return  // ignore
-            }
-          }
-
-          this.otr.authstate = CONST.AUTHSTATE_AWAITING_SIG
-
-          this.their_y = HLP.readMPI(msg[0])
-
-          // verify gy is legal 2 <= gy <= N-2
-          if (!HLP.checkGroup(this.their_y, N_MINUS_2))
-            return this.otr.error('Illegal g^y.', true)
-
-          this.createKeys(this.their_y)
-
-          type = '\x11'
-          send = HLP.packMPI(this.r)
-          send += this.makeM(this.their_y, this.m1, this.c, this.m2)
-
-          this.m1 = null
-          this.m2 = null
-          this.c = null
-          break
-
-        case '\x11':
-          HLP.debug.call(this.otr, 'signature message')
-
-          if (this.otr.authstate !== CONST.AUTHSTATE_AWAITING_REVEALSIG)
-            return  // ignore
-
-          msg = HLP.splitype(['DATA', 'DATA', 'MAC'], msg.msg)
-
-          this.r = HLP.readMPI(msg[0])
-
-          // decrypt their_y
-          var key = CryptoJS.enc.Hex.parse(BigInt.bigInt2str(this.r, 16))
-          key = CryptoJS.enc.Latin1.stringify(key)
-
-          var gxmpi = HLP.decryptAes(this.encrypted, key, HLP.packCtr(0))
-          gxmpi = gxmpi.toString(CryptoJS.enc.Latin1)
-
-          this.their_y = HLP.readMPI(gxmpi)
-
-          // verify hash
-          var hash = CryptoJS.SHA256(CryptoJS.enc.Latin1.parse(gxmpi))
-
-          if (!HLP.compare(this.hashed, hash.toString(CryptoJS.enc.Latin1)))
-            return this.otr.error('Hashed g^x does not match.', true)
-
-          // verify gx is legal 2 <= g^x <= N-2
-          if (!HLP.checkGroup(this.their_y, N_MINUS_2))
-            return this.otr.error('Illegal g^x.', true)
-
-          this.createKeys(this.their_y)
-
-          vsm = this.verifySignMac(
-              msg[2]
-            , msg[1]
-            , this.m2
-            , this.c
-            , this.their_y
-            , this.our_dh.publicKey
-            , this.m1
-            , HLP.packCtr(0)
-          )
-          if (vsm[0]) return this.otr.error(vsm[0], true)
-
-          // store their key
-          this.their_keyid = vsm[1]
-          this.their_priv_pk = vsm[2]
-
-          send = this.makeM(
-              this.their_y
-            , this.m1_prime
-            , this.c_prime
-            , this.m2_prime
-          )
-
-          this.m1 = null
-          this.m2 = null
-          this.m1_prime = null
-          this.m2_prime = null
-          this.c = null
-          this.c_prime = null
-
-          this.sendMsg(version, '\x12', send)
-          this.akeSuccess(version)
-          return
-
-        case '\x12':
-          HLP.debug.call(this.otr, 'data message')
-
-          if (this.otr.authstate !== CONST.AUTHSTATE_AWAITING_SIG)
-            return  // ignore
-
-          msg = HLP.splitype(['DATA', 'MAC'], msg.msg)
-
-          vsm = this.verifySignMac(
-              msg[1]
-            , msg[0]
-            , this.m2_prime
-            , this.c_prime
-            , this.their_y
-            , this.our_dh.publicKey
-            , this.m1_prime
-            , HLP.packCtr(0)
-          )
-          if (vsm[0]) return this.otr.error(vsm[0], true)
-
-          // store their key
-          this.their_keyid = vsm[1]
-          this.their_priv_pk = vsm[2]
-
-          this.m1_prime = null
-          this.m2_prime = null
-          this.c_prime = null
-
-          this.transmittedRS = true
-          this.akeSuccess(version)
-          return
-
-        default:
-          return  // ignore
-
-      }
-
-      this.sendMsg(version, type, send)
-    },
-
-    sendMsg: function (version, type, msg) {
-      var send = version + type
-      var v3 = (version === CONST.OTR_VERSION_3)
-
-      // instance tags for v3
-      if (v3) {
-        HLP.debug.call(this.otr, 'instance tags')
-        send += this.otr.our_instance_tag
-        send += this.otr.their_instance_tag
-      }
-
-      send += msg
-
-      // fragment message if necessary
-      send = HLP.wrapMsg(
-          send
-        , this.otr.fragment_size
-        , v3
-        , this.otr.our_instance_tag
-        , this.otr.their_instance_tag
-      )
-      if (send[0]) return this.otr.error(send[0])
-
-      this.otr.io(send[1])
-    },
-
-    initiateAKE: function (version) {
-      HLP.debug.call(this.otr, 'd-h commit message')
-
-      this.otr.trigger('status', [CONST.STATUS_AKE_INIT])
-
-      this.otr.authstate = CONST.AUTHSTATE_AWAITING_DHKEY
-
-      var gxmpi = HLP.packMPI(this.our_dh.publicKey)
-      gxmpi = CryptoJS.enc.Latin1.parse(gxmpi)
-
-      this.r = BigInt.randBigInt(128)
-      var key = CryptoJS.enc.Hex.parse(BigInt.bigInt2str(this.r, 16))
-      key = CryptoJS.enc.Latin1.stringify(key)
-
-      this.myhashed = CryptoJS.SHA256(gxmpi)
-      this.myhashed = HLP.packData(this.myhashed.toString(CryptoJS.enc.Latin1))
-
-      this.dhcommit = HLP.packData(HLP.encryptAes(gxmpi, key, HLP.packCtr(0)))
-      this.dhcommit += this.myhashed
-
-      this.sendMsg(version, '\x02', this.dhcommit)
-    }
-
-  }
-
-}).call(this)
-;(function () {
-  "use strict";
-
-  var root = this
-
-  var CryptoJS, BigInt,  EventEmitter, CONST, HLP
-  if (typeof module !== 'undefined' && module.exports) {
-    module.exports = SM
-    CryptoJS = require('../vendor/crypto.js')
-    BigInt = require('../vendor/bigint.js')
-    EventEmitter = require('../vendor/eventemitter.js')
-    CONST = require('./const.js')
-    HLP = require('./helpers.js')
-  } else {
-    root.OTR.SM = SM
-    CryptoJS = root.CryptoJS
-    BigInt = root.BigInt
-    EventEmitter = root.EventEmitter
-    CONST = root.OTR.CONST
-    HLP = root.OTR.HLP
-  }
-
-  // diffie-hellman modulus and generator
-  // see group 5, RFC 3526
-  var G = BigInt.str2bigInt(CONST.G, 10)
-  var N = BigInt.str2bigInt(CONST.N, 16)
-  var N_MINUS_2 = BigInt.sub(N, BigInt.str2bigInt('2', 10))
-
-  // to calculate D's for zero-knowledge proofs
-  var Q = BigInt.sub(N, BigInt.str2bigInt('1', 10))
-  BigInt.divInt_(Q, 2)  // meh
-
-  function SM(reqs) {
-    if (!(this instanceof SM)) return new SM(reqs)
-
-    this.version = 1
-
-    this.our_fp = reqs.our_fp
-    this.their_fp = reqs.their_fp
-    this.ssid = reqs.ssid
-
-    this.debug = !!reqs.debug
-
-    // initial state
-    this.init()
-  }
-
-  // inherit from EE
-  HLP.extend(SM, EventEmitter)
-
-  // set the initial values
-  // also used when aborting
-  SM.prototype.init = function () {
-    this.smpstate = CONST.SMPSTATE_EXPECT1
-    this.secret = null
-  }
-
-  SM.prototype.makeSecret = function (our, secret) {
-    var sha256 = CryptoJS.algo.SHA256.create()
-    sha256.update(CryptoJS.enc.Latin1.parse(HLP.packBytes(this.version, 1)))
-    sha256.update(CryptoJS.enc.Hex.parse(our ? this.our_fp : this.their_fp))
-    sha256.update(CryptoJS.enc.Hex.parse(our ? this.their_fp : this.our_fp))
-    sha256.update(CryptoJS.enc.Latin1.parse(this.ssid))
-    sha256.update(CryptoJS.enc.Latin1.parse(secret))
-    var hash = sha256.finalize()
-    this.secret = HLP.bits2bigInt(hash.toString(CryptoJS.enc.Latin1))
-  }
-
-  SM.prototype.makeG2s = function () {
-    this.a2 = HLP.randomExponent()
-    this.a3 = HLP.randomExponent()
-    this.g2a = BigInt.powMod(G, this.a2, N)
-    this.g3a = BigInt.powMod(G, this.a3, N)
-    if ( !HLP.checkGroup(this.g2a, N_MINUS_2) ||
-         !HLP.checkGroup(this.g3a, N_MINUS_2)
-    ) this.makeG2s()
-  }
-
-  SM.prototype.computeGs = function (g2a, g3a) {
-    this.g2 = BigInt.powMod(g2a, this.a2, N)
-    this.g3 = BigInt.powMod(g3a, this.a3, N)
-  }
-
-  SM.prototype.computePQ = function (r) {
-    this.p = BigInt.powMod(this.g3, r, N)
-    this.q = HLP.multPowMod(G, r, this.g2, this.secret, N)
-  }
-
-  SM.prototype.computeR = function () {
-    this.r = BigInt.powMod(this.QoQ, this.a3, N)
-  }
-
-  SM.prototype.computeRab = function (r) {
-    return BigInt.powMod(r, this.a3, N)
-  }
-
-  SM.prototype.computeC = function (v, r) {
-    return HLP.smpHash(v, BigInt.powMod(G, r, N))
-  }
-
-  SM.prototype.computeD = function (r, a, c) {
-    return BigInt.subMod(r, BigInt.multMod(a, c, Q), Q)
-  }
-
-  // the bulk of the work
-  SM.prototype.handleSM = function (msg) {
-    var send, r2, r3, r7, t1, t2, t3, t4, rab, tmp2, cR, d7, ms, trust
-
-    var expectStates = {
-        2: CONST.SMPSTATE_EXPECT1
-      , 3: CONST.SMPSTATE_EXPECT2
-      , 4: CONST.SMPSTATE_EXPECT3
-      , 5: CONST.SMPSTATE_EXPECT4
-      , 7: CONST.SMPSTATE_EXPECT1
-    }
-
-    if (msg.type === 6) {
-      this.init()
-      this.trigger('abort')
-      return
-    }
-
-    // abort! there was an error
-    if (this.smpstate !== expectStates[msg.type])
-      return this.abort()
-
-    switch (this.smpstate) {
-
-      case CONST.SMPSTATE_EXPECT1:
-        HLP.debug.call(this, 'smp tlv 2')
-
-        // user specified question
-        var ind, question
-        if (msg.type === 7) {
-          ind = msg.msg.indexOf('\x00')
-          question = msg.msg.substring(0, ind)
-          msg.msg = msg.msg.substring(ind + 1)
-        }
-
-        // 0:g2a, 1:c2, 2:d2, 3:g3a, 4:c3, 5:d3
-        ms = HLP.readLen(msg.msg.substr(0, 4))
-        if (ms !== 6) return this.abort()
-        msg = HLP.unpackMPIs(6, msg.msg.substring(4))
-
-        if ( !HLP.checkGroup(msg[0], N_MINUS_2) ||
-             !HLP.checkGroup(msg[3], N_MINUS_2)
-        ) return this.abort()
-
-        // verify znp's
-        if (!HLP.ZKP(1, msg[1], HLP.multPowMod(G, msg[2], msg[0], msg[1], N)))
-          return this.abort()
-
-        if (!HLP.ZKP(2, msg[4], HLP.multPowMod(G, msg[5], msg[3], msg[4], N)))
-          return this.abort()
-
-        this.g3ao = msg[3]  // save for later
-
-        this.makeG2s()
-
-        // zero-knowledge proof that the exponents
-        // associated with g2a & g3a are known
-        r2 = HLP.randomExponent()
-        r3 = HLP.randomExponent()
-        this.c2 = this.computeC(3, r2)
-        this.c3 = this.computeC(4, r3)
-        this.d2 = this.computeD(r2, this.a2, this.c2)
-        this.d3 = this.computeD(r3, this.a3, this.c3)
-
-        this.computeGs(msg[0], msg[3])
-
-        this.smpstate = CONST.SMPSTATE_EXPECT0
-
-        // assume utf8 question
-        question = CryptoJS.enc.Latin1
-          .parse(question)
-          .toString(CryptoJS.enc.Utf8)
-
-        // invoke question
-        this.trigger('question', [question])
-        return
-
-      case CONST.SMPSTATE_EXPECT2:
-        HLP.debug.call(this, 'smp tlv 3')
-
-        // 0:g2a, 1:c2, 2:d2, 3:g3a, 4:c3, 5:d3, 6:p, 7:q, 8:cP, 9:d5, 10:d6
-        ms = HLP.readLen(msg.msg.substr(0, 4))
-        if (ms !== 11) return this.abort()
-        msg = HLP.unpackMPIs(11, msg.msg.substring(4))
-
-        if ( !HLP.checkGroup(msg[0], N_MINUS_2) ||
-             !HLP.checkGroup(msg[3], N_MINUS_2) ||
-             !HLP.checkGroup(msg[6], N_MINUS_2) ||
-             !HLP.checkGroup(msg[7], N_MINUS_2)
-        ) return this.abort()
-
-        // verify znp of c3 / c3
-        if (!HLP.ZKP(3, msg[1], HLP.multPowMod(G, msg[2], msg[0], msg[1], N)))
-          return this.abort()
-
-        if (!HLP.ZKP(4, msg[4], HLP.multPowMod(G, msg[5], msg[3], msg[4], N)))
-          return this.abort()
-
-        this.g3ao = msg[3]  // save for later
-
-        this.computeGs(msg[0], msg[3])
-
-        // verify znp of cP
-        t1 = HLP.multPowMod(this.g3, msg[9], msg[6], msg[8], N)
-        t2 = HLP.multPowMod(G, msg[9], this.g2, msg[10], N)
-        t2 = BigInt.multMod(t2, BigInt.powMod(msg[7], msg[8], N), N)
-
-        if (!HLP.ZKP(5, msg[8], t1, t2))
-          return this.abort()
-
-        var r4 = HLP.randomExponent()
-        this.computePQ(r4)
-
-        // zero-knowledge proof that P & Q
-        // were generated according to the protocol
-        var r5 = HLP.randomExponent()
-        var r6 = HLP.randomExponent()
-        var tmp = HLP.multPowMod(G, r5, this.g2, r6, N)
-        var cP = HLP.smpHash(6, BigInt.powMod(this.g3, r5, N), tmp)
-        var d5 = this.computeD(r5, r4, cP)
-        var d6 = this.computeD(r6, this.secret, cP)
-
-        // store these
-        this.QoQ = BigInt.divMod(this.q, msg[7], N)
-        this.PoP = BigInt.divMod(this.p, msg[6], N)
-
-        this.computeR()
-
-        // zero-knowledge proof that R
-        // was generated according to the protocol
-        r7 = HLP.randomExponent()
-        tmp2 = BigInt.powMod(this.QoQ, r7, N)
-        cR = HLP.smpHash(7, BigInt.powMod(G, r7, N), tmp2)
-        d7 = this.computeD(r7, this.a3, cR)
-
-        this.smpstate = CONST.SMPSTATE_EXPECT4
-
-        send = HLP.packINT(8) + HLP.packMPIs([
-            this.p
-          , this.q
-          , cP
-          , d5
-          , d6
-          , this.r
-          , cR
-          , d7
-        ])
-
-        // TLV
-        send = HLP.packTLV(4, send)
-        break
-
-      case CONST.SMPSTATE_EXPECT3:
-        HLP.debug.call(this, 'smp tlv 4')
-
-        // 0:p, 1:q, 2:cP, 3:d5, 4:d6, 5:r, 6:cR, 7:d7
-        ms = HLP.readLen(msg.msg.substr(0, 4))
-        if (ms !== 8) return this.abort()
-        msg = HLP.unpackMPIs(8, msg.msg.substring(4))
-
-        if ( !HLP.checkGroup(msg[0], N_MINUS_2) ||
-             !HLP.checkGroup(msg[1], N_MINUS_2) ||
-             !HLP.checkGroup(msg[5], N_MINUS_2)
-        ) return this.abort()
-
-        // verify znp of cP
-        t1 = HLP.multPowMod(this.g3, msg[3], msg[0], msg[2], N)
-        t2 = HLP.multPowMod(G, msg[3], this.g2, msg[4], N)
-        t2 = BigInt.multMod(t2, BigInt.powMod(msg[1], msg[2], N), N)
-
-        if (!HLP.ZKP(6, msg[2], t1, t2))
-          return this.abort()
-
-        // verify znp of cR
-        t3 = HLP.multPowMod(G, msg[7], this.g3ao, msg[6], N)
-        this.QoQ = BigInt.divMod(msg[1], this.q, N)  // save Q over Q
-        t4 = HLP.multPowMod(this.QoQ, msg[7], msg[5], msg[6], N)
-
-        if (!HLP.ZKP(7, msg[6], t3, t4))
-          return this.abort()
-
-        this.computeR()
-
-        // zero-knowledge proof that R
-        // was generated according to the protocol
-        r7 = HLP.randomExponent()
-        tmp2 = BigInt.powMod(this.QoQ, r7, N)
-        cR = HLP.smpHash(8, BigInt.powMod(G, r7, N), tmp2)
-        d7 = this.computeD(r7, this.a3, cR)
-
-        send = HLP.packINT(3) + HLP.packMPIs([ this.r, cR, d7 ])
-        send = HLP.packTLV(5, send)
-
-        rab = this.computeRab(msg[5])
-        trust = !!BigInt.equals(rab, BigInt.divMod(msg[0], this.p, N))
-
-        this.trigger('trust', [trust, 'answered'])
-        this.init()
-        break
-
-      case CONST.SMPSTATE_EXPECT4:
-        HLP.debug.call(this, 'smp tlv 5')
-
-        // 0:r, 1:cR, 2:d7
-        ms = HLP.readLen(msg.msg.substr(0, 4))
-        if (ms !== 3) return this.abort()
-        msg = HLP.unpackMPIs(3, msg.msg.substring(4))
-
-        if (!HLP.checkGroup(msg[0], N_MINUS_2)) return this.abort()
-
-        // verify znp of cR
-        t3 = HLP.multPowMod(G, msg[2], this.g3ao, msg[1], N)
-        t4 = HLP.multPowMod(this.QoQ, msg[2], msg[0], msg[1], N)
-        if (!HLP.ZKP(8, msg[1], t3, t4))
-          return this.abort()
-
-        rab = this.computeRab(msg[0])
-        trust = !!BigInt.equals(rab, this.PoP)
-
-        this.trigger('trust', [trust, 'asked'])
-        this.init()
-        return
-
-    }
-
-    this.sendMsg(send)
-  }
-
-  // send a message
-  SM.prototype.sendMsg = function (send) {
-    this.trigger('send', [this.ssid, '\x00' + send])
-  }
-
-  SM.prototype.rcvSecret = function (secret, question) {
-    HLP.debug.call(this, 'receive secret')
-
-    var fn, our = false
-    if (this.smpstate === CONST.SMPSTATE_EXPECT0) {
-      fn = this.answer
-    } else {
-      fn = this.initiate
-      our = true
-    }
-
-    this.makeSecret(our, secret)
-    fn.call(this, question)
-  }
-
-  SM.prototype.answer = function () {
-    HLP.debug.call(this, 'smp answer')
-
-    var r4 = HLP.randomExponent()
-    this.computePQ(r4)
-
-    // zero-knowledge proof that P & Q
-    // were generated according to the protocol
-    var r5 = HLP.randomExponent()
-    var r6 = HLP.randomExponent()
-    var tmp = HLP.multPowMod(G, r5, this.g2, r6, N)
-    var cP = HLP.smpHash(5, BigInt.powMod(this.g3, r5, N), tmp)
-    var d5 = this.computeD(r5, r4, cP)
-    var d6 = this.computeD(r6, this.secret, cP)
-
-    this.smpstate = CONST.SMPSTATE_EXPECT3
-
-    var send = HLP.packINT(11) + HLP.packMPIs([
-        this.g2a
-      , this.c2
-      , this.d2
-      , this.g3a
-      , this.c3
-      , this.d3
-      , this.p
-      , this.q
-      , cP
-      , d5
-      , d6
-    ])
-
-    this.sendMsg(HLP.packTLV(3, send))
-  }
-
-  SM.prototype.initiate = function (question) {
-    HLP.debug.call(this, 'smp initiate')
-
-    if (this.smpstate !== CONST.SMPSTATE_EXPECT1)
-      this.abort()  // abort + restart
-
-    this.makeG2s()
-
-    // zero-knowledge proof that the exponents
-    // associated with g2a & g3a are known
-    var r2 = HLP.randomExponent()
-    var r3 = HLP.randomExponent()
-    this.c2 = this.computeC(1, r2)
-    this.c3 = this.computeC(2, r3)
-    this.d2 = this.computeD(r2, this.a2, this.c2)
-    this.d3 = this.computeD(r3, this.a3, this.c3)
-
-    // set the next expected state
-    this.smpstate = CONST.SMPSTATE_EXPECT2
-
-    var send = ''
-    var type = 2
-
-    if (question) {
-      send += question
-      send += '\x00'
-      type = 7
-    }
-
-    send += HLP.packINT(6) + HLP.packMPIs([
-        this.g2a
-      , this.c2
-      , this.d2
-      , this.g3a
-      , this.c3
-      , this.d3
-    ])
-
-    this.sendMsg(HLP.packTLV(type, send))
-  }
-
-  SM.prototype.abort = function () {
-    this.init()
-    this.sendMsg(HLP.packTLV(6, ''))
-    this.trigger('abort')
-  }
-
-}).call(this)
-;(function () {
-  "use strict";
-
-  var root = this
-
-  var CryptoJS, BigInt, EventEmitter, Worker, SMWPath
-    , CONST, HLP, Parse, AKE, SM, DSA
-  if (typeof module !== 'undefined' && module.exports) {
-    module.exports = OTR
-    CryptoJS = require('../vendor/crypto.js')
-    BigInt = require('../vendor/bigint.js')
-    EventEmitter = require('../vendor/eventemitter.js')
-    SMWPath = require('path').join(__dirname, '/sm-webworker.js')
-    CONST = require('./const.js')
-    HLP = require('./helpers.js')
-    Parse = require('./parse.js')
-    AKE = require('./ake.js')
-    SM = require('./sm.js')
-    DSA = require('./dsa.js')
-    // expose CONST for consistency with docs
-    OTR.CONST = CONST
-  } else {
-    // copy over and expose internals
-    Object.keys(root.OTR).forEach(function (k) {
-      OTR[k] = root.OTR[k]
-    })
-    root.OTR = OTR
-    CryptoJS = root.CryptoJS
-    BigInt = root.BigInt
-    EventEmitter = root.EventEmitter
-    Worker = root.Worker
-    SMWPath = 'sm-webworker.js'
-    CONST = OTR.CONST
-    HLP = OTR.HLP
-    Parse = OTR.Parse
-    AKE = OTR.AKE
-    SM = OTR.SM
-    DSA = root.DSA
-  }
-
-  // diffie-hellman modulus and generator
-  // see group 5, RFC 3526
-  var G = BigInt.str2bigInt(CONST.G, 10)
-  var N = BigInt.str2bigInt(CONST.N, 16)
-
-  // JavaScript integers
-  var MAX_INT = Math.pow(2, 53) - 1  // doubles
-  var MAX_UINT = Math.pow(2, 31) - 1  // bitwise operators
-
-  // OTR contructor
-  function OTR(options) {
-    if (!(this instanceof OTR)) return new OTR(options)
-
-    // options
-    options = options || {}
-
-    // private keys
-    if (options.priv && !(options.priv instanceof DSA))
-      throw new Error('Requires long-lived DSA key.')
-
-    this.priv = options.priv ? options.priv : new DSA()
-
-    this.fragment_size = options.fragment_size || 0
-    if (this.fragment_size < 0)
-      throw new Error('Fragment size must be a positive integer.')
-
-    this.send_interval = options.send_interval || 0
-    if (this.send_interval < 0)
-      throw new Error('Send interval must be a positive integer.')
-
-    this.outgoing = []
-
-    // instance tag
-    this.our_instance_tag = options.instance_tag || OTR.makeInstanceTag()
-
-    // debug
-    this.debug = !!options.debug
-
-    // smp in webworker options
-    // this is still experimental and undocumented
-    this.smw = options.smw
-
-    // init vals
-    this.init()
-
-    // bind methods
-    var self = this
-    ;['sendMsg', 'receiveMsg'].forEach(function (meth) {
-      self[meth] = self[meth].bind(self)
-    })
-
-    EventEmitter.call(this)
-  }
-
-  // inherit from EE
-  HLP.extend(OTR, EventEmitter)
-
-  // add to prototype
-  OTR.prototype.init = function () {
-
-    this.msgstate = CONST.MSGSTATE_PLAINTEXT
-    this.authstate = CONST.AUTHSTATE_NONE
-
-    this.ALLOW_V2 = true
-    this.ALLOW_V3 = true
-
-    this.REQUIRE_ENCRYPTION = false
-    this.SEND_WHITESPACE_TAG = false
-    this.WHITESPACE_START_AKE = false
-    this.ERROR_START_AKE = false
-
-    Parse.initFragment(this)
-
-    // their keys
-    this.their_y = null
-    this.their_old_y = null
-    this.their_keyid = 0
-    this.their_priv_pk = null
-    this.their_instance_tag = '\x00\x00\x00\x00'
-
-    // our keys
-    this.our_dh = this.dh()
-    this.our_old_dh = this.dh()
-    this.our_keyid = 2
-
-    // session keys
-    this.sessKeys = [ new Array(2), new Array(2) ]
-
-    // saved
-    this.storedMgs = []
-    this.oldMacKeys = []
-
-    // smp
-    this.sm = null  // initialized after AKE
-
-    // when ake is complete
-    // save their keys and the session
-    this._akeInit()
-
-    // receive plaintext message since switching to plaintext
-    // used to decide when to stop sending pt tags when SEND_WHITESPACE_TAG
-    this.receivedPlaintext = false
-
-  }
-
-  OTR.prototype._akeInit = function () {
-    this.ake = new AKE(this)
-    this.transmittedRS = false
-    this.ssid = null
-  }
-
-  // smp over webworker
-  OTR.prototype._SMW = function (otr, reqs) {
-    this.otr = otr
-    var opts = {
-        path: SMWPath
-      , seed: BigInt.getSeed
-    }
-    if (typeof otr.smw === 'object')
-      Object.keys(otr.smw).forEach(function (k) {
-        opts[k] = otr.smw[k]
-      })
-
-    // load optional dep. in node
-    if (typeof module !== 'undefined' && module.exports)
-      Worker = require('webworker-threads').Worker
-
-    this.worker = new Worker(opts.path)
-    var self = this
-    this.worker.onmessage = function (e) {
-      var d = e.data
-      if (!d) return
-      self.trigger(d.method, d.args)
-    }
-    this.worker.postMessage({
-        type: 'seed'
-      , seed: opts.seed()
-      , imports: opts.imports
-    })
-    this.worker.postMessage({
-        type: 'init'
-      , reqs: reqs
-    })
-  }
-
-  // inherit from EE
-  HLP.extend(OTR.prototype._SMW, EventEmitter)
-
-  // shim sm methods
-  ;['handleSM', 'rcvSecret', 'abort'].forEach(function (m) {
-    OTR.prototype._SMW.prototype[m] = function () {
-      this.worker.postMessage({
-          type: 'method'
-        , method: m
-        , args: Array.prototype.slice.call(arguments, 0)
-      })
-    }
-  })
-
-  OTR.prototype._smInit = function () {
-    var reqs = {
-        ssid: this.ssid
-      , our_fp: this.priv.fingerprint()
-      , their_fp: this.their_priv_pk.fingerprint()
-      , debug: this.debug
-    }
-    if (this.smw) {
-      if (this.sm) this.sm.worker.terminate()  // destroy prev webworker
-      this.sm = new this._SMW(this, reqs)
-    } else {
-      this.sm = new SM(reqs)
-    }
-    var self = this
-    ;['trust', 'abort', 'question'].forEach(function (e) {
-      self.sm.on(e, function () {
-        self.trigger('smp', [e].concat(Array.prototype.slice.call(arguments)))
-      })
-    })
-    this.sm.on('send', function (ssid, send) {
-      if (self.ssid === ssid) {
-        send = self.prepareMsg(send)
-        self.io(send)
-      }
-    })
-  }
-
-  OTR.prototype.io = function (msg, meta) {
-
-    // buffer
-    msg = ([].concat(msg)).map(function(m){
-       return { msg: m, meta: meta }
-    })
-    this.outgoing = this.outgoing.concat(msg)
-
-    var self = this
-    ;(function send(first) {
-      if (!first) {
-        if (!self.outgoing.length) return
-        var elem = self.outgoing.shift()
-        self.trigger('io', [elem.msg, elem.meta])
-      }
-      setTimeout(send, first ? 0 : self.send_interval)
-    }(true))
-
-  }
-
-  OTR.prototype.dh = function dh() {
-    var keys = { privateKey: BigInt.randBigInt(320) }
-    keys.publicKey = BigInt.powMod(G, keys.privateKey, N)
-    return keys
-  }
-
-  // session constructor
-  OTR.prototype.DHSession = function DHSession(our_dh, their_y) {
-    if (!(this instanceof DHSession)) return new DHSession(our_dh, their_y)
-
-    // shared secret
-    var s = BigInt.powMod(their_y, our_dh.privateKey, N)
-    var secbytes = HLP.packMPI(s)
-
-    // session id
-    this.id = HLP.mask(HLP.h2('\x00', secbytes), 0, 64)  // first 64-bits
-
-    // are we the high or low end of the connection?
-    var sq = BigInt.greater(our_dh.publicKey, their_y)
-    var sendbyte = sq ? '\x01' : '\x02'
-    var rcvbyte  = sq ? '\x02' : '\x01'
-
-    // sending and receiving keys
-    this.sendenc = HLP.mask(HLP.h1(sendbyte, secbytes), 0, 128)  // f16 bytes
-    this.sendmac = CryptoJS.SHA1(CryptoJS.enc.Latin1.parse(this.sendenc))
-    this.sendmac = this.sendmac.toString(CryptoJS.enc.Latin1)
-
-    this.rcvenc = HLP.mask(HLP.h1(rcvbyte, secbytes), 0, 128)
-    this.rcvmac = CryptoJS.SHA1(CryptoJS.enc.Latin1.parse(this.rcvenc))
-    this.rcvmac = this.rcvmac.toString(CryptoJS.enc.Latin1)
-    this.rcvmacused = false
-
-    // extra symmetric key
-    this.extra_symkey = HLP.h2('\xff', secbytes)
-
-    // counters
-    this.send_counter = 0
-    this.rcv_counter = 0
-  }
-
-  OTR.prototype.rotateOurKeys = function () {
-
-    // reveal old mac keys
-    var self = this
-    this.sessKeys[1].forEach(function (sk) {
-      if (sk && sk.rcvmacused) self.oldMacKeys.push(sk.rcvmac)
-    })
-
-    // rotate our keys
-    this.our_old_dh = this.our_dh
-    this.our_dh = this.dh()
-    this.our_keyid += 1
-
-    this.sessKeys[1][0] = this.sessKeys[0][0]
-    this.sessKeys[1][1] = this.sessKeys[0][1]
-    this.sessKeys[0] = [
-        this.their_y ?
-            new this.DHSession(this.our_dh, this.their_y) : null
-      , this.their_old_y ?
-            new this.DHSession(this.our_dh, this.their_old_y) : null
-    ]
-
-  }
-
-  OTR.prototype.rotateTheirKeys = function (their_y) {
-
-    // increment their keyid
-    this.their_keyid += 1
-
-    // reveal old mac keys
-    var self = this
-    this.sessKeys.forEach(function (sk) {
-      if (sk[1] && sk[1].rcvmacused) self.oldMacKeys.push(sk[1].rcvmac)
-    })
-
-    // rotate their keys / session
-    this.their_old_y = this.their_y
-    this.sessKeys[0][1] = this.sessKeys[0][0]
-    this.sessKeys[1][1] = this.sessKeys[1][0]
-
-    // new keys / sessions
-    this.their_y = their_y
-    this.sessKeys[0][0] = new this.DHSession(this.our_dh, this.their_y)
-    this.sessKeys[1][0] = new this.DHSession(this.our_old_dh, this.their_y)
-
-  }
-
-  OTR.prototype.prepareMsg = function (msg, esk) {
-    if (this.msgstate !== CONST.MSGSTATE_ENCRYPTED || this.their_keyid === 0)
-      return this.error('Not ready to encrypt.')
-
-    var sessKeys = this.sessKeys[1][0]
-
-    if (sessKeys.send_counter >= MAX_INT)
-      return this.error('Should have rekeyed by now.')
-
-    sessKeys.send_counter += 1
-
-    var ctr = HLP.packCtr(sessKeys.send_counter)
-
-    var send = this.ake.otr_version + '\x03'  // version and type
-    var v3 = (this.ake.otr_version === CONST.OTR_VERSION_3)
-
-    if (v3) {
-      send += this.our_instance_tag
-      send += this.their_instance_tag
-    }
-
-    send += '\x00'  // flag
-    send += HLP.packINT(this.our_keyid - 1)
-    send += HLP.packINT(this.their_keyid)
-    send += HLP.packMPI(this.our_dh.publicKey)
-    send += ctr.substring(0, 8)
-
-    if (Math.ceil(msg.length / 8) >= MAX_UINT)  // * 16 / 128
-      return this.error('Message is too long.')
-
-    var aes = HLP.encryptAes(
-        CryptoJS.enc.Latin1.parse(msg)
-      , sessKeys.sendenc
-      , ctr
-    )
-
-    send += HLP.packData(aes)
-    send += HLP.make1Mac(send, sessKeys.sendmac)
-    send += HLP.packData(this.oldMacKeys.splice(0).join(''))
-
-    send = HLP.wrapMsg(
-        send
-      , this.fragment_size
-      , v3
-      , this.our_instance_tag
-      , this.their_instance_tag
-    )
-    if (send[0]) return this.error(send[0])
-
-    // emit extra symmetric key
-    if (esk) this.trigger('file', ['send', sessKeys.extra_symkey, esk])
-
-    return send[1]
-  }
-
-  OTR.prototype.handleDataMsg = function (msg) {
-    var vt = msg.version + msg.type
-
-    if (this.ake.otr_version === CONST.OTR_VERSION_3)
-      vt += msg.instance_tags
-
-    var types = ['BYTE', 'INT', 'INT', 'MPI', 'CTR', 'DATA', 'MAC', 'DATA']
-    msg = HLP.splitype(types, msg.msg)
-
-    // ignore flag
-    var ign = (msg[0] === '\x01')
-
-    if (this.msgstate !== CONST.MSGSTATE_ENCRYPTED || msg.length !== 8) {
-      if (!ign) this.error('Received an unreadable encrypted message.', true)
-      return
-    }
-
-    var our_keyid = this.our_keyid - HLP.readLen(msg[2])
-    var their_keyid = this.their_keyid - HLP.readLen(msg[1])
-
-    if (our_keyid < 0 || our_keyid > 1) {
-      if (!ign) this.error('Not of our latest keys.', true)
-      return
-    }
-
-    if (their_keyid < 0 || their_keyid > 1) {
-      if (!ign) this.error('Not of your latest keys.', true)
-      return
-    }
-
-    var their_y = their_keyid ? this.their_old_y : this.their_y
-
-    if (their_keyid === 1 && !their_y) {
-      if (!ign) this.error('Do not have that key.')
-      return
-    }
-
-    var sessKeys = this.sessKeys[our_keyid][their_keyid]
-
-    var ctr = HLP.unpackCtr(msg[4])
-    if (ctr <= sessKeys.rcv_counter) {
-      if (!ign) this.error('Counter in message is not larger.')
-      return
-    }
-    sessKeys.rcv_counter = ctr
-
-    // verify mac
-    vt += msg.slice(0, 6).join('')
-    var vmac = HLP.make1Mac(vt, sessKeys.rcvmac)
-
-    if (!HLP.compare(msg[6], vmac)) {
-      if (!ign) this.error('MACs do not match.')
-      return
-    }
-    sessKeys.rcvmacused = true
-
-    var out = HLP.decryptAes(
-        msg[5].substring(4)
-      , sessKeys.rcvenc
-      , HLP.padCtr(msg[4])
-    )
-    out = out.toString(CryptoJS.enc.Latin1)
-
-    if (!our_keyid) this.rotateOurKeys()
-    if (!their_keyid) this.rotateTheirKeys(HLP.readMPI(msg[3]))
-
-    // parse TLVs
-    var ind = out.indexOf('\x00')
-    if (~ind) {
-      this.handleTLVs(out.substring(ind + 1), sessKeys)
-      out = out.substring(0, ind)
-    }
-
-    out = CryptoJS.enc.Latin1.parse(out)
-    return out.toString(CryptoJS.enc.Utf8)
-  }
-
-  OTR.prototype.handleTLVs = function (tlvs, sessKeys) {
-    var type, len, msg
-    for (; tlvs.length; ) {
-      type = HLP.unpackSHORT(tlvs.substr(0, 2))
-      len = HLP.unpackSHORT(tlvs.substr(2, 2))
-
-      msg = tlvs.substr(4, len)
-
-      // TODO: handle pathological cases better
-      if (msg.length < len) break
-
-      switch (type) {
-        case 1:
-          // Disconnected
-          this.msgstate = CONST.MSGSTATE_FINISHED
-          this.trigger('status', [CONST.STATUS_END_OTR])
-          break
-        case 2: case 3: case 4:
-        case 5: case 6: case 7:
-          // SMP
-          if (this.msgstate !== CONST.MSGSTATE_ENCRYPTED) {
-            if (this.sm) this.sm.abort()
-            return
-          }
-          if (!this.sm) this._smInit()
-          this.sm.handleSM({ msg: msg, type: type })
-          break
-        case 8:
-          // utf8 filenames
-          msg = msg.substring(4) // remove 4-byte indication
-          msg = CryptoJS.enc.Latin1.parse(msg)
-          msg = msg.toString(CryptoJS.enc.Utf8)
-
-          // Extra Symkey
-          this.trigger('file', ['receive', sessKeys.extra_symkey, msg])
-          break
-      }
-
-      tlvs = tlvs.substring(4 + len)
-    }
-  }
-
-  OTR.prototype.smpSecret = function (secret, question) {
-    if (this.msgstate !== CONST.MSGSTATE_ENCRYPTED)
-      return this.error('Must be encrypted for SMP.')
-
-    if (typeof secret !== 'string' || secret.length < 1)
-      return this.error('Secret is required.')
-
-    if (!this.sm) this._smInit()
-
-    // utf8 inputs
-    secret = CryptoJS.enc.Utf8.parse(secret).toString(CryptoJS.enc.Latin1)
-    question = CryptoJS.enc.Utf8.parse(question).toString(CryptoJS.enc.Latin1)
-
-    this.sm.rcvSecret(secret, question)
-  }
-
-  OTR.prototype.sendQueryMsg = function () {
-    var versions = {}
-      , msg = CONST.OTR_TAG
-
-    if (this.ALLOW_V2) versions['2'] = true
-    if (this.ALLOW_V3) versions['3'] = true
-
-    // but we don't allow v1
-    // if (versions['1']) msg += '?'
-
-    var vs = Object.keys(versions)
-    if (vs.length) {
-      msg += 'v'
-      vs.forEach(function (v) {
-        if (v !== '1') msg += v
-      })
-      msg += '?'
-    }
-
-    this.io(msg)
-    this.trigger('status', [CONST.STATUS_SEND_QUERY])
-  }
-
-  OTR.prototype.sendMsg = function (msg, meta) {
-    if ( this.REQUIRE_ENCRYPTION ||
-         this.msgstate !== CONST.MSGSTATE_PLAINTEXT
-    ) {
-      msg = CryptoJS.enc.Utf8.parse(msg)
-      msg = msg.toString(CryptoJS.enc.Latin1)
-    }
-
-    switch (this.msgstate) {
-      case CONST.MSGSTATE_PLAINTEXT:
-        if (this.REQUIRE_ENCRYPTION) {
-          this.storedMgs.push({msg: msg, meta: meta})
-          this.sendQueryMsg()
-          return
-        }
-        if (this.SEND_WHITESPACE_TAG && !this.receivedPlaintext) {
-          msg += CONST.WHITESPACE_TAG  // 16 byte tag
-          if (this.ALLOW_V3) msg += CONST.WHITESPACE_TAG_V3
-          if (this.ALLOW_V2) msg += CONST.WHITESPACE_TAG_V2
-        }
-        break
-      case CONST.MSGSTATE_FINISHED:
-        this.storedMgs.push({msg: msg, meta: meta})
-        this.error('Message cannot be sent at this time.')
-        return
-      case CONST.MSGSTATE_ENCRYPTED:
-        msg = this.prepareMsg(msg)
-        break
-      default:
-        throw new Error('Unknown message state.')
-    }
-
-    if (msg) this.io(msg, meta)
-  }
-
-  OTR.prototype.receiveMsg = function (msg) {
-
-    // parse type
-    msg = Parse.parseMsg(this, msg)
-
-    if (!msg) return
-
-    switch (msg.cls) {
-      case 'error':
-        this.error(msg.msg)
-        return
-      case 'ake':
-        if ( msg.version === CONST.OTR_VERSION_3 &&
-          this.checkInstanceTags(msg.instance_tags)
-        ) return  // ignore
-        this.ake.handleAKE(msg)
-        return
-      case 'data':
-        if ( msg.version === CONST.OTR_VERSION_3 &&
-          this.checkInstanceTags(msg.instance_tags)
-        ) return  // ignore
-        msg.msg = this.handleDataMsg(msg)
-        msg.encrypted = true
-        break
-      case 'query':
-        if (this.msgstate === CONST.MSGSTATE_ENCRYPTED) this._akeInit()
-        this.doAKE(msg)
-        break
-      default:
-        // check for encrypted
-        if ( this.REQUIRE_ENCRYPTION ||
-             this.msgstate !== CONST.MSGSTATE_PLAINTEXT
-        ) this.error('Received an unencrypted message.')
-
-        // received a plaintext message
-        // stop sending the whitespace tag
-        this.receivedPlaintext = true
-
-        // received a whitespace tag
-        if (this.WHITESPACE_START_AKE && msg.ver.length > 0)
-          this.doAKE(msg)
-    }
-
-    if (msg.msg) this.trigger('ui', [msg.msg, !!msg.encrypted])
-  }
-
-  OTR.prototype.checkInstanceTags = function (it) {
-    var their_it = HLP.readLen(it.substr(0, 4))
-    var our_it = HLP.readLen(it.substr(4, 4))
-
-    if (our_it && our_it !== HLP.readLen(this.our_instance_tag))
-      return true
-
-    if (HLP.readLen(this.their_instance_tag)) {
-      if (HLP.readLen(this.their_instance_tag) !== their_it) return true
-    } else {
-      if (their_it < 100) return true
-      this.their_instance_tag = HLP.packINT(their_it)
-    }
-  }
-
-  OTR.prototype.doAKE = function (msg) {
-    if (this.ALLOW_V3 && ~msg.ver.indexOf(CONST.OTR_VERSION_3)) {
-      this.ake.initiateAKE(CONST.OTR_VERSION_3)
-    } else if (this.ALLOW_V2 && ~msg.ver.indexOf(CONST.OTR_VERSION_2)) {
-      this.ake.initiateAKE(CONST.OTR_VERSION_2)
-    } else {
-      // is this an error?
-      this.error('OTR conversation requested, ' +
-        'but no compatible protocol version found.')
-    }
-  }
-
-  OTR.prototype.error = function (err, send) {
-    if (send) {
-      if (!this.debug) err = "An OTR error has occurred."
-      err = '?OTR Error:' + err
-      this.io(err)
-      return
-    }
-    this.trigger('error', [err])
-  }
-
-  OTR.prototype.sendStored = function () {
-    var self = this
-    ;(this.storedMgs.splice(0)).forEach(function (elem) {
-      var msg = self.prepareMsg(elem.msg)
-      self.io(msg, elem.meta)
-    })
-  }
-
-  OTR.prototype.sendFile = function (filename) {
-    if (this.msgstate !== CONST.MSGSTATE_ENCRYPTED)
-      return this.error('Not ready to encrypt.')
-
-    if (this.ake.otr_version !== CONST.OTR_VERSION_3)
-      return this.error('Protocol v3 required.')
-
-    if (!filename) return this.error('Please specify a filename.')
-
-    // utf8 filenames
-    var l1name = CryptoJS.enc.Utf8.parse(filename)
-    l1name = l1name.toString(CryptoJS.enc.Latin1)
-
-    if (l1name.length >= 65532) return this.error('filename is too long.')
-
-    var msg = '\x00'  // null byte
-    msg += '\x00\x08'  // type 8 tlv
-    msg += HLP.packSHORT(4 + l1name.length)  // length of value
-    msg += '\x00\x00\x00\x01'  // four bytes indicating file
-    msg += l1name
-
-    msg = this.prepareMsg(msg, filename)
-    this.io(msg)
-  }
-
-  OTR.prototype.endOtr = function () {
-    if (this.msgstate === CONST.MSGSTATE_ENCRYPTED) {
-      this.sendMsg('\x00\x00\x01\x00\x00')
-      if (this.sm) {
-        if (this.smw) this.sm.worker.terminate()  // destroy webworker
-        this.sm = null
-      }
-    }
-    this.msgstate = CONST.MSGSTATE_PLAINTEXT
-    this.receivedPlaintext = false
-    this.trigger('status', [CONST.STATUS_END_OTR])
-  }
-
-  // attach methods
-
-  OTR.makeInstanceTag = function () {
-    var num = BigInt.randBigInt(32)
-    if (BigInt.greater(BigInt.str2bigInt('100', 16), num))
-      return OTR.makeInstanceTag()
-    return HLP.packINT(parseInt(BigInt.bigInt2str(num, 10), 10))
-  }
-
-}).call(this)
-
-
-  return {
-      OTR: this.OTR
-    , DSA: this.DSA
-  }
-
-}))

+ 16 - 25
config.js

@@ -67,21 +67,23 @@ require.config({
         "converse-vcard":           "src/converse-vcard",
 
         // Off-the-record-encryption
-        "bigint":               "3rdparty/bigint",
-        "crypto":               "3rdparty/crypto",
-        "crypto.aes":           "node_modules/otr/vendor/cryptojs/aes",
-        "crypto.cipher-core":   "node_modules/otr/vendor/cryptojs/cipher-core",
-        "crypto.core":          "node_modules/otr/vendor/cryptojs/core",
-        "crypto.enc-base64":    "node_modules/otr/vendor/cryptojs/enc-base64",
-        "crypto.evpkdf":        "components/crypto-js-evanvosberg/src/evpkdf",
-        "crypto.hmac":          "node_modules/otr/vendor/cryptojs/hmac",
-        "crypto.md5":           "components/crypto-js-evanvosberg/src/md5",
-        "crypto.mode-ctr":      "node_modules/otr/vendor/cryptojs/mode-ctr",
-        "crypto.pad-nopadding": "node_modules/otr/vendor/cryptojs/pad-nopadding",
-        "crypto.sha1":          "node_modules/otr/vendor/cryptojs/sha1",
-        "crypto.sha256":        "node_modules/otr/vendor/cryptojs/sha256",
+        "bigint":               "node_modules/otr/vendor/bigint",
+        "crypto":               "node_modules/otr/build/dep/crypto",
+        "aes":                  "node_modules/crypto-js/aes",
+        "cipher-core":          "node_modules/crypto-js/cipher-core",
+        "core":                 "node_modules/crypto-js/core",
+        "const":                "node_modules/otr/lib/const",
+        "helpers":              "node_modules/otr/lib/helpers",
+        "sha1":                 "node_modules/crypto-js/sha1",
+        "hmac":                 "node_modules/crypto-js/hmac",
+        "enc-base64":           "node_modules/crypto-js/enc-base64",
+        "evpkdf":               "node_modules/crypto-js/evpkdf",
+        "md5":                  "node_modules/crypto-js/md5",
+        "mode-ctr":             "node_modules/crypto-js/mode-ctr",
+        "pad-nopadding":        "node_modules/crypto-js/pad-nopadding",
+        "sha256":               "node_modules/crypto-js/sha256",
         "salsa20":              "node_modules/otr/build/dep/salsa20",
-        "otr":                  "3rdparty/otr",
+        "otr":                  "node_modules/otr/build/otr",
 
         // Locales paths
         "locales":   "src/locales",
@@ -215,17 +217,6 @@ require.config({
     shim: {
         'awesomplete':          { exports: 'Awesomplete' },
         'backbone':             { deps: ['underscore'] },
-        'bigint':               { deps: ['crypto'] },
-        'crypto.aes':           { deps: ['crypto.cipher-core'] },
-        'crypto.cipher-core':   { deps: ['crypto.enc-base64', 'crypto.evpkdf'] },
-        'crypto.enc-base64':    { deps: ['crypto.core'] },
-        'crypto.evpkdf':        { deps: ['crypto.md5'] },
-        'crypto.hmac':          { deps: ['crypto.core'] },
-        'crypto.md5':           { deps: ['crypto.core'] },
-        'crypto.mode-ctr':      { deps: ['crypto.cipher-core'] },
-        'crypto.pad-nopadding': { deps: ['crypto.cipher-core'] },
-        'crypto.sha1':          { deps: ['crypto.core'] },
-        'crypto.sha256':        { deps: ['crypto.core'] },
         'strophe.ping':         { deps: ['strophe'] },
         'strophe.register':     { deps: ['strophe'] },
         'strophe.vcard':        { deps: ['strophe'] },

+ 2 - 0
src/converse-chatview.js

@@ -830,4 +830,6 @@
             });
         }
     });
+
+    return converse;
 }));

+ 9 - 2
src/converse-otr.js

@@ -10,9 +10,16 @@
  * encryption of one-on-one chat messages.
  */
 (function (root, factory) {
-    define(["otr", "converse-core", "tpl!toolbar_otr"], factory);
-}(this, function (otr, converse, tpl_toolbar_otr) {
+
+    define(["converse-chatview",
+            "tpl!toolbar_otr",
+            'otr',
+            'crypto',
+            'aes'
+    ], factory);
+}(this, function (converse, tpl_toolbar_otr, otr, CryptoJS) {
     "use strict";
+
     // Strophe methods for building stanzas
     var Strophe = converse.env.Strophe,
         utils = converse.env.utils,