// Generated by IcedCoffeeScript 1.7.1-f
(function() {
  var HMAC_SHA256, Salsa20InnerCore, Scrypt, Timer, WordArray, blkcpy, blkxor, default_delay, endian_reverse, fixup_uint32, iced, pbkdf2, scrub_vec, scrypt, timer, ui8a_to_buffer, v_endian_reverse, __iced_k, __iced_k_noop, _ref, _ref1, _ref2;

  iced = require('iced-runtime');
  __iced_k = __iced_k_noop = function() {};

  HMAC_SHA256 = require('./hmac').HMAC_SHA256;

  pbkdf2 = require('./pbkdf2').pbkdf2;

  _ref = require('./salsa20'), endian_reverse = _ref.endian_reverse, Salsa20InnerCore = _ref.Salsa20InnerCore;

  _ref1 = require('./wordarray'), ui8a_to_buffer = _ref1.ui8a_to_buffer, WordArray = _ref1.WordArray;

  _ref2 = require('./util'), fixup_uint32 = _ref2.fixup_uint32, default_delay = _ref2.default_delay, scrub_vec = _ref2.scrub_vec;

  Timer = (function() {
    function Timer() {
      this.tot = 0;
    }

    Timer.prototype.start = function() {
      return this._t = Date.now();
    };

    Timer.prototype.stop = function() {
      return this.tot += Date.now() - this._t;
    };

    return Timer;

  })();

  timer = new Timer();

  blkcpy = function(D, S, d_offset, s_offset, len) {
    "use asm";
    var end, i, j;
    j = (d_offset << 4) | 0;
    i = (s_offset << 4) | 0;
    end = (i + (len << 4)) | 0;
    while (i < end) {
      D[j] = S[i];
      D[j + 1] = S[i + 1];
      D[j + 2] = S[i + 2];
      D[j + 3] = S[i + 3];
      D[j + 4] = S[i + 4];
      D[j + 5] = S[i + 5];
      D[j + 6] = S[i + 6];
      D[j + 7] = S[i + 7];
      D[j + 8] = S[i + 8];
      D[j + 9] = S[i + 9];
      D[j + 10] = S[i + 10];
      D[j + 11] = S[i + 11];
      D[j + 12] = S[i + 12];
      D[j + 13] = S[i + 13];
      D[j + 14] = S[i + 14];
      D[j + 15] = S[i + 15];
      i += 16;
      j += 16;
    }
    return true;
  };

  blkxor = function(D, S, s_offset, len) {
    "use asm";
    var i, j;
    len = (len << 4) | 0;
    i = 0;
    j = (s_offset << 4) | 0;
    while (i < len) {
      D[i] ^= S[j];
      D[i + 1] ^= S[j + 1];
      D[i + 2] ^= S[j + 2];
      D[i + 3] ^= S[j + 3];
      D[i + 4] ^= S[j + 4];
      D[i + 5] ^= S[j + 5];
      D[i + 6] ^= S[j + 6];
      D[i + 7] ^= S[j + 7];
      D[i + 8] ^= S[j + 8];
      D[i + 9] ^= S[j + 9];
      D[i + 10] ^= S[j + 10];
      D[i + 11] ^= S[j + 11];
      D[i + 12] ^= S[j + 12];
      D[i + 13] ^= S[j + 13];
      D[i + 14] ^= S[j + 14];
      D[i + 15] ^= S[j + 15];
      i += 16;
      j += 16;
    }
    return true;
  };

  v_endian_reverse = function(v) {
    var e, i, _i, _len;
    for (i = _i = 0, _len = v.length; _i < _len; i = ++_i) {
      e = v[i];
      v[i] = endian_reverse(e);
    }
    return true;
  };

  Scrypt = (function() {
    function Scrypt(_arg) {
      var N, c, c0, c1;
      N = _arg.N, this.r = _arg.r, this.p = _arg.p, c = _arg.c, c0 = _arg.c0, c1 = _arg.c1, this.klass = _arg.klass;
      this.N || (this.N = 1 << (N || 15));
      this.r || (this.r = 8);
      this.p || (this.p = 1);
      this.c0 = c0 || c || 1;
      this.c1 = c1 || c || 1;
      this.klass || (this.klass = HMAC_SHA256);
      this.X16_tmp = new Int32Array(0x10);
      this.s20ic = new Salsa20InnerCore(8);
    }

    Scrypt.prototype.salsa20_8 = function(B) {
      var X, i, x, _i, _len;
      X = this.s20ic._core(B);
      for (i = _i = 0, _len = X.length; _i < _len; i = ++_i) {
        x = X[i];
        B[i] += x;
      }
      return true;
    };

    Scrypt.prototype.pbkdf2 = function(_arg, cb) {
      var c, dkLen, key, progress_hook, salt, wa, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      key = _arg.key, salt = _arg.salt, dkLen = _arg.dkLen, progress_hook = _arg.progress_hook, c = _arg.c;
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/home/max/src/keybase/triplesec/src/scrypt.iced",
            funcname: "Scrypt.pbkdf2"
          });
          pbkdf2({
            key: key,
            salt: salt,
            c: c,
            dkLen: dkLen,
            klass: _this.klass,
            progress_hook: progress_hook
          }, __iced_deferrals.defer({
            assign_fn: (function() {
              return function() {
                return wa = arguments[0];
              };
            })(),
            lineno: 113
          }));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          return cb(wa);
        };
      })(this));
    };

    Scrypt.prototype.blockmix_salsa8 = function(B, Y) {
      var X, i, _i, _ref3;
      X = this.X16_tmp;
      blkcpy(X, B, 0, 2 * this.r - 1, 1);
      for (i = _i = 0, _ref3 = 2 * this.r; 0 <= _ref3 ? _i < _ref3 : _i > _ref3; i = 0 <= _ref3 ? ++_i : --_i) {
        blkxor(X, B, i, 1);
        this.salsa20_8(X);
        blkcpy(Y, X, i, 0, 1);
      }
      i = 0;
      while (i < this.r) {
        blkcpy(B, Y, i, i * 2, 1);
        i++;
      }
      i = 0;
      while (i < this.r) {
        blkcpy(B, Y, i + this.r, i * 2 + 1, 1);
        i++;
      }
      return true;
    };

    Scrypt.prototype.smix = function(_arg, cb) {
      var B, V, X, XY, Y, i, j, lim, progress_hook, stop, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      B = _arg.B, V = _arg.V, XY = _arg.XY, progress_hook = _arg.progress_hook;
      X = XY;
      lim = 2 * this.r;
      Y = XY.subarray(0x10 * lim);
      blkcpy(X, B, 0, 0, lim);
      i = 0;
      (function(_this) {
        return (function(__iced_k) {
          var _results, _while;
          _results = [];
          _while = function(__iced_k) {
            var _break, _continue, _next;
            _break = function() {
              return __iced_k(_results);
            };
            _continue = function() {
              return iced.trampoline(function() {
                return _while(__iced_k);
              });
            };
            _next = function(__iced_next_arg) {
              _results.push(__iced_next_arg);
              return _continue();
            };
            if (!(i < _this.N)) {
              return _break();
            } else {
              stop = Math.min(_this.N, i + 2048);
              while (i < stop) {
                blkcpy(V, X, lim * i, 0, lim);
                _this.blockmix_salsa8(X, Y);
                i++;
              }
              if (typeof progress_hook === "function") {
                progress_hook(i);
              }
              (function(__iced_k) {
                __iced_deferrals = new iced.Deferrals(__iced_k, {
                  parent: ___iced_passed_deferral,
                  filename: "/home/max/src/keybase/triplesec/src/scrypt.iced",
                  funcname: "Scrypt.smix"
                });
                default_delay(0, 0, __iced_deferrals.defer({
                  lineno: 170
                }));
                __iced_deferrals._fulfill();
              })(_next);
            }
          };
          _while(__iced_k);
        });
      })(this)((function(_this) {
        return function() {
          i = 0;
          (function(__iced_k) {
            var _results, _while;
            _results = [];
            _while = function(__iced_k) {
              var _break, _continue, _next;
              _break = function() {
                return __iced_k(_results);
              };
              _continue = function() {
                return iced.trampoline(function() {
                  return _while(__iced_k);
                });
              };
              _next = function(__iced_next_arg) {
                _results.push(__iced_next_arg);
                return _continue();
              };
              if (!(i < _this.N)) {
                return _break();
              } else {
                stop = Math.min(_this.N, i + 256);
                while (i < stop) {
                  j = fixup_uint32(X[0x10 * (lim - 1)]) & (_this.N - 1);
                  blkxor(X, V, j * lim, lim);
                  _this.blockmix_salsa8(X, Y);
                  i++;
                }
                if (typeof progress_hook === "function") {
                  progress_hook(i + _this.N);
                }
                (function(__iced_k) {
                  __iced_deferrals = new iced.Deferrals(__iced_k, {
                    parent: ___iced_passed_deferral,
                    filename: "/home/max/src/keybase/triplesec/src/scrypt.iced",
                    funcname: "Scrypt.smix"
                  });
                  default_delay(0, 0, __iced_deferrals.defer({
                    lineno: 187
                  }));
                  __iced_deferrals._fulfill();
                })(_next);
              }
            };
            _while(__iced_k);
          })(function() {
            blkcpy(B, X, 0, 0, lim);
            return cb();
          });
        };
      })(this));
    };

    Scrypt.prototype.run = function(_arg, cb) {
      var B, MAX, V, XY, dkLen, err, j, key, lph, out, progress_hook, ret, salt, ___iced_passed_deferral, __iced_deferrals, __iced_k, _begin, _end, _positive;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      key = _arg.key, salt = _arg.salt, dkLen = _arg.dkLen, progress_hook = _arg.progress_hook;
      MAX = 0xffffffff;
      err = ret = null;
      err = dkLen > MAX ? err = new Error("asked for too much data") : this.r * this.p >= (1 << 30) ? new Error("r & p are too big") : (this.r > MAX / 128 / this.p) || (this.r > MAX / 256) || (this.N > MAX / 128 / this.r) ? new Error("N is too big") : null;
      XY = new Int32Array(64 * this.r);
      V = new Int32Array(32 * this.r * this.N);
      lph = function(o) {
        o.what += " (pass 1)";
        return typeof progress_hook === "function" ? progress_hook(o) : void 0;
      };
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/home/max/src/keybase/triplesec/src/scrypt.iced",
            funcname: "Scrypt.run"
          });
          _this.pbkdf2({
            key: key.clone(),
            salt: salt,
            dkLen: 128 * _this.r * _this.p,
            c: _this.c0,
            progress_hook: lph
          }, __iced_deferrals.defer({
            assign_fn: (function() {
              return function() {
                return B = arguments[0];
              };
            })(),
            lineno: 218
          }));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          B = new Int32Array(B.words);
          v_endian_reverse(B);
          lph = function(j) {
            return function(i) {
              return typeof progress_hook === "function" ? progress_hook({
                i: i + j * _this.N * 2,
                what: "scrypt",
                total: _this.p * _this.N * 2
              }) : void 0;
            };
          };
          (function(__iced_k) {
            var _i, _results, _while;
            j = 0;
            _begin = 0;
            _end = _this.p;
            _positive = _end > _begin;
            _results = [];
            _while = function(__iced_k) {
              var _break, _continue, _next;
              _break = function() {
                return __iced_k(_results);
              };
              _continue = function() {
                return iced.trampoline(function() {
                  if (_positive) {
                    j += 1;
                  } else {
                    j -= 1;
                  }
                  return _while(__iced_k);
                });
              };
              _next = function(__iced_next_arg) {
                _results.push(__iced_next_arg);
                return _continue();
              };
              if (!!((_positive === true && j >= _this.p) || (_positive === false && j <= _this.p))) {
                return _break();
              } else {

                (function(__iced_k) {
                  __iced_deferrals = new iced.Deferrals(__iced_k, {
                    parent: ___iced_passed_deferral,
                    filename: "/home/max/src/keybase/triplesec/src/scrypt.iced",
                    funcname: "Scrypt.run"
                  });
                  _this.smix({
                    B: B.subarray(32 * _this.r * j),
                    V: V,
                    XY: XY,
                    progress_hook: lph(j)
                  }, __iced_deferrals.defer({
                    lineno: 225
                  }));
                  __iced_deferrals._fulfill();
                })(_next);
              }
            };
            _while(__iced_k);
          })(function() {
            v_endian_reverse(B);
            lph = function(o) {
              o.what += " (pass 2)";
              return typeof progress_hook === "function" ? progress_hook(o) : void 0;
            };
            (function(__iced_k) {
              __iced_deferrals = new iced.Deferrals(__iced_k, {
                parent: ___iced_passed_deferral,
                filename: "/home/max/src/keybase/triplesec/src/scrypt.iced",
                funcname: "Scrypt.run"
              });
              _this.pbkdf2({
                key: key,
                salt: WordArray.from_i32a(B),
                dkLen: dkLen,
                c: _this.c1,
                progress_hook: lph
              }, __iced_deferrals.defer({
                assign_fn: (function() {
                  return function() {
                    return out = arguments[0];
                  };
                })(),
                lineno: 233
              }));
              __iced_deferrals._fulfill();
            })(function() {
              scrub_vec(XY);
              scrub_vec(V);
              scrub_vec(B);
              key.scrub();
              return cb(out);
            });
          });
        };
      })(this));
    };

    return Scrypt;

  })();

  scrypt = function(_arg, cb) {
    var N, c, c0, c1, dkLen, eng, key, klass, p, progress_hook, r, salt, wa, ___iced_passed_deferral, __iced_deferrals, __iced_k;
    __iced_k = __iced_k_noop;
    ___iced_passed_deferral = iced.findDeferral(arguments);
    key = _arg.key, salt = _arg.salt, r = _arg.r, N = _arg.N, p = _arg.p, c0 = _arg.c0, c1 = _arg.c1, c = _arg.c, klass = _arg.klass, progress_hook = _arg.progress_hook, dkLen = _arg.dkLen;
    eng = new Scrypt({
      r: r,
      N: N,
      p: p,
      c: c,
      c0: c0,
      c1: c1,
      klass: klass
    });
    (function(_this) {
      return (function(__iced_k) {
        __iced_deferrals = new iced.Deferrals(__iced_k, {
          parent: ___iced_passed_deferral,
          filename: "/home/max/src/keybase/triplesec/src/scrypt.iced"
        });
        eng.run({
          key: key,
          salt: salt,
          progress_hook: progress_hook,
          dkLen: dkLen
        }, __iced_deferrals.defer({
          assign_fn: (function() {
            return function() {
              return wa = arguments[0];
            };
          })(),
          lineno: 263
        }));
        __iced_deferrals._fulfill();
      });
    })(this)((function(_this) {
      return function() {
        return cb(wa);
      };
    })(this));
  };

  exports.Scrypt = Scrypt;

  exports.scrypt = scrypt;

  exports.v_endian_reverse = v_endian_reverse;

}).call(this);
