mirror of
				https://github.com/ton-blockchain/ton
				synced 2025-03-09 15:40:10 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			138 lines
		
	
	
	
		
			3.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			138 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-2020 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
 |