// Generated by IcedCoffeeScript 1.7.1-c
(function() {
  var ASP, BaseEccKey, BaseKey, BaseKeyPair, Const, Output, Pair, Priv, Pub, SlicerBuffer, bufeq_secure, ecc_pkcs5_pad_data, generate, hashmod, iced, konst, make_esc, sym, uint_to_buffer, unwrap, wrap, __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() {};

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

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

  konst = require('../const');

  Const = konst.openpgp;

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

  ecc_pkcs5_pad_data = require('../pad').ecc_pkcs5_pad_data;

  _ref2 = require('./base'), generate = _ref2.generate, BaseEccKey = _ref2.BaseEccKey;

  hashmod = require('../hash');

  sym = require('../symmetric');

  SlicerBuffer = require('../openpgp/buffer').SlicerBuffer;

  _ref3 = require('../rfc3394'), wrap = _ref3.wrap, unwrap = _ref3.unwrap;

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

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

    Pub.type = Const.public_key_algorithms.ECDH;

    Pub.prototype.type = Pub.type;

    Pub.prototype.apply_defaults = function() {
      this.cipher || (this.cipher = sym.get_cipher());
      return this.hasher || (this.hasher = hashmod.SHA512);
    };

    Pub.prototype.read_params = function(sb) {
      var n, size, v, val;
      if ((size = sb.read_uint8()) < (n = Const.ecdh.param_bytes)) {
        throw new Error("Need at least " + n + " bytes of params; got " + size);
      }
      if ((val = sb.read_uint8()) !== (v = Const.ecdh.version)) {
        throw new Error("Cannot deal with future extensions, byte=" + val + "; wanted " + v);
      }
      this.hasher = hashmod.alloc_or_throw(sb.read_uint8());
      this.cipher = sym.get_cipher(sb.read_uint8());
      return sb.advance(size - 3);
    };

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

    Pub.prototype.serialize_params = function() {
      return Buffer.concat([uint_to_buffer(8, Const.ecdh.param_bytes), uint_to_buffer(8, Const.ecdh.version), uint_to_buffer(8, this.hasher.type), uint_to_buffer(8, this.cipher.type)]);
    };

    Pub.prototype.serialize = function() {
      return Buffer.concat([Pub.__super__.serialize.call(this), this.serialize_params()]);
    };

    Pub.prototype.format_params = function(_arg) {
      var fingerprint;
      fingerprint = _arg.fingerprint;
      return Buffer.concat([uint_to_buffer(8, this.curve.oid.length), this.curve.oid, uint_to_buffer(8, this.type), this.serialize_params(), new Buffer("Anonymous Sender    ", "utf8"), fingerprint]);
    };

    Pub.prototype.kdf = function(_arg) {
      var X, X_compact, buf, hash, o_bytes, params;
      X = _arg.X, params = _arg.params;
      o_bytes = this.cipher.key_size;
      X_compact = this.curve.point_to_mpi_buffer_compact(X);
      buf = Buffer.concat([new Buffer([0, 0, 0, 1]), X_compact, params]);
      hash = this.hasher(buf);
      return hash.slice(0, o_bytes);
    };

    Pub.prototype.encrypt = function(m, _arg, cb) {
      var C, G, S, V, fingerprint, key, n, params, v, ___iced_passed_deferral, __iced_deferrals, __iced_k, _ref4;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      fingerprint = _arg.fingerprint;
      _ref4 = this.curve, n = _ref4.n, G = _ref4.G;
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/Users/max/src/keybase/kbpgp/src/ecc/ecdh.iced",
            funcname: "Pub.encrypt"
          });
          _this.curve.random_scalar(__iced_deferrals.defer({
            assign_fn: (function() {
              return function() {
                return v = arguments[0];
              };
            })(),
            lineno: 100
          }));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          V = G.multiply(v);
          S = _this.R.multiply(v);
          params = _this.format_params({
            fingerprint: fingerprint
          });
          key = _this.kdf({
            X: S,
            params: params
          });
          C = wrap({
            key: key,
            plaintext: m,
            cipher: _this.cipher
          });
          return cb({
            V: V,
            C: C
          });
        };
      })(this));
    };

    return Pub;

  })(BaseEccKey);

  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, _arg, cb) {
      var S, V, curve, err, esc, fingerprint, key, params, ret, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      fingerprint = _arg.fingerprint;
      esc = make_esc(cb, "Priv::decrypt");
      curve = this.pub.curve;
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/Users/max/src/keybase/kbpgp/src/ecc/ecdh.iced",
            funcname: "Priv.decrypt"
          });
          c.load_V(curve, esc(__iced_deferrals.defer({
            assign_fn: (function() {
              return function() {
                return V = arguments[0];
              };
            })(),
            lineno: 141
          })));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          var _ref4;
          S = V.multiply(_this.x);
          params = _this.pub.format_params({
            fingerprint: fingerprint
          });
          key = _this.pub.kdf({
            X: S,
            params: params
          });
          _ref4 = unwrap({
            key: key,
            ciphertext: c.C,
            cipher: _this.pub.cipher
          }), err = _ref4[0], ret = _ref4[1];
          return cb(err, ret);
        };
      })(this));
    };

    return Priv;

  })(BaseKey);

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

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

    Pair.Pub = Pub;

    Pair.prototype.Pub = Pub;

    Pair.Priv = Priv;

    Pair.prototype.Priv = Priv;

    Pair.type = Const.public_key_algorithms.ECDH;

    Pair.prototype.type = Pair.type;

    Pair.klass_name = "ECDH";

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

    Pair.prototype.fulfills_flags = function(flags) {
      var good_for;
      good_for = Const.key_flags.encrypt_comm | Const.key_flags.encrypt_storage;
      return (flags & good_for) === flags;
    };

    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, _arg, cb) {
      var C, V, err, fingerprint, m, ret, ___iced_passed_deferral, __iced_deferrals, __iced_k, _ref4;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      fingerprint = _arg.fingerprint;
      err = ret = null;
      _ref4 = ecc_pkcs5_pad_data(data), err = _ref4[0], m = _ref4[1];
      (function(_this) {
        return (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/ecc/ecdh.iced",
                funcname: "Pair.pad_and_encrypt"
              });
              _this.pub.encrypt(m, {
                fingerprint: fingerprint
              }, __iced_deferrals.defer({
                assign_fn: (function() {
                  return function() {
                    C = arguments[0].C;
                    return V = arguments[0].V;
                  };
                })(),
                lineno: 196
              }));
              __iced_deferrals._fulfill();
            })(function() {
              return __iced_k(ret = _this.export_output({
                C: C,
                V: V,
                curve: _this.pub.curve
              }));
            });
          } else {
            return __iced_k();
          }
        });
      })(this)((function(_this) {
        return function() {
          return cb(err, ret);
        };
      })(this));
    };

    Pair.prototype.decrypt_and_unpad = function(ciphertext, _arg, cb) {
      var err, fingerprint, m, ret, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      fingerprint = _arg.fingerprint;
      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/ecc/ecdh.iced",
            funcname: "Pair.decrypt_and_unpad"
          });
          _this.priv.decrypt(ciphertext, {
            fingerprint: fingerprint
          }, __iced_deferrals.defer({
            assign_fn: (function() {
              return function() {
                err = arguments[0];
                return m = arguments[1];
              };
            })(),
            lineno: 204
          }));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          return cb(err, m, true);
        };
      })(this));
    };

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

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

    Pair.generate = function(_arg, cb) {
      var asp, err, nbits, pair, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      nbits = _arg.nbits, asp = _arg.asp;
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/Users/max/src/keybase/kbpgp/src/ecc/ecdh.iced",
            funcname: "Pair.generate"
          });
          generate({
            nbits: nbits,
            asp: asp,
            Pair: Pair
          }, __iced_deferrals.defer({
            assign_fn: (function() {
              return function() {
                err = arguments[0];
                return pair = arguments[1];
              };
            })(),
            lineno: 215
          }));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          if (typeof err === "undefined" || err === null) {
            pair.pub.apply_defaults();
          }
          return cb(err, pair);
        };
      })(this));
    };

    return Pair;

  })(BaseKeyPair);

  Output = (function() {
    function Output(_arg) {
      this.V_buf = _arg.V_buf, this.C = _arg.C, this.V = _arg.V, this.curve = _arg.curve;
    }

    Output.prototype.load_V = function(curve, cb) {
      var err, _ref4;
      this.curve = curve;
      _ref4 = curve.mpi_point_from_buffer(this.V_buf), err = _ref4[0], this.V = _ref4[1];
      return cb(err, this.V);
    };

    Output.parse = function(buf) {
      var C, V_buf, a, n_bits, n_bytes, ret, sb;
      sb = new SlicerBuffer(buf);
      n_bits = sb.read_uint16();
      n_bytes = Math.ceil(n_bits / 8);
      V_buf = Buffer.concat([buf.slice(0, 2), sb.read_buffer(n_bytes)]);
      n_bytes = sb.read_uint8();
      C = sb.consume_rest_to_buffer();
      if ((a = C.length) !== n_bytes) {
        throw new Error("bad C input: wanted " + n_bytes + " bytes, but got " + a);
      }
      ret = new Output({
        V_buf: V_buf,
        C: C
      });
      return ret;
    };

    Output.prototype.get_V_buf = function() {
      if (this.V_buf == null) {
        this.V_buf = this.curve.point_to_mpi_buffer(this.V);
      }
      return this.V_buf;
    };

    Output.prototype.hide = function(_arg, cb) {
      var key, max, slosh;
      key = _arg.key, max = _arg.max, slosh = _arg.slosh;
      return cb(null);
    };

    Output.prototype.find = function(_arg) {
      var key;
      key = _arg.key;
    };

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

    Output.prototype.output = function() {
      return Buffer.concat([this.get_V_buf(), uint_to_buffer(8, this.C.length), this.C]);
    };

    return Output;

  })();

  exports.ECDH = exports.Pair = Pair;

}).call(this);
