[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/NeoResearch/csbiginteger-cpp/master/src/BigIntegerGMP.cpp [Back]  [Original]

// SPDX-License-Identifier:  LGPL-3.0-or-later AND MIT
// Copyright (C) 2020-2022 - csbiginteger-cpp project

#include 

//
// using gmp as internal computation method
// TODO(igormcoelho): abandon this in favor of more portable libraries
// sudo apt install libgmp (or libgmp-dev)
#include 
#include 
#include 

// c++
#include   // TODO(igormcoelho): remove

// Ported from
// -
// https://referencesource.microsoft.com/#System.Numerics/System/Numerics/BigInteger.cs

// using namespace std;
using namespace csbiginteger;  // NOLINT

// input is raw little-endian format
mpz_class csBigIntegerMPZparse(cs_vbyte n);

// string parse
mpz_class csBigIntegerMPZparses(std::string n, int base);

// get bitstring from mpz bignum non-negative object
std::string csBigIntegerGetBitsFromNonNegativeMPZ(mpz_class big);

// get big-endian bytearray from mpz bignum (positive or negative)
cs_vbyte csBigIntegerGetBytesFromMPZ(mpz_class big);

// ==================== END MPZ =======================

std::string BigInteger::getEngine() { return "GMP"; }

const BigInteger BigInteger::error() {
  BigInteger big;
  big._data = cs_vbyte(0);  // empty array is error
  return big;
}

BigInteger BigInteger::Pow(BigInteger value, int exponent) {
  // according to C# spec, only non-negative int32 values accepted here
  if (exponent < 0) return BigInteger::Error();
  mpz_class big1 = csBigIntegerMPZparse(value.ToByteArray());
  mpz_class r;
  uint64_t _exp = exponent;
  mpz_pow_ui(r.get_mpz_t(), big1.get_mpz_t(), _exp);
  cs_vbyte vr = csBigIntegerGetBytesFromMPZ(r);
  reverse(vr.begin(), vr.end());  // to little-endian
  return BigInteger(vr);
}

// default is base 10
// allows base 2
// if base 16, prefix '0x' indicates big-endian, otherwise is little-endian
BigInteger::BigInteger(std::string str, int base) {
  mpz_class a = csBigIntegerMPZparses(str, base);
  _data = csBigIntegerGetBytesFromMPZ(a);
}

BigInteger::BigInteger(float val) {
  mpz_class a = val;

  _data = csBigIntegerGetBytesFromMPZ(a);
}

cs_int32 BigInteger::toInt() const {
  cs_vbyte vb = this->ToByteArray();  // little-endian
  mpz_class a = csBigIntegerMPZparse(vb);
  cs_int32 i = a.get_ui();  // unsigned int
  if (a < 0) i *= -1;
  return i;
}

cs_int64 BigInteger::toLong() const {
  cs_vbyte vb = this->ToByteArray();  // little-endian
  mpz_class a = csBigIntegerMPZparse(vb);
  cs_int64 i = a.get_si();  // signed long int
  return i;
}

bool BigInteger::operator>(const BigInteger& big2) const {
  if (this->IsError() || big2.IsError()) return false;

  mpz_class bThis =
      csBigIntegerMPZparse(this->ToByteArray());  // parse from little-endian
  mpz_class bOther =
      csBigIntegerMPZparse(big2.ToByteArray());  // parse from little-endian

  bool r = (bThis > bOther);  // result
  return r;
}

bool BigInteger::operatorIsError() || big2.IsError()) {
    return false;
  }

  mpz_class bThis =
      csBigIntegerMPZparse(this->ToByteArray());  // parse from little-endian
  mpz_class bOther =
      csBigIntegerMPZparse(big2.ToByteArray());  // parse from little-endian

  bool r = (bThis < bOther);  // result
  return r;
}

// ----------------- arithmetic ---------------------

BigInteger BigInteger::operator+(const BigInteger& big2) const {
  if (this->IsError() || big2.IsError()) return Error();

  mpz_class bThis =
      csBigIntegerMPZparse(this->ToByteArray());  // parse from little-endian
  mpz_class bOther =
      csBigIntegerMPZparse(big2.ToByteArray());  // parse from little-endian
  BigInteger r;                                  // result
  r._data = csBigIntegerGetBytesFromMPZ(bThis + bOther);  // get big-endian
  return r;
}

BigInteger BigInteger::operator-(const BigInteger& big2) const {
  if (this->IsError() || big2.IsError()) return Error();

  mpz_class bThis =
      csBigIntegerMPZparse(this->ToByteArray());  // parse from little-endian
  mpz_class bOther =
      csBigIntegerMPZparse(big2.ToByteArray());  // parse from little-endian
  BigInteger r;                                  // result
  r._data = csBigIntegerGetBytesFromMPZ(bThis - bOther);  // get big-endian
  return r;
}

BigInteger BigInteger::operator*(const BigInteger& big2) const {
  if (this->IsError() || big2.IsError()) return Error();

  mpz_class bThis =
      csBigIntegerMPZparse(this->ToByteArray());  // parse from little-endian
  mpz_class bOther =
      csBigIntegerMPZparse(big2.ToByteArray());  // parse from little-endian
  BigInteger r;                                  // result
  r._data = csBigIntegerGetBytesFromMPZ(bThis * bOther);  // get big-endian
  return r;
}

BigInteger BigInteger::operator/(const BigInteger& big2) const {
  if (this->IsError() || big2.IsError() || big2.IsZero()) return Error();
  mpz_class bThis =
      csBigIntegerMPZparse(this->ToByteArray());  // parse from little-endian
  mpz_class bOther =
      csBigIntegerMPZparse(big2.ToByteArray());  // parse from little-endian
  BigInteger r;                                  // result
  r._data = csBigIntegerGetBytesFromMPZ(bThis / bOther);  // get big-endian
  return r;
}

BigInteger BigInteger::operator%(const BigInteger& big2) const {
  if (this->IsError() || big2.IsError() || big2.IsZero()) return Error();

  mpz_class bThis =
      csBigIntegerMPZparse(this->ToByteArray());  // parse from little-endian
  mpz_class bOther =
      csBigIntegerMPZparse(big2.ToByteArray());  // parse from little-endian
  BigInteger r;                                  // result
  r._data = csBigIntegerGetBytesFromMPZ(bThis % bOther);  // get big-endian
  return r;
}

BigInteger BigInteger::operator> -big2;

  mpz_class bThis =
      csBigIntegerMPZparse(this->ToByteArray());  // parse from little-endian
  BigInteger r;                                   // result
  r._data =
      csBigIntegerGetBytesFromMPZ(bThis >(const BigInteger& big2) const {
  if (this->IsError() || big2.IsError()) return Error();
  if (big2 < Zero()) return (*this) ToByteArray());  // parse from little-endian
  BigInteger r;                                   // result
  r._data =
      csBigIntegerGetBytesFromMPZ(bThis >> big2.toInt());  // get big-endian
  return r;
}

// =================== BEGIN MPZ AGAIN =======================

std::string BigInteger::toStringBase10() const {
  mpz_class bThis =
      csBigIntegerMPZparse(this->ToByteArray());  // parse from little-endian
  return bThis.get_str(10);
}

// assumes big >= 0
std::string csBigIntegerGetBitsFromNonNegativeMPZ(mpz_class big) {
  std::string sbin;
  while (big > 0) {
    mpz_class rest = (big % 2);
    sbin.insert(0, (rest.get_ui() == 0 ? std::string("0") : std::string("1")));
    big = big / 2;
  }
  return sbin;
}

cs_vbyte csBigIntegerGetBytesFromMPZ(mpz_class big) {
  // check if positive or negative
  if (big >= 0) {
    // -------------------
    // positive conversion
    // -------------------
    cs_vbyte v;
    while (big > 0) {
      mpz_class rest = (big % 256);
      v.push_back((cs_byte)rest.get_ui());
      big = big / 256;
    }

    // added in little-endian format (backwards)
    std::string leHex = Helper::toHexString(v);
    if (leHex.length() == 0) leHex = "00";
    // check if became negative
    if (Helper::checkNegativeBit(leHex)) {
      v.push_back(0);  // guarantee non-negative
    }

    // v is added backwards (little-endian), must reverse (to big-endian)
    reverse(v.begin(), v.end());
    if (v.size() == 0) v.push_back(0x00);
    // finished
    return v;
  } else {
    // -------------------
    // negative conversion
    // -------------------
    // turn into positive
    mpz_class x = big * (-1);
    // cout 

Web Proxy Viewer  |  New URL  |  Original Page