Реальная история.
Для удобства, позвольте мне процитировать соответствующий раздел кода:
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.");
}
возвращает истину;
};