// Generated by IcedCoffeeScript 1.7.1-c
(function() {
  var ASP, BaseKey, BaseKeyPair, C, K, MRF, Output, Pair, Priv, Pub, SRF, bn, bufeq_secure, eme_pkcs1_decode, eme_pkcs1_encode, iced, konst, make_esc, __iced_k, __iced_k_noop, _ref, _ref1, _ref2, _ref3,
    __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; };

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

  bn = require('./bn');

  _ref = require('./util'), bufeq_secure = _ref.bufeq_secure, ASP = _ref.ASP;

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

  konst = require('./const');

  C = konst.openpgp;

  K = konst.kb;

  _ref1 = require('./basekeypair'), BaseKeyPair = _ref1.BaseKeyPair, BaseKey = _ref1.BaseKey;

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

  _ref3 = require('./pad'), eme_pkcs1_encode = _ref3.eme_pkcs1_encode, eme_pkcs1_decode = _ref3.eme_pkcs1_decode;

  Pub = (function(_super) {
    __extends(Pub, _super);

    Pub.type = C.public_key_algorithms.ELGAMAL;

    Pub.prototype.type = Pub.type;

    Pub.ORDER = ['p', 'g', 'y'];

    Pub.prototype.ORDER = Pub.ORDER;

    function Pub(_arg) {
      this.p = _arg.p, this.g = _arg.g, this.y = _arg.y;
    }

    Pub.alloc = function(raw) {
      return BaseKey.alloc(Pub, raw);
    };

    Pub.prototype.encrypt = function(m, cb) {
      var c, k, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/Users/max/src/keybase/kbpgp/src/elgamal.iced",
            funcname: "Pub.encrypt"
          });
          SRF().random_zn(_this.p.subtract(bn.nbv(2)), __iced_deferrals.defer({
            assign_fn: (function() {
              return function() {
                return k = arguments[0];
              };
            })(),
            lineno: 35
          }));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          k = k.add(bn.BigInteger.ONE);
          c = [_this.g.modPow(k, _this.p), _this.y.modPow(k, _this.p).multiply(m).mod(_this.p)];
          return cb(c);
        };
      })(this));
    };

    return Pub;

  })(BaseKey);

  Priv = (function(_super) {
    __extends(Priv, _super);

    Priv.ORDER = ['x'];

    Priv.prototype.ORDER = Priv.ORDER;

    function Priv(_arg) {
      this.x = _arg.x, this.pub = _arg.pub;
    }

    Priv.prototype.serialize = function() {
      return this.x.to_mpi_buffer();
    };

    Priv.alloc = function(raw, pub) {
      return BaseKey.alloc(Priv, raw, {
        pub: pub
      });
    };

    Priv.prototype.decrypt = function(c, cb) {
      var p, ret;
      p = this.pub.p;
      ret = c[0].modPow(this.x, p).modInverse(p).multiply(c[1]).mod(p);
      return cb(null, ret);
    };

    return Priv;

  })(BaseKey);

  Pair = (function(_super) {
    __extends(Pair, _super);

    Pair.Pub = Pub;

    Pair.prototype.Pub = Pub;

    Pair.Priv = Priv;

    Pair.prototype.Priv = Priv;

    Pair.type = C.public_key_algorithms.ELGAMAL;

    Pair.klass_name = "ELGAMAL";

    Pair.prototype.type = Pair.type;

    Pair.prototype.get_type = function() {
      return this.type;
    };

    Pair.prototype.fulfills_flags = function(flags) {
      var good_for;
      good_for = this.good_for_flags();
      return (flags & good_for) === flags;
    };

    Pair.prototype.good_for_flags = function() {
      return C.key_flags.encrypt_comm | C.key_flags.encrypt_storage;
    };

    function Pair(_arg) {
      var priv, pub;
      pub = _arg.pub, priv = _arg.priv;
      Pair.__super__.constructor.call(this, {
        pub: pub,
        priv: priv
      });
    }

    Pair.prototype.can_sign = function() {
      return false;
    };

    Pair.parse = function(pub_raw) {
      var ret;
      ret = BaseKeyPair.parse(Pair, pub_raw);
      return ret;
    };

    Pair.prototype.max_value = function() {
      return this.pub.p;
    };

    Pair.prototype.pad_and_encrypt = function(data, params, cb) {
      var c_mpis, err, m, ret, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      err = ret = null;
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/Users/max/src/keybase/kbpgp/src/elgamal.iced",
            funcname: "Pair.pad_and_encrypt"
          });
          eme_pkcs1_encode(data, _this.pub.p.mpi_byte_length(), __iced_deferrals.defer({
            assign_fn: (function() {
              return function() {
                err = arguments[0];
                return m = arguments[1];
              };
            })(),
            lineno: 112
          }));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          (function(__iced_k) {
            if (err == null) {
              (function(__iced_k) {
                __iced_deferrals = new iced.Deferrals(__iced_k, {
                  parent: ___iced_passed_deferral,
                  filename: "/Users/max/src/keybase/kbpgp/src/elgamal.iced",
                  funcname: "Pair.pad_and_encrypt"
                });
                _this.pub.encrypt(m, __iced_deferrals.defer({
                  assign_fn: (function() {
                    return function() {
                      return c_mpis = arguments[0];
                    };
                  })(),
                  lineno: 114
                }));
                __iced_deferrals._fulfill();
              })(function() {
                return __iced_k(ret = _this.export_output({
                  c_mpis: c_mpis
                }));
              });
            } else {
              return __iced_k();
            }
          })(function() {
            return cb(err, ret);
          });
        };
      })(this));
    };

    Pair.prototype.decrypt_and_unpad = function(ciphertext, params, cb) {
      var b, err, m, ret, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      err = ret = null;
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/Users/max/src/keybase/kbpgp/src/elgamal.iced",
            funcname: "Pair.decrypt_and_unpad"
          });
          _this.priv.decrypt(ciphertext.c(), __iced_deferrals.defer({
            assign_fn: (function() {
              return function() {
                err = arguments[0];
                return m = arguments[1];
              };
            })(),
            lineno: 122
          }));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          var _ref4;
          if (err == null) {
            b = m.to_padded_octets(_this.pub.p);
            _ref4 = eme_pkcs1_decode(b), err = _ref4[0], ret = _ref4[1];
          }
          return cb(err, ret);
        };
      })(this));
    };

    Pair.parse_output = function(buf) {
      return Output.parse(buf);
    };

    Pair.prototype.export_output = function(args) {
      return new Output(args);
    };

    return Pair;

  })(BaseKeyPair);

  Output = (function() {
    function Output(_arg) {
      this.c_mpis = _arg.c_mpis, this.c_bufs = _arg.c_bufs;
    }

    Output.parse = function(buf) {
      var c_mpis, err, i, n, ret;
      c_mpis = (function() {
        var _i, _ref4, _results;
        _results = [];
        for (i = _i = 0; _i < 2; i = ++_i) {
          _ref4 = bn.mpi_from_buffer(buf), err = _ref4[0], ret = _ref4[1], buf = _ref4[2], n = _ref4[3];
          if (err != null) {
            throw err;
          }
          _results.push(ret);
        }
        return _results;
      })();
      if (buf.length !== 0) {
        throw new Error("junk at the end of input");
      }
      return new Output({
        c_mpis: c_mpis
      });
    };

    Output.prototype.c = function() {
      return this.c_mpis;
    };

    Output.prototype.hide = function(_arg, cb) {
      var c_mpi, err, key, max, new_c_mpis, slosh, tmp, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      key = _arg.key, max = _arg.max, slosh = _arg.slosh;
      max || (max = 4096);
      slosh || (slosh = 128);
      err = null;
      this.c_bufs = null;
      new_c_mpis = [];
      (function(_this) {
        return (function(__iced_k) {
          var _i, _len, _ref4, _results, _while;
          _ref4 = _this.c_mpis;
          _len = _ref4.length;
          _i = 0;
          _results = [];
          _while = function(__iced_k) {
            var _break, _continue, _next;
            _break = function() {
              return __iced_k(_results);
            };
            _continue = function() {
              return iced.trampoline(function() {
                ++_i;
                return _while(__iced_k);
              });
            };
            _next = function(__iced_next_arg) {
              _results.push(__iced_next_arg);
              return _continue();
            };
            if (!(_i < _len)) {
              return _break();
            } else {
              c_mpi = _ref4[_i];
              (function(__iced_k) {
                __iced_deferrals = new iced.Deferrals(__iced_k, {
                  parent: ___iced_passed_deferral,
                  filename: "/Users/max/src/keybase/kbpgp/src/elgamal.iced",
                  funcname: "Output.hide"
                });
                key.hide({
                  i: c_mpi,
                  max: max,
                  slosh: slosh
                }, __iced_deferrals.defer({
                  assign_fn: (function() {
                    return function() {
                      err = arguments[0];
                      return tmp = arguments[1];
                    };
                  })(),
                  lineno: 164
                }));
                __iced_deferrals._fulfill();
              })(function() {
                new_c_mpis.push(tmp);
                (function(__iced_k) {
                  if (err != null) {
                    (function(__iced_k) {
_break()
                    })(__iced_k);
                  } else {
                    return __iced_k();
                  }
                })(_next);
              });
            }
          };
          _while(__iced_k);
        });
      })(this)((function(_this) {
        return function() {
          if (err == null) {
            _this.c_mpis = new_c_mpis;
          }
          return cb(err);
        };
      })(this));
    };

    Output.prototype.find = function(_arg) {
      var j, key;
      key = _arg.key;
      return this.c_mpis = (function() {
        var _i, _len, _ref4, _results;
        _ref4 = this.c_mpis;
        _results = [];
        for (_i = 0, _len = _ref4.length; _i < _len; _i++) {
          j = _ref4[_i];
          _results.push(key.find(j));
        }
        return _results;
      }).call(this);
    };

    Output.prototype.get_c_bufs = function() {
      var i;
      if (this.c_bufs != null) {
        return this.c_bufs;
      } else {
        return this.c_bufs = (function() {
          var _i, _len, _ref4, _results;
          _ref4 = this.c_mpis;
          _results = [];
          for (_i = 0, _len = _ref4.length; _i < _len; _i++) {
            i = _ref4[_i];
            _results.push(i.to_mpi_buffer());
          }
          return _results;
        }).call(this);
      }
    };

    Output.prototype.output = function() {
      return Buffer.concat(this.get_c_bufs());
    };

    return Output;

  })();

  exports.ElGamal = exports.Pair = Pair;

}).call(this);
