mirror of
				https://github.com/ton-blockchain/ton
				synced 2025-03-09 15:40:10 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			176 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			176 lines
		
	
	
	
		
			4.5 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 "residue.h"
 | 
						|
 | 
						|
// --- impl
 | 
						|
#include <assert.h>
 | 
						|
 | 
						|
namespace arith {
 | 
						|
class Residue;
 | 
						|
class ResidueRing;
 | 
						|
 | 
						|
void ResidueRing::init() {
 | 
						|
  Zero = new Residue(0, td::Ref<ResidueRing>(this));
 | 
						|
  One = new Residue(1, td::Ref<ResidueRing>(this));
 | 
						|
}
 | 
						|
 | 
						|
ResidueRing::~ResidueRing() {
 | 
						|
  delete Zero;
 | 
						|
  delete One;
 | 
						|
  delete Img_i;
 | 
						|
  Zero = One = Img_i = 0;
 | 
						|
}
 | 
						|
 | 
						|
const Residue operator+(const Residue& x, const Residue& y) {
 | 
						|
  x.same_ring(y);
 | 
						|
  Residue z(x.ring_ref());
 | 
						|
  bn_assert(BN_mod_add(z.val.bn_ptr(), x.val.bn_ptr(), y.val.bn_ptr(), x.modulus().bn_ptr(), get_ctx()));
 | 
						|
  return z;
 | 
						|
}
 | 
						|
 | 
						|
const Residue operator-(const Residue& x, const Residue& y) {
 | 
						|
  x.same_ring(y);
 | 
						|
  Residue z(x.ring_ref());
 | 
						|
  bn_assert(BN_mod_sub(z.val.bn_ptr(), x.val.bn_ptr(), y.val.bn_ptr(), x.modulus().bn_ptr(), get_ctx()));
 | 
						|
  return z;
 | 
						|
}
 | 
						|
 | 
						|
const Residue operator*(const Residue& x, const Residue& y) {
 | 
						|
  x.same_ring(y);
 | 
						|
  Residue z(x.ring_ref());
 | 
						|
  bn_assert(BN_mod_mul(z.val.bn_ptr(), x.val.bn_ptr(), y.val.bn_ptr(), x.modulus().bn_ptr(), get_ctx()));
 | 
						|
  return z;
 | 
						|
}
 | 
						|
 | 
						|
const Residue operator-(const Residue& x) {
 | 
						|
  Residue z(x);
 | 
						|
  z.val.negate();
 | 
						|
  return z.reduce();
 | 
						|
}
 | 
						|
 | 
						|
Residue& Residue::operator+=(const Residue& y) {
 | 
						|
  same_ring(y);
 | 
						|
  bn_assert(BN_mod_add(val.bn_ptr(), val.bn_ptr(), y.val.bn_ptr(), modulus().bn_ptr(), get_ctx()));
 | 
						|
  return *this;
 | 
						|
}
 | 
						|
 | 
						|
Residue& Residue::operator-=(const Residue& y) {
 | 
						|
  same_ring(y);
 | 
						|
  bn_assert(BN_mod_sub(val.bn_ptr(), val.bn_ptr(), y.val.bn_ptr(), modulus().bn_ptr(), get_ctx()));
 | 
						|
  return *this;
 | 
						|
}
 | 
						|
 | 
						|
Residue& Residue::operator*=(const Residue& y) {
 | 
						|
  same_ring(y);
 | 
						|
  bn_assert(BN_mod_mul(val.bn_ptr(), val.bn_ptr(), y.val.bn_ptr(), modulus().bn_ptr(), get_ctx()));
 | 
						|
  return *this;
 | 
						|
}
 | 
						|
 | 
						|
bool operator==(const Residue& x, const Residue& y) {
 | 
						|
  x.same_ring(y);
 | 
						|
  return x.extract() == y.extract();
 | 
						|
}
 | 
						|
 | 
						|
bool operator!=(const Residue& x, const Residue& y) {
 | 
						|
  x.same_ring(y);
 | 
						|
  return x.extract() != y.extract();
 | 
						|
}
 | 
						|
 | 
						|
Residue sqr(const Residue& x) {
 | 
						|
  Residue z(x.ring_ref());
 | 
						|
  bn_assert(BN_mod_sqr(z.val.bn_ptr(), x.val.bn_ptr(), x.modulus().bn_ptr(), get_ctx()));
 | 
						|
  return z;
 | 
						|
}
 | 
						|
 | 
						|
Residue power(const Residue& x, const Bignum& y) {
 | 
						|
  Residue z(x.ring_ref());
 | 
						|
  bn_assert(BN_mod_exp(z.val.bn_ptr(), x.val.bn_ptr(), y.bn_ptr(), x.modulus().bn_ptr(), get_ctx()));
 | 
						|
  return z;
 | 
						|
}
 | 
						|
 | 
						|
Residue inverse(const Residue& x) {
 | 
						|
  assert(x.ring_ref()->is_prime());
 | 
						|
  return power(x, x.ring_ref()->get_modulus() - 2);
 | 
						|
}
 | 
						|
 | 
						|
const Residue& ResidueRing::img_i() const {
 | 
						|
  if (!Img_i) {
 | 
						|
    assert(is_prime());
 | 
						|
    assert(modulus % 4 == 1);
 | 
						|
    int g = 2;
 | 
						|
    Bignum n = (modulus - 1) / 4;
 | 
						|
    while (true) {
 | 
						|
      Residue t = power(frac(g), n);
 | 
						|
      if (t != one() && t != frac(-1)) {
 | 
						|
        Img_i = new Residue(t);
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      g++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return *Img_i;
 | 
						|
}
 | 
						|
 | 
						|
Residue sqrt(const Residue& x) {
 | 
						|
  assert(x.ring_of().is_prime());
 | 
						|
  const ResidueRing& R = x.ring_of();
 | 
						|
  const Bignum& p = R.get_modulus();
 | 
						|
  if (x.is_zero() || !p.odd()) {
 | 
						|
    return x;
 | 
						|
  }
 | 
						|
  if (p[1]) {  // p=3 (mod 4)
 | 
						|
    return power(x, (p + 1) >> 2);
 | 
						|
  } else if (p[2]) {
 | 
						|
    // p=5 (mod 8)
 | 
						|
    Residue t = power(x, (p + 3) >> 3);
 | 
						|
    return (sqr(t) == x) ? t : R.img_i() * t;
 | 
						|
  } else {
 | 
						|
    assert(p[2]);
 | 
						|
    return R.zero();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
Residue ResidueRing::frac(long num, long denom) const {
 | 
						|
  assert(denom);
 | 
						|
  if (denom < 0) {
 | 
						|
    num = -num;
 | 
						|
    denom = -denom;
 | 
						|
  }
 | 
						|
  if (!(num % denom)) {
 | 
						|
    return Residue(num / denom, self_ref());
 | 
						|
  } else {
 | 
						|
    return Residue(num, self_ref()) * inverse(Residue(denom, self_ref()));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
std::string Residue::to_str() const {
 | 
						|
  return "Mod(" + val.to_str() + "," + modulus().to_str() + ")";
 | 
						|
}
 | 
						|
 | 
						|
std::ostream& operator<<(std::ostream& os, const Residue& x) {
 | 
						|
  return os << x.to_str();
 | 
						|
}
 | 
						|
 | 
						|
std::istream& operator>>(std::istream& is, Residue& x) {
 | 
						|
  std::string word;
 | 
						|
  is >> word;
 | 
						|
  x = dec_string(word);
 | 
						|
  return is;
 | 
						|
}
 | 
						|
}  // namespace arith
 |