// Generated by IcedCoffeeScript 1.7.1-f
(function() {
  var Global, Hasher, SHA3, WordArray, X64Word, X64WordArray, glbl, _ref,
    __hasProp = {}.hasOwnProperty,
    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

  _ref = require('./wordarray'), WordArray = _ref.WordArray, X64Word = _ref.X64Word, X64WordArray = _ref.X64WordArray;

  Hasher = require('./algbase').Hasher;

  Global = (function() {
    function Global() {
      this.RHO_OFFSETS = [];
      this.PI_INDEXES = [];
      this.ROUND_CONSTANTS = [];
      this.T = [];
      this.compute_rho_offsets();
      this.compute_pi_indexes();
      this.compute_round_constants();
      this.make_reusables();
    }

    Global.prototype.compute_rho_offsets = function() {
      var newX, newY, t, x, y, _i, _results;
      x = 1;
      y = 0;
      _results = [];
      for (t = _i = 0; _i < 24; t = ++_i) {
        this.RHO_OFFSETS[x + 5 * y] = ((t + 1) * (t + 2) / 2) % 64;
        newX = y % 5;
        newY = (2 * x + 3 * y) % 5;
        x = newX;
        _results.push(y = newY);
      }
      return _results;
    };

    Global.prototype.compute_pi_indexes = function() {
      var x, y, _i, _results;
      _results = [];
      for (x = _i = 0; _i < 5; x = ++_i) {
        _results.push((function() {
          var _j, _results1;
          _results1 = [];
          for (y = _j = 0; _j < 5; y = ++_j) {
            _results1.push(this.PI_INDEXES[x + 5 * y] = y + ((2 * x + 3 * y) % 5) * 5);
          }
          return _results1;
        }).call(this));
      }
      return _results;
    };

    Global.prototype.compute_round_constants = function() {
      var LFSR, bitPosition, i, j, roundConstantLsw, roundConstantMsw, _i, _j, _results;
      LFSR = 0x01;
      _results = [];
      for (i = _i = 0; _i < 24; i = ++_i) {
        roundConstantMsw = 0;
        roundConstantLsw = 0;
        for (j = _j = 0; _j < 7; j = ++_j) {
          if (LFSR & 0x01) {
            bitPosition = (1 << j) - 1;
            if (bitPosition < 32) {
              roundConstantLsw ^= 1 << bitPosition;
            } else {
              roundConstantMsw ^= 1 << (bitPosition - 32);
            }
          }
          if (LFSR & 0x80) {
            LFSR = (LFSR << 1) ^ 0x71;
          } else {
            LFSR <<= 1;
          }
        }
        _results.push(this.ROUND_CONSTANTS[i] = new X64Word(roundConstantMsw, roundConstantLsw));
      }
      return _results;
    };

    Global.prototype.make_reusables = function() {
      var i;
      return this.T = (function() {
        var _i, _results;
        _results = [];
        for (i = _i = 0; _i < 25; i = ++_i) {
          _results.push(new X64Word(0, 0));
        }
        return _results;
      })();
    };

    return Global;

  })();

  glbl = new Global();

  exports.SHA3 = SHA3 = (function(_super) {
    __extends(SHA3, _super);

    function SHA3() {
      return SHA3.__super__.constructor.apply(this, arguments);
    }

    SHA3.outputLength = 512;

    SHA3.prototype.outputLength = SHA3.outputLength;

    SHA3.blockSize = (1600 - 2 * SHA3.outputLength) / 32;

    SHA3.prototype.blockSize = SHA3.blockSize;

    SHA3.output_size = SHA3.outputLength / 8;

    SHA3.prototype.output_size = SHA3.output_size;

    SHA3.prototype._doReset = function() {
      var i;
      return this._state = (function() {
        var _i, _results;
        _results = [];
        for (i = _i = 0; _i < 25; i = ++_i) {
          _results.push(new X64Word(0, 0));
        }
        return _results;
      })();
    };

    SHA3.prototype._doProcessBlock = function(M, offset) {
      var G, M2i, M2i1, T0, TLane, TPiLane, Tx, Tx1, Tx1Lane, Tx1Lsw, Tx1Msw, Tx2Lane, Tx4, i, lane, laneIndex, laneLsw, laneMsw, nBlockSizeLanes, rhoOffset, round, roundConstant, state, state0, tLsw, tMsw, x, y, _i, _j, _k, _l, _m, _n, _o, _p, _q, _results;
      G = glbl;
      state = this._state;
      nBlockSizeLanes = this.blockSize / 2;
      for (i = _i = 0; 0 <= nBlockSizeLanes ? _i < nBlockSizeLanes : _i > nBlockSizeLanes; i = 0 <= nBlockSizeLanes ? ++_i : --_i) {
        M2i = M[offset + 2 * i];
        M2i1 = M[offset + 2 * i + 1];
        M2i = (((M2i << 8) | (M2i >>> 24)) & 0x00ff00ff) | (((M2i << 24) | (M2i >>> 8)) & 0xff00ff00);
        M2i1 = (((M2i1 << 8) | (M2i1 >>> 24)) & 0x00ff00ff) | (((M2i1 << 24) | (M2i1 >>> 8)) & 0xff00ff00);
        lane = state[i];
        lane.high ^= M2i1;
        lane.low ^= M2i;
      }
      _results = [];
      for (round = _j = 0; _j < 24; round = ++_j) {
        for (x = _k = 0; _k < 5; x = ++_k) {
          tMsw = tLsw = 0;
          for (y = _l = 0; _l < 5; y = ++_l) {
            lane = state[x + 5 * y];
            tMsw ^= lane.high;
            tLsw ^= lane.low;
          }
          Tx = G.T[x];
          Tx.high = tMsw;
          Tx.low = tLsw;
        }
        for (x = _m = 0; _m < 5; x = ++_m) {
          Tx4 = G.T[(x + 4) % 5];
          Tx1 = G.T[(x + 1) % 5];
          Tx1Msw = Tx1.high;
          Tx1Lsw = Tx1.low;
          tMsw = Tx4.high ^ ((Tx1Msw << 1) | (Tx1Lsw >>> 31));
          tLsw = Tx4.low ^ ((Tx1Lsw << 1) | (Tx1Msw >>> 31));
          for (y = _n = 0; _n < 5; y = ++_n) {
            lane = state[x + 5 * y];
            lane.high ^= tMsw;
            lane.low ^= tLsw;
          }
        }
        for (laneIndex = _o = 1; _o < 25; laneIndex = ++_o) {
          lane = state[laneIndex];
          laneMsw = lane.high;
          laneLsw = lane.low;
          rhoOffset = G.RHO_OFFSETS[laneIndex];
          if (rhoOffset < 32) {
            tMsw = (laneMsw << rhoOffset) | (laneLsw >>> (32 - rhoOffset));
            tLsw = (laneLsw << rhoOffset) | (laneMsw >>> (32 - rhoOffset));
          } else {
            tMsw = (laneLsw << (rhoOffset - 32)) | (laneMsw >>> (64 - rhoOffset));
            tLsw = (laneMsw << (rhoOffset - 32)) | (laneLsw >>> (64 - rhoOffset));
          }
          TPiLane = G.T[G.PI_INDEXES[laneIndex]];
          TPiLane.high = tMsw;
          TPiLane.low = tLsw;
        }
        T0 = G.T[0];
        state0 = state[0];
        T0.high = state0.high;
        T0.low = state0.low;
        for (x = _p = 0; _p < 5; x = ++_p) {
          for (y = _q = 0; _q < 5; y = ++_q) {
            laneIndex = x + 5 * y;
            lane = state[laneIndex];
            TLane = G.T[laneIndex];
            Tx1Lane = G.T[((x + 1) % 5) + 5 * y];
            Tx2Lane = G.T[((x + 2) % 5) + 5 * y];
            lane.high = TLane.high ^ (~Tx1Lane.high & Tx2Lane.high);
            lane.low = TLane.low ^ (~Tx1Lane.low & Tx2Lane.low);
          }
        }
        lane = state[0];
        roundConstant = G.ROUND_CONSTANTS[round];
        lane.high ^= roundConstant.high;
        _results.push(lane.low ^= roundConstant.low);
      }
      return _results;
    };

    SHA3.prototype._doFinalize = function() {
      var blockSizeBits, data, dataWords, hashWords, i, lane, laneLsw, laneMsw, nBitsLeft, nBitsTotal, outputLengthBytes, outputLengthLanes, state, _i;
      data = this._data;
      dataWords = data.words;
      nBitsTotal = this._nDataBytes * 8;
      nBitsLeft = data.sigBytes * 8;
      blockSizeBits = this.blockSize * 32;
      dataWords[nBitsLeft >>> 5] |= 0x1 << (24 - nBitsLeft % 32);
      dataWords[((Math.ceil((nBitsLeft + 1) / blockSizeBits) * blockSizeBits) >>> 5) - 1] |= 0x80;
      data.sigBytes = dataWords.length * 4;
      this._process();
      state = this._state;
      outputLengthBytes = this.outputLength / 8;
      outputLengthLanes = outputLengthBytes / 8;
      hashWords = [];
      for (i = _i = 0; 0 <= outputLengthLanes ? _i < outputLengthLanes : _i > outputLengthLanes; i = 0 <= outputLengthLanes ? ++_i : --_i) {
        lane = state[i];
        laneMsw = lane.high;
        laneLsw = lane.low;
        laneMsw = (((laneMsw << 8) | (laneMsw >>> 24)) & 0x00ff00ff) | (((laneMsw << 24) | (laneMsw >>> 8)) & 0xff00ff00);
        laneLsw = (((laneLsw << 8) | (laneLsw >>> 24)) & 0x00ff00ff) | (((laneLsw << 24) | (laneLsw >>> 8)) & 0xff00ff00);
        hashWords.push(laneLsw);
        hashWords.push(laneMsw);
      }
      return new WordArray(hashWords, outputLengthBytes);
    };

    SHA3.prototype.copy_to = function(obj) {
      var s;
      SHA3.__super__.copy_to.call(this, obj);
      return obj._state = (function() {
        var _i, _len, _ref1, _results;
        _ref1 = this._state;
        _results = [];
        for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
          s = _ref1[_i];
          _results.push(s.clone());
        }
        return _results;
      }).call(this);
    };

    SHA3.prototype.scrub = function() {};

    SHA3.prototype.clone = function() {
      var out;
      out = new SHA3();
      this.copy_to(out);
      return out;
    };

    return SHA3;

  })(Hasher);

  exports.transform = function(x) {
    var out;
    out = (new SHA3).finalize(x);
    x.scrub();
    return out;
  };

}).call(this);
