// Generated by IcedCoffeeScript 1.7.1-c
(function() {
  var ASP, Avg, BigInteger, MRF, PrimeFinder, SRF, Timer, fermat2_test, fta, iced, make_esc, miller_rabin, naive_is_prime, native_rng, nbi, nbs, nbv, prime_search, prng, quickmod, random_prime, small_primes, _MR_inner, _MR_small_check, __iced_k, __iced_k_noop, _ref, _ref1;

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

  _ref = require('bn'), nbv = _ref.nbv, nbi = _ref.nbi, BigInteger = _ref.BigInteger;

  prng = require('triplesec').prng;

  native_rng = prng.native_rng;

  small_primes = require('./primes').small_primes;

  make_esc = require('iced-error').make_esc;

  ASP = require('./util').ASP;

  nbs = require('./bn').nbs;

  _ref1 = require('./rand'), MRF = _ref1.MRF, SRF = _ref1.SRF;

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

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

    return Timer;

  })();

  Avg = (function() {
    function Avg() {
      this.tot = 0;
      this.n = 0;
    }

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

    Avg.prototype.stop = function() {
      var s;
      s = Date.now() - this._t;
      console.log("ran in " + s);
      this.tot += s;
      return this.n++;
    };

    Avg.prototype.avg = function() {
      return this.tot / this.n;
    };

    return Avg;

  })();

  quickmod = function(p, d) {
    return p.modInt(d);
  };

  fta = new Avg();

  fermat2_test = function(n) {
    var Bl, bl, i, ret, t, _i;
    t = nbv(1);
    bl = n.bitLength();
    bl--;
    Bl = n.byteLength();
    for (i = _i = bl; bl <= 0 ? _i <= 0 : _i >= 0; i = bl <= 0 ? ++_i : --_i) {
      t = t.square();
      if (t.byteLength() > Bl) {
        t = t.mod(n);
      }
      if (n.testBit(i)) {
        t = t.shiftLeft(1);
      }
    }
    if (t.compareTo(n) > 0) {
      t = t.mod(n);
    }
    ret = t.compareTo(nbv(2)) === 0;
    return ret;
  };

  _MR_inner = function(_arg) {
    var a, j, p, p1, r, s, y, _i, _ref2;
    s = _arg.s, r = _arg.r, p = _arg.p, p1 = _arg.p1;
    a = MRF().random_zn(p);
    y = a.modPow(r, p);
    if (y.compareTo(BigInteger.ONE) !== 0) {
      for (j = _i = _ref2 = s - 1; _ref2 <= 0 ? _i <= 0 : _i >= 0; j = _ref2 <= 0 ? ++_i : --_i) {
        if (!(y.compareTo(p1) !== 0)) {
          continue;
        }
        if (j === 0) {
          return false;
        }
        y = y.square().mod(p);
        if (y.compareTo(BigInteger.ONE) === 0) {
          return false;
        }
      }
    }
    return true;
  };

  _MR_small_check = function(_arg) {
    var p, _ref2;
    p = _arg.p;
    if (p.compareTo(BigInteger.ZERO) <= 0) {
      return false;
    } else if (p.compareTo(nbv(7)) <= 0) {
      return (_ref2 = p.intValue()) === 2 || _ref2 === 3 || _ref2 === 5 || _ref2 === 7;
    } else if (!p.testBit(0)) {
      return false;
    } else {
      return true;
    }
  };

  miller_rabin = function(_arg, cb) {
    var asp, esc, i, iter, p, p1, r, ret, s, ___iced_passed_deferral, __iced_deferrals, __iced_k, _begin, _end, _positive;
    __iced_k = __iced_k_noop;
    ___iced_passed_deferral = iced.findDeferral(arguments);
    p = _arg.p, iter = _arg.iter, asp = _arg.asp;
    asp || (asp = new ASP({}));
    iter || (iter = 10);
    esc = make_esc(cb, "miller_rabin");
    ret = _MR_small_check({
      p: p
    });
    (function(_this) {
      return (function(__iced_k) {
        if (ret) {
          p1 = p.subtract(BigInteger.ONE);
          s = p1.getLowestSetBit();
          r = p1.shiftRight(s);
          ret = true;
          (function(__iced_k) {
            var _i, _results, _while;
            i = 0;
            _begin = 0;
            _end = iter;
            _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) {
                    i += 1;
                  } else {
                    i -= 1;
                  }
                  return _while(__iced_k);
                });
              };
              _next = function(__iced_next_arg) {
                _results.push(__iced_next_arg);
                return _continue();
              };
              if (!!((_positive === true && i >= iter) || (_positive === false && i <= iter))) {
                return _break();
              } else {

                (function(__iced_k) {
                  __iced_deferrals = new iced.Deferrals(__iced_k, {
                    parent: ___iced_passed_deferral,
                    filename: "/home/max/src/keybase/kbpgp/src/primegen.iced"
                  });
                  asp.progress({
                    what: "mr",
                    i: i,
                    total: iter,
                    p: p
                  }, esc(__iced_deferrals.defer({
                    lineno: 122
                  })));
                  __iced_deferrals._fulfill();
                })(function() {
                  (function(__iced_k) {
                    if (!_MR_inner({
                      s: s,
                      r: r,
                      p: p,
                      p1: p1
                    })) {
                      ret = false;
                      (function(__iced_k) {
_break()
                      })(__iced_k);
                    } else {
                      return __iced_k();
                    }
                  })(_next);
                });
              }
            };
            _while(__iced_k);
          })(function() {
            (function(__iced_k) {
              __iced_deferrals = new iced.Deferrals(__iced_k, {
                parent: ___iced_passed_deferral,
                filename: "/home/max/src/keybase/kbpgp/src/primegen.iced"
              });
              asp.progress({
                what: "mr",
                i: iter,
                total: iter,
                p: p
              }, esc(__iced_deferrals.defer({
                lineno: 127
              })));
              __iced_deferrals._fulfill();
            })(__iced_k);
          });
        } else {
          return __iced_k();
        }
      });
    })(this)((function(_this) {
      return function() {
        return cb(null, ret);
      };
    })(this));
  };

  PrimeFinder = (function() {
    function PrimeFinder(p, sieve) {
      this.p = p;
      this.sieve = sieve;
      this.inc = 0;
      this.maxinc = -1;
      this.sievepos = quickmod(this.p, this.sieve.length);
      this.calcmods();
    }

    PrimeFinder.prototype.getp = function() {
      return this.p;
    };

    PrimeFinder.prototype.setmax = function(i) {
      if (this.maxinc !== -1) {
        throw new Error("can only setmax() once");
      }
      return this.maxinc = i;
    };

    PrimeFinder.prototype.calcmods = function() {
      var sp;
      this.p = this.p.add(nbv(this.inc));
      if (this.maxinc !== -1) {
        this.maxinc -= this.inc;
      }
      this.inc = 0;
      return this.mods = (function() {
        var _i, _len, _results;
        _results = [];
        for (_i = 0, _len = small_primes.length; _i < _len; _i++) {
          sp = small_primes[_i];
          _results.push(quickmod(this.p, sp));
        }
        return _results;
      }).call(this);
    };

    PrimeFinder.prototype.decrement_mods_find_divisor = function() {
      var i, sp, _i, _len;
      for (i = _i = 0, _len = small_primes.length; _i < _len; i = ++_i) {
        sp = small_primes[i];
        while (this.mods[i] + this.inc >= sp) {
          this.mods[i] -= sp;
          if ((this.mods[i] + this.inc) === 0) {
            return true;
          }
        }
      }
      return false;
    };

    PrimeFinder.prototype.next_weak = function() {
      var step;
      while (true) {
        step = this.sieve[this.sievepos];
        this.sievepos = (this.sievepos + step) % this.sieve.length;
        this.inc += step;
        if (this.inc > this.maxinc && this.maxinc > 0) {
          this.tmp = nbv(0);
          return this.tmp;
        }
        if (this.inc < 0) {
          this.calcmods();
        }
        if (!this.decrement_mods_find_divisor()) {
          this.tmp = this.p.add(nbv(this.inc));
          return this.tmp;
        }
      }
    };

    PrimeFinder.prototype.next_fermat = function() {
      while (true) {
        this.next_weak();
        if (!this.tmp || fermat2_test(this.tmp)) {
          return this.tmp;
        }
      }
    };

    PrimeFinder.prototype.next_strong = function(iter) {
      if (iter == null) {
        iter = 32;
      }
      while (true) {
        this.next_weak();
        if (!this.tmp || (fermat2_test(this.tmp) && probab_prime(this.tmp, iter))) {
          return this.tmp;
        }
      }
    };

    return PrimeFinder;

  })();

  prime_search = function(_arg, cb) {
    var asp, esc, i, is_prime, iters, p, pf, pp, pvec, range, ret, sieve, start, tmp, ___iced_passed_deferral, __iced_deferrals, __iced_k;
    __iced_k = __iced_k_noop;
    ___iced_passed_deferral = iced.findDeferral(arguments);
    start = _arg.start, range = _arg.range, sieve = _arg.sieve, asp = _arg.asp, iters = _arg.iters;
    iters || (iters = 20);
    pf = new PrimeFinder(start, sieve);
    pf.setmax(range);
    pvec = ((function() {
      var _results;
      _results = [];
      while ((pp = pf.next_weak()).compareTo(BigInteger.ZERO) > 0) {
        _results.push(pp);
      }
      return _results;
    })());
    esc = make_esc(cb, "prime_search");
    ret = null;
    (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 (!(pvec.length && (ret == null))) {
            return _break();
          } else {
            i = MRF().random_word() % pvec.length;
            p = pvec[i];
            (function(__iced_k) {
              __iced_deferrals = new iced.Deferrals(__iced_k, {
                parent: ___iced_passed_deferral,
                filename: "/home/max/src/keybase/kbpgp/src/primegen.iced"
              });
              asp.progress({
                what: "fermat",
                p: p
              }, esc(__iced_deferrals.defer({
                lineno: 226
              })));
              __iced_deferrals._fulfill();
            })(function() {
              (function(__iced_k) {
                if (!fermat2_test(p)) {
                  return __iced_k();
                } else {
                  (function(__iced_k) {
                    __iced_deferrals = new iced.Deferrals(__iced_k, {
                      parent: ___iced_passed_deferral,
                      filename: "/home/max/src/keybase/kbpgp/src/primegen.iced"
                    });
                    miller_rabin({
                      p: p,
                      iters: iters,
                      asp: asp
                    }, esc(__iced_deferrals.defer({
                      assign_fn: (function() {
                        return function() {
                          return is_prime = arguments[0];
                        };
                      })(),
                      lineno: 229
                    })));
                    __iced_deferrals._fulfill();
                  })(function() {
                    (function(__iced_k) {
                      __iced_deferrals = new iced.Deferrals(__iced_k, {
                        parent: ___iced_passed_deferral,
                        filename: "/home/max/src/keybase/kbpgp/src/primegen.iced"
                      });
                      asp.progress({
                        what: "passed_mr",
                        p: p
                      }, esc(__iced_deferrals.defer({
                        lineno: 230
                      })));
                      __iced_deferrals._fulfill();
                    })(function() {
                      return __iced_k(is_prime ? ret = p : asp.progress({
                        what: "failed_mr",
                        p: p
                      }));
                    });
                  });
                }
              })(function() {
                tmp = pvec.pop();
                return _next(i < pvec.length ? pvec[i] = tmp : void 0);
              });
            });
          }
        };
        _while(__iced_k);
      });
    })(this)((function(_this) {
      return function() {
        if (ret == null) {
          ret = nbv(0);
        }
        return cb(null, ret);
      };
    })(this));
  };

  random_prime = function(_arg, cb) {
    var asp, e, esc, go, iters, nbits, p, range, sieve, ___iced_passed_deferral, __iced_deferrals, __iced_k;
    __iced_k = __iced_k_noop;
    ___iced_passed_deferral = iced.findDeferral(arguments);
    nbits = _arg.nbits, iters = _arg.iters, asp = _arg.asp, e = _arg.e;
    sieve = [1, 2];
    go = true;
    esc = make_esc(cb, "random_prime");
    range = nbits;
    p = null;
    (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 (!go) {
            return _break();
          } else {
            (function(__iced_k) {
              __iced_deferrals = new iced.Deferrals(__iced_k, {
                parent: ___iced_passed_deferral,
                filename: "/home/max/src/keybase/kbpgp/src/primegen.iced"
              });
              SRF().random_nbit(nbits, __iced_deferrals.defer({
                assign_fn: (function() {
                  return function() {
                    return p = arguments[0];
                  };
                })(),
                lineno: 262
              }));
              __iced_deferrals._fulfill();
            })(function() {
              p = p.setBit(0).setBit(nbits - 1).setBit(nbits - 2);
              (function(__iced_k) {
                if ((e == null) || p.subtract(BigInteger.ONE).gcd(e).compareTo(BigInteger.ONE) === 0) {
                  (function(__iced_k) {
                    __iced_deferrals = new iced.Deferrals(__iced_k, {
                      parent: ___iced_passed_deferral,
                      filename: "/home/max/src/keybase/kbpgp/src/primegen.iced"
                    });
                    asp.progress({
                      what: "guess",
                      p: p
                    }, esc(__iced_deferrals.defer({
                      lineno: 265
                    })));
                    __iced_deferrals._fulfill();
                  })(function() {
                    (function(__iced_k) {
                      __iced_deferrals = new iced.Deferrals(__iced_k, {
                        parent: ___iced_passed_deferral,
                        filename: "/home/max/src/keybase/kbpgp/src/primegen.iced"
                      });
                      prime_search({
                        start: p,
                        range: range,
                        sieve: sieve,
                        asp: asp,
                        iters: iters
                      }, esc(__iced_deferrals.defer({
                        assign_fn: (function() {
                          return function() {
                            return p = arguments[0];
                          };
                        })(),
                        lineno: 266
                      })));
                      __iced_deferrals._fulfill();
                    })(function() {
                      return __iced_k(go = (p == null) || (p.compareTo(BigInteger.ZERO) === 0));
                    });
                  });
                } else {
                  return __iced_k();
                }
              })(_next);
            });
          }
        };
        _while(__iced_k);
      });
    })(this)((function(_this) {
      return function() {
        (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/home/max/src/keybase/kbpgp/src/primegen.iced"
          });
          asp.progress({
            what: "found",
            p: p
          }, esc(__iced_deferrals.defer({
            lineno: 269
          })));
          __iced_deferrals._fulfill();
        })(function() {
          return cb(null, p);
        });
      };
    })(this));
  };

  exports.naive_is_prime = naive_is_prime = function(n) {
    var biggest, p, _i, _len;
    biggest = Math.floor(Math.sqrt(n));
    for (_i = 0, _len = small_primes.length; _i < _len; _i++) {
      p = small_primes[_i];
      if (p > biggest) {
        return true;
      }
      if ((n % p) === 0) {
        return false;
      }
    }
    return false;
  };

  exports.fermat2_test = fermat2_test;

  exports.nbs = nbs;

  exports.small_primes = small_primes;

  exports.miller_rabin = miller_rabin;

  exports.random_prime = random_prime;

}).call(this);
