1
0
mirror of https://github.com/danog/ton.git synced 2024-12-02 09:28:02 +01:00
ton/crypto/ellcurve/Montgomery.cpp
2019-09-07 14:33:36 +04:00

139 lines
3.8 KiB
C++

/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "ellcurve/Montgomery.h"
#include <assert.h>
#include <cstring>
namespace ellcurve {
using namespace arith;
class MontgomeryCurve;
void MontgomeryCurve::init() {
assert(!((a_short + 2) & 3) && a_short >= 0);
}
void MontgomeryCurve::set_order_cofactor(const Bignum& order, int cof) {
assert(order > 0);
assert(cof >= 0);
assert(cof == 0 || (order % cof) == 0);
Order = order;
cofactor = cofactor_short = cof;
if (cof > 0) {
L = order / cof;
assert(is_prime(L));
}
assert(!power_gen_xz(1).is_infty());
assert(power_gen_xz(Order).is_infty());
}
// computes u(P+Q)*u(P-Q) as X/Z
MontgomeryCurve::PointXZ MontgomeryCurve::add_xz(const MontgomeryCurve::PointXZ& P,
const MontgomeryCurve::PointXZ& Q) const {
Residue u = (P.X + P.Z) * (Q.X - Q.Z);
Residue v = (P.X - P.Z) * (Q.X + Q.Z);
return MontgomeryCurve::PointXZ(sqr(u + v), sqr(u - v));
}
// computes u(2P) as X/Z
MontgomeryCurve::PointXZ MontgomeryCurve::double_xz(const MontgomeryCurve::PointXZ& P) const {
Residue u = sqr(P.X + P.Z);
Residue v = sqr(P.X - P.Z);
Residue w = u - v;
return PointXZ(u * v, w * (v + Residue(a_short, ring) * w));
}
MontgomeryCurve::PointXZ MontgomeryCurve::power_gen_xz(const Bignum& n) const {
return power_xz(Gu, n);
}
MontgomeryCurve::PointXZ MontgomeryCurve::power_xz(const Residue& u, const Bignum& n) const {
return power_xz(PointXZ(u), n);
}
// computes u([n]P) in form X/Z
MontgomeryCurve::PointXZ MontgomeryCurve::power_xz(const PointXZ& A, const Bignum& n) const {
assert(n >= 0);
if (n == 0) {
return PointXZ(ring);
}
int k = n.num_bits();
PointXZ P(A);
PointXZ Q(double_xz(P));
for (int i = k - 2; i >= 0; --i) {
PointXZ PQ(add_xz(P, Q));
PQ.X *= A.Z;
PQ.Z *= A.X;
if (n[i]) {
P = PQ;
Q = double_xz(Q);
} else {
Q = PQ;
P = double_xz(P);
}
}
return P;
}
bool MontgomeryCurve::PointXZ::export_point_y(unsigned char buffer[32]) const {
if ((X + Z).is_zero()) {
std::memset(buffer, 0xff, 32);
return false;
} else {
get_y().extract().export_lsb(buffer, 32);
return true;
}
}
bool MontgomeryCurve::PointXZ::export_point_u(unsigned char buffer[32]) const {
if (Z.is_zero()) {
std::memset(buffer, 0xff, 32);
return false;
} else {
get_u().extract().export_lsb(buffer, 32);
return true;
}
}
MontgomeryCurve::PointXZ MontgomeryCurve::import_point_u(const unsigned char point[32]) const {
Bignum u;
u.import_lsb(point, 32);
u[255] = 0;
return PointXZ(Residue(u, ring));
}
MontgomeryCurve::PointXZ MontgomeryCurve::import_point_y(const unsigned char point[32]) const {
Bignum y;
y.import_lsb(point, 32);
y[255] = 0;
return PointXZ(Residue(y, ring), true);
}
const MontgomeryCurve& Curve25519() {
static const MontgomeryCurve Curve25519 = [] {
MontgomeryCurve res(486662, 9, Fp25519());
res.set_order_cofactor(hex_string{"80000000000000000000000000000000a6f7cef517bce6b2c09318d2e7ae9f68"}, 8);
return res;
}();
return Curve25519;
}
} // namespace ellcurve