/* 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 . Copyright 2017-2020 Telegram Systems LLP */ #include "ellcurve/Montgomery.h" #include #include 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