Реальная история.   
Для удобства, позвольте мне процитировать соответствующий раздел кода: 
ec.PointFp = функция (кривая, х, у, г, сжатый) {
                this.curve = кривой;
                this.x = х;
                this.y = у;
                // Проекционные координаты: либо zinv == нуль или г * zinv == 1
                // г и zinv просто BigIntegers, не fieldElements
                если (г == NULL) {
                        this.z = BigInteger.ONE;
                }
                еще {
                        this.z = г;
                }
                this.zinv = NULL;
                // флаг сжатия
                this.compressed = !! сжат;
        };
        ec.PointFp.prototype.getX = функция () {
                если (this.zinv == NULL) {
                        this.zinv = this.z.modInverse (this.curve.q);
                }
                вар г = this.x.toBigInteger () умножить (this.zinv).
                this.curve.reduce (г);
                вернуть this.curve.fromBigInteger (г);
        };
        ec.PointFp.prototype.getY = функция () {
                если (this.zinv == NULL) {
                        this.zinv = this.z.modInverse (this.curve.q);
                }
                вар г = this.y.toBigInteger () умножить (this.zinv).
                this.curve.reduce (г);
                вернуть this.curve.fromBigInteger (г);
        };
        ec.PointFp.prototype.equals = функция (другой) {
                если (другой == это) возвращает истину;
                если (this.isInfinity ()) возвращает other.isInfinity ();
                если (other.isInfinity ()) возвращает this.isInfinity ();
                вар U, V;
                // и = У2 * Z1 - Z2 Y1 *
                . И = other.y.toBigInteger () умножить (this.z) .subtract (this.y.toBigInteger () умножить (other.z).) Мод (this.curve.q).
                если (! u.equals (BigInteger.ZERO)) возвращает ложь;
                // v = X2 * Z1 - Z2 X1 *
                . V = other.x.toBigInteger () умножить (this.z) .subtract (this.x.toBigInteger () умножить (other.z).) Мод (this.curve.q).
                Обратные v.equals (BigInteger.ZERO);
        };
        ec.PointFp.prototype.isInfinity = функция () {
                если ((this.x == NULL) && (This.y == NULL)) возвращает истину;
                вернуться this.z.equals (BigInteger.ZERO) && !. this.y.toBigInteger () равно (BigInteger.ZERO);
        };
        ec.PointFp.prototype.negate = функция () {
                вернуть новый ec.PointFp (this.curve, this.x, this.y.negate (), this.z);
        };
        ec.PointFp.prototype.add = функция (б) {
                если (this.isInfinity ()) возвращение б;
                если (b.isInfinity ()) возвращает это;
                // и = У2 * Z1 - Z2 Y1 *
                вар и = b.y.toBigInteger () умножить (this.z) .subtract (this.y.toBigInteger () умножить (b.z).) MOD (this.curve.q)..;
                // v = X2 * Z1 - Z2 X1 *
                переменная v = b.x.toBigInteger () умножить (this.z) .subtract (this.x.toBigInteger () умножить (b.z).) MOD (this.curve.q)..;
                если (BigInteger.ZERO.equals (v)) {
                        если (BigInteger.ZERO.equals (и)) {
                                вернуть this.twice (); // это == Ь, так что дважды
                        }
                        вернуть this.curve.getInfinity (); // это = -b, так что бесконечность
                }
                вар ТРИ = новый BigInteger ("3");
                переменная x1 = this.x.toBigInteger ();
                вар у1 = this.y.toBigInteger ();
                вар х2 = b.x.toBigInteger ();
                вар у2 = b.y.toBigInteger ();
                вар v2 = v.square ();
                вар v3 = v2.multiply (v);
                вар x1v2 = x1.multiply (v2);
                . Вар zu2 = u.square () умножить (this.z);
                // x3 = v * (z2 * (z1 * и ^ 2 - 2 * x1 * v ^ 2) - v ^ 3)
                . Вар х3 = zu2.subtract (x1v2.shiftLeft (1)) умножают (b.z) .subtract (V3) .multiply (v) .mod (this.curve.q);
                // у3 = z2 * (3 * х1 * и * V ^ 2 - у1 * V ^ 3 - z1 * и ^ 3) + и * V ^ 3
                вар у3 = x1v2.multiply (ТРИ) .multiply (и) .subtract (y1.multiply (V3)). вычитают (zu2.multiply (и)). умножать (BZ) .add (u.multiply (V3)). мод (this.curve.q);
                // z3 = v ^ 3 * z1 * z2
                вар Z3 = v3.multiply (this.z) .multiply (b.z) .mod (this.curve.q);
                вернуть новый ec.PointFp (this.curve, this.curve.fromBigInteger (x3), this.curve.fromBigInteger (y3), z3);
        };
        ec.PointFp.prototype.twice = функция () {
                если (this.isInfinity ()) возвращает это;
                если (this.y.toBigInteger () сигнум () == 0.) возвращают this.curve.getInfinity ();
                // TODO: оптимизированная обработка констант
                вар ТРИ = новый BigInteger ("3");
                переменная x1 = this.x.toBigInteger ();
                вар у1 = this.y.toBigInteger ();
                вар y1z1 = y1.multiply (this.z);
                вар y1sqz1 = y1z1.multiply (у1) .mod (this.curve.q);
                а = переменная this.curve.a.toBigInteger ();
                // ш = 3 * x1 ^ 2 + а * z1 ^ 2
                . Вар ш = x1.square () умножить (три);
                если (! BigInteger.ZERO.equals (а)) {
                        ш = w.add (this.z.square () умножают (а).);
                }
                ш = w.mod (this.curve.q);
                //this.curve.reduce(w);
                // х3 = 2 * у1 * z1 * (ш ^ 2 - 8 * x1 * y1 ^ 2 * z1)
                переменная х3 = w.square () вычесть (x1.shiftLeft (3) .multiply (y1sqz1)) shiftLeft (1) .multiply (y1z1) .mod (this.curve.q)..;
                // у3 = 4 * у1 ^ 2 * г1 * (3 * ш * x1 - 2 * у1 ^ 2 * г1) - ш ^ 3
                вар у3 = w.multiply (ТРИ) .multiply (x1) .subtract (y1sqz1.shiftLeft (1)). shiftLeft (2) .multiply (y1sqz1) .subtract (w.square (). умножать (ш)). мод (this.curve.q);
                // г3 = 8 * (у1 * z1) ^ 3
                вар Z3 = y1z1.square () умножить (y1z1) .shiftLeft (3) .mod (this.curve.q).
                вернуть новый ec.PointFp (this.curve, this.curve.fromBigInteger (x3), this.curve.fromBigInteger (y3), z3);
        };
        // Простой NAF (несмежная форма) алгоритм умножения
        // TODO: модуляризуете алгоритм умножения
        ec.PointFp.prototype.multiply = функция (к) {
                если (this.isInfinity ()) возвращает это;
                если (k.signum () == 0) возвращают this.curve.getInfinity ();
                вар е = к;
                вар ч = e.multiply (новый BigInteger ("3"));
                вар отр = this.negate ();
                Var R = это;
                вар я;
                для (я = h.bitLength () - 2; я > 0; --i) {
                        R = R.twice ();
                        вар hBit = h.testBit (я);
                        вар EBIT = e.testBit (я);
                        если (hBit! = EBIT) {
                                R = R.add (hBit это: отр?);
                        }
                }
                возвращать R;
        };
        // Вычислить это * J + х * к (одновременное умножение)
        ec.PointFp.prototype.multiplyTwo = функция (у, х, к) {
                вар я;
                если (j.bitLength () > k.bitLength ())
                        я = j.bitLength () - 1;
                еще
                        я = k.bitLength () - 1;
                Var R = this.curve.getInfinity ();
                вар как = this.add (х);
                в то время как я >= 0) {
                        R = R.twice ();
                        если (j.testBit (я)) {
                                если (k.testBit (я)) {
                                        R = R.add (оба);
                                }
                                еще {
                                        R = R.add (это);
                                }
                        }
                        еще {
                                если (k.testBit (я)) {
                                        R = R.add (х);
                                }
                        }
                        --я;
                }
                возвращать R;
        };
        // затяну- bitaddress.org и Casascius для использования с Bitcoin.ECKey
        // затяну- coretechs для поддержки сжатых открытых ключей
        ec.PointFp.prototype.getEncoded = функция (сжатый) {
                . Вар х = this.getX () toBigInteger ();
                вар у = this.getY () toBigInteger ().
                вар Len = 32; // integerToBytes обнулит пэд, если число меньше 32 байт. 32 длина байта требуется в соответствии с протоколом Bitcoin.
                вар прил = ec.integerToBytes (х, длина);
                // при сжатии байт в зависимости добавьте в начале, если у точки четным или нечетным
                если (сжатый) {
                        если (y.isEven ()) {
                                enc.unshift (0x02);
                        }
                        еще {
                                enc.unshift (0x03);
                        }
                }
                еще {
                        enc.unshift (0x04);
                        ENC = enc.concat (ec.integerToBytes (у, длина)); // несжатый открытый ключ добавляет байты точки у
                }
                вернуться прил;
        };
        ec.PointFp.decodeFrom = функция (кривая, ENC) {
                тип переменная = ENC [0];
                вар dataLen = enc.length - 1;
                // Извлечение х и у в виде байтовых массивов
                вар Xba = enc.slice (1, 1 + dataLen / 2);
                вар YBa = enc.slice (1 + dataLen / 2, 1 + dataLen);
                // Prepend нулевых байт, чтобы предотвратить интерпретацию как отрицательное число
                xBa.unshift (0);
                yBa.unshift (0);
                // Преобразовать в BigIntegers
                переменная х = новый BigInteger (Xba);
                вар у = новый BigInteger (YBA);
                // Точка возврата
                вернуть новый ec.PointFp (кривая, curve.fromBigInteger (х), curve.fromBigInteger (у));
        };
        ec.PointFp.prototype.add2D = функция (б) {
                если (this.isInfinity ()) возвращение б;
                если (b.isInfinity ()) возвращает это;
                если (this.x.equals (b.x)) {
                        если (this.y.equals (b.y)) {
                                // это = Ь, то есть это должно быть в два раза
                                вернуть this.twice ();
                        }
                        // это = -b, т.е. результатом является точка на бесконечности
                        вернуть this.curve.getInfinity ();
                }
                вар x_x = b.x.subtract (this.x);
                вар y_y = b.y.subtract (this.y);
                вар гамма = y_y.divide (x_x);
                переменная х3 = gamma.square () вычесть (this.x) .subtract (b.x).
                переменная у3 = gamma.multiply (this.x.subtract (х3)) вычесть (this.y).
                вернуть новый ec.PointFp (this.curve, x3, y3);
        };
        ec.PointFp.prototype.twice2D = функция () {
                если (this.isInfinity ()) возвращает это;
                если (this.y.toBigInteger (). сигнум () == 0) {
                        // если y1 == 0, то (x1, y1) == (x1, -y1)
                        // и, следовательно, это = -за и, следовательно, 2 (x1, y1) == бесконечность
                        вернуть this.curve.getInfinity ();
                }
                ДВА вар = this.curve.fromBigInteger (BigInteger.valueOf (2));
                вар ТРИ = this.curve.fromBigInteger (BigInteger.valueOf (3));
                вар гамма = this.x.square () умножить (три) .add (this.curve.a) .divide (this.y.multiply (ДВА)).
                переменная х3 = gamma.square () вычесть (this.x.multiply (ДВА)).
                переменная у3 = gamma.multiply (this.x.subtract (х3)) вычесть (this.y).
                вернуть новый ec.PointFp (this.curve, x3, y3);
        };
        ec.PointFp.prototype.multiply2D = функция (к) {
                если (this.isInfinity ()) возвращает это;
                если (k.signum () == 0) возвращают this.curve.getInfinity ();
                вар е = к;
                вар ч = e.multiply (новый BigInteger ("3"));
                вар отр = this.negate ();
                Var R = это;
                вар я;
                для (я = h.bitLength () - 2; я > 0; --i) {
                        R = R.twice ();
                        вар hBit = h.testBit (я);
                        вар EBIT = e.testBit (я);
                        если (hBit! = EBIT) {
                                R = R.add2D (hBit это: отр?);
                        }
                }
                возвращать R;
        };
        ec.PointFp.prototype.isOnCurve = функция () {
                . Вар х = this.getX () toBigInteger ();
                вар у = this.getY () toBigInteger ().
                а = переменная this.curve.getA () toBigInteger ().
                вар б = this.curve.getB () toBigInteger ().
                вар п = this.curve.getQ ();
                вар LHS = y.multiply (у) .mod (п);
                . Вар RHS = x.multiply (х) .multiply (х) .add (a.multiply (х)) добавляют (б) .mod (п);
                вернуть lhs.equals (РИТ);
        };
        ec.PointFp.prototype.toString = функция () {
                Возвращение '('.... + this.getX () toBigInteger () ToString () + '' + this.getY () toBigInteger () ToString () + ')';
        };
        / **
        * Подтвердить эллиптическую точку кривой.
        *
        * См SEC 1, раздел 3.2.2.1: Эллиптическая кривая открытого ключа проверки примитив
        * /
        ec.PointFp.prototype.validate = функция () {
                вар п = this.curve.getQ ();
                // Проверка Q! = O
                если (this.isInfinity ()) {
                        певд Error ("Точка находится на бесконечности.");
                }
                // Проверка координат границ
                . Вар х = this.getX () toBigInteger ();
                вар у = this.getY () toBigInteger ().
                если (x.compareTo (BigInteger.ONE) < 0 || x.compareTo (n.subtract (BigInteger.ONE)) > 0) {
                        певд Error ( «координата х вне границ»);
                }
                если (y.compareTo (BigInteger.ONE) < 0 || y.compareTo (n.subtract (BigInteger.ONE)) > 0) {
                        певд Error ( «координата вне границ»);
                }
                // Проверка у ^ 2 = х ^ 3 + ах + Ь (по модулю п)
                если (! this.isOnCurve ()) {
                        певд Error ("Точка не на кривой.");
                }
                // Проверка NQ = 0 (Q представляет собой скалярное кратное G)
                если (this.multiply (п) .isInfinity ()) {
                        // TODO: Эта проверка не работает - исправить.
                        певд Error ("Точка не является скалярным кратным G.");
                }
                возвращает истину;
        };