docs: function (input, dir) {
      if (input.length !== 4) {
        throw new sjcl.exception.invalid("invalid aes block size");
      }
  
      var key = this._key[dir],
          // state variables a,b,c,d are loaded with pre-whitened data
          a = input[0]           ^ key[0],
          b = input[dir ? 3 : 1] ^ key[1],
          c = input[2]           ^ key[2],
          d = input[dir ? 1 : 3] ^ key[3],
          a2, b2, c2,
  
          nInnerRounds = key.length/4 - 2,
          i,
          kIndex = 4,
          out = [0,0,0,0],
          table = this._tables[dir],
  
          // load up the tables
          t0    = table[0],
          t1    = table[1],
          t2    = table[2],
          t3    = table[3],
          sbox  = table[4];
  
      // Inner rounds.  Cribbed from OpenSSL.
      for (i = 0; i < nInnerRounds; i++) {
        a2 = t0[a>>>24] ^ t1[b>>16 & 255] ^ t2[c>>8 & 255] ^ t3[d & 255] ^ key[kIndex];
        b2 = t0[b>>>24] ^ t1[c>>16 & 255] ^ t2[d>>8 & 255] ^ t3[a & 255] ^ key[kIndex + 1];
        c2 = t0[c>>>24] ^ t1[d>>16 & 255] ^ t2[a>>8 & 255] ^ t3[b & 255] ^ key[kIndex + 2];
        d  = t0[d>>>24] ^ t1[a>>16 & 255] ^ t2[b>>8 & 255] ^ t3[c & 255] ^ key[kIndex + 3];
        kIndex += 4;
        a=a2; b=b2; c=c2;
      }
  
      // Last round.
      for (i = 0; i < 4; i++) {
        out[dir ? 3&-i : i] =
          sbox[a>>>24      ]<<24 ^
          sbox[b>>16  & 255]<<16 ^
          sbox[c>>8   & 255]<<8  ^
          sbox[d      & 255]     ^
          key[kIndex++];
        a2=a; a=b; b=c; c=d; d=a2;
      }
  
      return out;
    }