/*
  uint2048_t Class
  Written by John Ryland
  (C) Copyright 2015
*/
#ifndef INTEGER_H
#define INTEGER_H

#include <stdint.h>
#include <vector>
#include <string>
#include <memory>

/*
  uint2048_t is a class that behaves similar to a regular built in type
  however it can represent arbitrarily large values, eg 1024 bit numbers
  which is commonly the case in cryptographic code or other special uses
  of maths. As its name suggests, it only holds integers, and positive
  ones at that. Treat it like you would an unsigned int that can't
  overflow, and in the case where it could go negative, it truncates to
  zero (this happens when subtracting a larger number from a smaller one).

  Note that this class has optimizations depending on the size of the
  numbers used, so it could be susceptible to timing based side-channel
  attacks.
*/
class uint2048_t
{
public:
  uint2048_t();                            // Default constructor (the value will be zero)
  uint2048_t(const uint2048_t& other);     // Copy constructor
  uint2048_t(uint64_t a_number);           // Create from a number
  uint2048_t(const char* str);             // Create from a string
  ~uint2048_t();                           // Destructor
  void operator=(const uint2048_t& other); // Assignment operator

  // Operator overloads
  bool operator!() const; // Is zero
  bool operator<(const uint2048_t& other) const;
  bool operator>(const uint2048_t& other) const;
  bool operator<=(const uint2048_t& other) const;
  bool operator>=(const uint2048_t& other) const;
  bool operator==(const uint2048_t& other) const;
  bool operator!=(const uint2048_t& other) const;
  bool operator&&(const uint2048_t& other) const;
  bool operator||(const uint2048_t& other) const;
  uint2048_t operator>>(int shift) const;
  uint2048_t operator<<(int shift) const;
  uint2048_t operator--(int);
  uint2048_t operator++(int);
  uint2048_t operator-(const uint2048_t& other) const;
  uint2048_t operator+(const uint2048_t& other) const;
  uint2048_t operator*(const uint2048_t& other) const;
  uint2048_t operator/(const uint2048_t& other) const;
  uint2048_t operator%(const uint2048_t& other) const;
  uint2048_t operator&(const uint2048_t& other) const;
  uint2048_t operator|(const uint2048_t& other) const;
  uint2048_t operator^(const uint2048_t& other) const;
  uint2048_t operator~() const;
  uint2048_t& operator>>=(int shift);
  uint2048_t& operator<<=(int shift);
  uint2048_t& operator--();
  uint2048_t& operator++();
  uint2048_t& operator-=(const uint2048_t& other);
  uint2048_t& operator+=(const uint2048_t& other);
  uint2048_t& operator*=(const uint2048_t& other);
  uint2048_t& operator/=(const uint2048_t& other);
  uint2048_t& operator%=(const uint2048_t& other);
  uint2048_t& operator&=(const uint2048_t& other);
  uint2048_t& operator|=(const uint2048_t& other);
  uint2048_t& operator^=(const uint2048_t& other);

  explicit operator std::string() const;
  explicit operator uint64_t() const;
  uint8_t operator[](size_t index) const;
  void Print() const;
  size_t Size() const;

  // Returns the quotent, and modulus in modulusResult of numerator / denominator
  static uint2048_t DivMod(const uint2048_t& numerator, const uint2048_t& denominator, uint2048_t& modulusResult);

  // Returns the result of:  base ^ exponent % modulus
  static uint2048_t ExpMod(const uint2048_t& base, const uint2048_t& exponent, const uint2048_t& modulus);

private:
  // Implementation hidden behind pimpl
  // helps with compile times
  // helps maintain binary compatibility
  // makes it possible to easily swap out implementations
  struct Pimpl;
  std::unique_ptr<Pimpl> m_pimpl;
};

#endif // INTEGER_H

