Browse Source

Half-implenentation of RLP encoder and Merkle tree hasher.

cl-refactor
Gav Wood 11 years ago
parent
commit
e2b1a2ceda
  1. 8
      Common.h
  2. 22
      PatriciaTree.cpp
  3. 198
      PatriciaTree.h
  4. 58
      RLP.h
  5. 87
      VirtualMachine.h
  6. 29
      sha256.cpp
  7. 5
      sha256.h
  8. 600
      uint128_t.h
  9. 606
      uint256_t.h

8
Common.h

@ -5,15 +5,19 @@
#include <cstdint>
#include <boost/multiprecision/cpp_int.hpp>
#include "foreign.h"
#include "uint256_t.h"
namespace eth
{
using byte = uint8_t;
using Bytes = foreign<byte>;
using ConstBytes = foreign<byte const>;
using bytes = vector<byte>;
using fBytes = foreign<byte>;
using fConstBytes = foreign<byte const>;
using bigint = boost::multiprecision::cpp_int;
using u256 = uint256_t;
using uint = uint64_t;
using sint = int64_t;

22
PatriciaTree.cpp

@ -0,0 +1,22 @@
#include "Common.h"
#include "PatriciaTree.h"
using namespace std;
using namespace eth;
PatriciaTree::PatriciaTree(RLP const& _data)
{
// Make tree based on _data
assert(_data.isList());
if (_data.isEmpty())
{
// NULL node.
}
else if (_data.isList() && _data.itemCount() == 2)
{
// Key-value pair
}
else if (_data.isList() && _data.itemCount() == 17)
{
// Branch
}
}

198
PatriciaTree.h

@ -0,0 +1,198 @@
#pragma once
#include <map>
#include "RLP.h"
namespace eth
{
using StringMap = std::map<std::string, std::string>;
using HexMap = std::map<bytes, std::string>;
/*
* Hex-prefix Notation. First nibble has flags: oddness = 2^0 & termination = 2^1
* [0,0,1,2,3,4,5] 0x10012345
* [0,1,2,3,4,5] 0x00012345
* [1,2,3,4,5] 0x112345
* [0,0,1,2,3,4] 0x00001234
* [0,1,2,3,4] 0x101234
* [1,2,3,4] 0x001234
* [0,0,1,2,3,4,5,T] 0x30012345
* [0,0,1,2,3,4,T] 0x20001234
* [0,1,2,3,4,5,T] 0x20012345
* [1,2,3,4,5,T] 0x312345
* [1,2,3,4,T] 0x201234
*/
std::string fromHex(bytes const& _hexVector, bool _forceTerminated = false)
{
uint begin = 0;
uint end = _hexVector.size();
bool termed = _forceTerminated;
bool odd = _hexVector.size() % 2;
std::string ret(((termed ? 2 : 0) | (odd ? 1 : 0)) * 16, 1);
if (odd)
{
ret[0] |= _hexVector[0];
begin = 1;
}
else if (leadingZero)
for (uint i = begin; i < end; i += 2)
ret += _hexVector[i] * 16 + _hexVector[i + 1];
return ret;
}
template <class _T, class ... _Ts> bytes encodeRLP(_T _t, _Ts ... _ts)
{
}
struct rlplist { rlplist(uint _count): count(_count) {} uint count; };
class RLPStream
{
public:
RLPStream() {}
void append(uint _s) { appendNumeric(_s); }
void append(u256 _s) { appendNumeric(_s); }
void append(bigint _s) { appendNumeric(_s); }
void append(std::string const& _s)
{
if (_s.size() < 0x38)
m_out.push_back(_count | 0x40);
else
pushCount(_count, 0x40);
uint os = m_out.size();
m_out.resize(m_out.size() + _s.size());
memcpy(m_out.data() + os, _s.data(), _s.size());
}
void appendList(uint _count)
{
if (_s.size() < 0x38)
m_out.push_back(_count | 0x80);
else
pushCount(_count, 0x80);
}
RLPStream operator<<(uint _t) { append(_i); }
RLPStream operator<<(u256 _t) { append(_i); }
RLPStream operator<<(bigint _t) { append(_i); }
RLPStream operator<<(std::string const& _s) { append(_s); }
RLPStream operator<<(rlplist _l) { m_lists.push_back(_l.count); appendList(_l.count); }
private:
void appendNumeric(uint _i)
{
if (_i < 0x18)
m_out.push_back(_i);
else
m_out.push_back(bytesRequired(_i) + 0x17); // max 8 bytes.
}
void appendNumeric(u256 _i)
{
if (_i < 0x18)
m_out.push_back(_i);
else
m_out.push_back(bytesRequired(_i) + 0x17); // max 32 bytes.
}
void appendNumeric(bigint _i)
{
if (_i < 0x18)
m_out.push_back(_i);
else
{
uint br = bytesRequired(_i);
if (br <= 32)
m_out.push_back(bytesRequired(_i) + 0x17); // max 32 bytes.
else
m_out.push_back(0x37 + bytesRequired(br));
}
for (uint i = 0; i < )
m_out.push_back()
}
void pushCount(uint _count, byte _base)
{
m_out.push_back(bytesRequired(_i) + 0x17); // max 8 bytes.
}
template <class _T> static uint bytesRequired(_T _i)
{
_i >>= 8;
uint i = 1;
for (; _i != 0; ++i, _i >>= 8) {}
return i;
}
bytes m_out;
};
template <> bytes encodeRLP(_T _t)
{
}
u256 hash256aux(HexMap const& _s, HexMap::const_iterator _begin, HexMap::const_iterator _end, unsigned _preLen)
{
unsigned c = 0;
for (auto i = _begin; i != _end; ++i, ++c) {}
assert(c > 0);
if (c == 1)
return sha256(encodeRLP());
for (auto i = 0; i < 16; ++i)
{
}
}
bytes toHex(std::string const& _s)
{
std::vector<uint8_t> ret(_s.size() * 2 + 1);
for (auto i: _s)
{
ret.push_back(i / 16);
ret.push_back(i % 16);
}
ret.push_back(16);
return ret;
}
u256 hash256(StringMap const& _s)
{
// build patricia tree.
if (_s.empty())
return 0;
HexMap hexMap;
for (auto const& i: _s)
hexMap[toHex(i.first)] = i.second;
return hash256aux(hexMap, hexMap.cbegin(), hexMap.cend(), 0);
}
/**
* @brief Merkle Patricia Tree: a modifed base-16 Radix tree.
*/
class PatriciaTree
{
public:
PatriciaTree() {}
~PatriciaTree() {}
void fromRLP(RLP const& _data);
std::string toRLP();
private:
};
}

58
RLP.h

@ -23,13 +23,13 @@ public:
RLP() {}
/// Construct a node of value given in the bytes.
explicit RLP(ConstBytes _d): m_data(_d) {}
explicit RLP(fConstBytes _d): m_data(_d) {}
/// Construct a node to read RLP data in the bytes given.
RLP(byte const* _b, uint _s): m_data(ConstBytes(_b, _s)) {}
RLP(byte const* _b, uint _s): m_data(fConstBytes(_b, _s)) {}
/// Construct a node to read RLP data in the string.
explicit RLP(std::string const& _s): m_data(ConstBytes((byte const*)_s.data(), _s.size())) {}
explicit RLP(std::string const& _s): m_data(fConstBytes((byte const*)_s.data(), _s.size())) {}
/// @returns true if the RLP is non-null.
explicit operator bool() const { return !isNull(); }
@ -37,20 +37,32 @@ public:
/// No value.
bool isNull() const { return m_data.size() == 0; }
/// Contains a zero-length string or zero-length list.
bool isEmpty() const { return m_data[0] == 0x40 || m_data[0] == 0x80; }
/// String value.
bool isString() const { assert(!isNull()); return m_data[0] >= 0x40 && m_data[0] < 0x80; }
/// List value.
bool isList() const { assert(!isNull()); return m_data[0] >= 0x80 && m_data[0] < 0xc0; }
/// Integer value. Either isNormalInt() or isBigInt().
/// Integer value. Either isSlimInt() or isBigInt().
bool isInt() const { assert(!isNull()); return m_data[0] < 0x40; }
/// Fits into eth::uint type. Can use toInt() to read.
bool isNormalInt() const { assert(!isNull()); return m_data[0] < 0x18; }
/// Fits into eth::uint type. Can use toInt() to read (as well as toBigInt() or toHugeInt() ).
bool isSlimInt() const { assert(!isNull()); return m_data[0] < 0x20; }
/// Fits only into eth::u256 type. Use only toFatInt() or toBigInt() to read.
bool isFatInt() const { assert(!isNull()); return m_data[0] >= 0x20 && m_data[0] < 0x38; }
/// Fits only into eth::bigint type. Use only toBigInt() to read.
bool isBigInt() const { assert(!isNull()); return m_data[0] < 0x40 && m_data[0] >= 0x18; }
bool isBigInt() const { assert(!isNull()); return m_data[0] >= 0x38 && m_data[0] < 0x40; }
/// @returns the number of items in the list, or zero if it isn't a list.
uint itemCount() const { return isList() ? items() : 0; }
/// @returns the number of characters in the string, or zero if it isn't a string.
uint stringSize() const { return isString() ? items() : 0; }
std::string toString() const
{
@ -59,32 +71,22 @@ public:
return payload().cropped(0, items()).toString();
}
uint toInt(uint _def = 0) const
template <class _T = uint> _T toInt(_T _def = 0) const
{
if (!isInt())
return _def;
if (isDirectValueInt())
return m_data[0];
uint ret = 0;
_T ret = 0;
auto s = intSize();
for (uint i = 0; i < s; ++i)
ret = (ret << 8) | m_data[i + 1];
return ret;
}
bigint toBigInt(bigint _def = 0) const
{
if (!isInt())
return _def;
if (isDirectValueInt())
return m_data[0];
bigint ret = 0;
auto s = intSize() - intLengthSize();
uint l = 1 + intLengthSize();
for (uint i = 0; i < s; ++i)
ret = (ret << 8) | m_data[i + l];
return ret;
}
uint toSlimInt(uint _def = 0) const { return toInt<uint>(_def); }
u256 toFatInt(u256 _def = 0) const { return toInt<u256>(_def); }
bigint toBigInt(bigint _def = 0) const { return toInt<bigint>(_def); }
RLPs toList() const
{
@ -92,7 +94,7 @@ public:
if (!isList())
return ret;
uint64_t c = items();
ConstBytes d = payload();
fConstBytes d = payload();
for (uint64_t i = 0; i < c; ++i, d = d.cropped(RLP(d).size()))
ret.push_back(RLP(d));
return ret;
@ -122,7 +124,7 @@ private:
return payload().data() - m_data.data() + items();
if (isList())
{
ConstBytes d = payload();
fConstBytes d = payload();
uint64_t c = items();
for (uint64_t i = 0; i < c; ++i, d = d.cropped(RLP(d).size())) {}
return d.data() - m_data.data();
@ -144,14 +146,14 @@ private:
return ret;
}
ConstBytes payload() const
fConstBytes payload() const
{
assert(isString() || isList());
auto n = (m_data[0] & 0x3f);
return m_data.cropped(1 + (n < 0x38 ? 0 : (n - 0x37)));
}
ConstBytes m_data;
fConstBytes m_data;
};
}
@ -160,10 +162,8 @@ inline std::ostream& operator<<(std::ostream& _out, eth::RLP _d)
{
if (_d.isNull())
_out << "null";
else if (_d.isBigInt())
_out << _d.toBigInt();
else if (_d.isInt())
_out << _d.toInt();
_out << _d.toBigInt();
else if (_d.isString())
_out << "\"" << _d.toString() << "\"";
else if (_d.isList())

87
VirtualMachine.h

@ -1,50 +1,53 @@
#pragma once
#include <array>
#include <map>
#include <unordered_map>
#include "RLP.h"
#include "Common.h"
namespace eth
{
/// Virtual machine bytecode instruction.
enum class Instruction: uint8_t
{
Stop = 0x00, //halts execution
Add = 0x10, // Rx Ry Rz - sets Rz <- Rx + Ry mod 2^256
/* (11) SUB Rx Ry Rz - sets Rz <- Rx - Ry mod 2^256
(12) MUL Rx Ry Rz - sets Rz <- Rx * Ry mod 2^256
(13) DIV Rx Ry Rz - sets Rz <- floor(Rx / Ry)
(14) SDIV Rx Ry Rz - like DIV, except it treats values above 2^255 as negative (ie. 2^256 - x -> -x)
(15) MOD Rx Ry Rz - sets Rz <- Rx mod Ry
(16) SMOD Rx Ry Rz - like MOD, but for signed values just like SDIV (using Python's convention with negative numbers)
(17) EXP Rx Ry Rz - sets Rz <- Rx ^ Ry mod 2^256
(18) NEG Rx Ry - sets Ry <- 2^256 - Rx
(20) LT Rx Ry Rz - sets Rz <- 1 if Rx < Ry else 0
(21) LE Rx Ry Rz - sets Rz <- 1 if Rx <= Ry else 0
(22) GT Rx Ry Rz - sets Rz <- 1 if Rx > Ry else 0
(23) GE Rx Ry Rz - sets Rz <- 1 if Rx >= Ry else 0
(24) EQ Rx Ry Rz - sets Rz <- 1 if Rx = Ry else 0
(25) NOT Rx Ry - sets Ry <- 1 if Rx = 0 else 0
(30) SHA256 Rx Ry - sets Ry <- SHA256(Rx)
(31) RIPEMD160 Rx Ry - sets Ry <- RIPEMD160(Rx)
(32) ECMUL Rx Ry Rz Ra Rb - sets (Ra, Rb) = Rz * (Rx, Ry) in secp256k1, using (0,0) for the point at infinity
(33) ECADD Rx Ry Rz Ra Rb Rc - sets (Rb, Rc) = (Rx, Ry) + (Ra, Rb)
(34) SIGN Rx Ry Rz Ra Rb - sets(Rz, Ra, Rb)as the(r,s,prefix)values of an Electrum-style RFC6979 deterministic signature ofRxwith private keyRy`
(35) RECOVER Rx Ry Rz Ra Rb Rc - sets(Rb, Rc)as the public key from the signature(Ry, Rz, Ra)of the message hashRx`
(40) COPY Rx Ry - copies Ry <- Rx
(41) ST Rx Ry - sets M[Ry] <- Rx
(42) LD Rx Ry - sets Ry <- M[Rx]
(43) SET Rx V1 V2 V3 V4 - sets Rx <- V1 + 2^8*V2 + 2^16*V3 + 2^24*V4 (where 0 <= V[i] <= 255)
(50) JMP Rx - sets the index pointer to the value at Rx
(51) JMPI Rx Ry - if Rx != 0, sets the index pointer to Ry
(52) IND Rx - sets Rx to the index pointer.
(60) EXTRO Rx Ry Rz - looks at the contract at address Rx and its memory state Ry, and outputs the result to Rz
(61) BALANCE Rx - returns the ether balance of address Rx
(70) MKTX Rx Ry Rz Rw Rv - sends Ry ether to Rx plus Rz fee with Rw data items starting from memory index Rv (and then reading to (Rv + 1), (Rv + 2) etc). Note that if Rx = 0 then this creates a new contract.
(80) DATA Rx Ry - sets Ry to data item index Rx if possible, otherwise zero
(81) DATAN Rx - sets Rx to the number of data items
(90) MYADDRESS Rx - sets Rx to the contract's own address*/
Suicide = 0xff //Rx - destroys the contract and clears all memory, sending the entire balance plus the negative fee from clearing memory minus TXFEE to the address
STOP = 0x00, ///< halts execution
ADD = 0x10, ///< Rx Ry Rz - sets Rz <- Rx + Ry mod 2^256
SUB, ///< Rx Ry Rz - sets Rz <- Rx - Ry mod 2^256
MUL, ///< Rx Ry Rz - sets Rz <- Rx * Ry mod 2^256
DIV, ///< Rx Ry Rz - sets Rz <- floor(Rx / Ry)
SDIV, ///< Rx Ry Rz - like DIV, except it treats values above 2^255 as negative (ie. 2^256 - x -> -x)
MOD, ///< Rx Ry Rz - sets Rz <- Rx mod Ry
SMOD, ///< Rx Ry Rz - like MOD, but for signed values just like SDIV (using Python's convention with negative numbers)
EXP, ///< Rx Ry Rz - sets Rz <- Rx ^ Ry mod 2^256
NEG, ///< Rx Ry - sets Ry <- 2^256 - Rx
LT = 0x20, ///< Rx Ry Rz - sets Rz <- 1 if Rx < Ry else 0
LE, ///< Rx Ry Rz - sets Rz <- 1 if Rx <= Ry else 0
GT, ///< Rx Ry Rz - sets Rz <- 1 if Rx > Ry else 0
GE, ///< Rx Ry Rz - sets Rz <- 1 if Rx >= Ry else 0
EQ, ///< Rx Ry Rz - sets Rz <- 1 if Rx = Ry else 0
NOT, ///< Rx Ry - sets Ry <- 1 if Rx = 0 else 0
SHA256 = 0x30, ///< Rx Ry - sets Ry <- SHA256(Rx)
RIPEMD160, ///< Rx Ry - sets Ry <- RIPEMD160(Rx)
ECMUL, ///< Rx Ry Rz Ra Rb - sets (Ra, Rb) = Rz * (Rx, Ry) in secp256k1, using (0,0) for the point at infinity
ECADD, ///< Rx Ry Rz Ra Rb Rc - sets (Rb, Rc) = (Rx, Ry) + (Ra, Rb)
SIGN, ///< Rx Ry Rz Ra Rb - sets(Rz, Ra, Rb)as the(r,s,prefix)values of an Electrum-style RFC6979 deterministic signature ofRxwith private keyRy`
RECOVER, ///< Rx Ry Rz Ra Rb Rc - sets(Rb, Rc)as the public key from the signature(Ry, Rz, Ra)of the message hashRx`
COPY = 0x40, ///< Rx Ry - copies Ry <- Rx
ST, ///< Rx Ry - sets M[Ry] <- Rx
LD, ///< Rx Ry - sets Ry <- M[Rx]
SET, ///< Rx V1 V2 V3 V4 - sets Rx <- V1 + 2^8*V2 + 2^16*V3 + 2^24*V4 (where 0 <= V[i] <= 255)
JMP = 0x50, ///< Rx - sets the index pointer to the value at Rx
JMPI, ///< Rx Ry - if Rx != 0, sets the index pointer to Ry
IND, ///< Rx - sets Rx to the index pointer.
EXTRO = 0x60, ///< Rx Ry Rz - looks at the contract at address Rx and its memory state Ry, and outputs the result to Rz
BALANCE, ///< Rx - returns the ether balance of address Rx
MKTX = 0x70, ///< Rx Ry Rz Rw Rv - sends Ry ether to Rx plus Rz fee with Rw data items starting from memory index Rv (and then reading to (Rv + 1), (Rv + 2) etc). Note that if Rx = 0 then this creates a new contract.
DATA = 0x80, ///< Rx Ry - sets Ry to data item index Rx if possible, otherwise zero
DATAN, ///< Rx - sets Rx to the number of data items
MYADDRESS = 0x90, ///< Rx - sets Rx to the contract's own address
SUICIDE = 0xff ///< Rx - destroys the contract and clears all memory, sending the entire balance plus the negative fee from clearing memory minus TXFEE to the address
};
class VirtualMachine
@ -53,8 +56,18 @@ public:
VirtualMachine();
~VirtualMachine();
void initMemory(RLP _contract);
void setMemory(RLP _state);
private:
std::map<bigint, bigint> m_memory;
std::map<u256, u256> m_memory;
std::array<u256, 256> m_registers;
bigint m_stepCount;
bigint m_totalFee;
bigint m_stepFee;
bigint m_dataFee;
bigint m_memoryFee;
bigint m_extroFee;
};
}

29
sha256.cpp

@ -148,19 +148,30 @@ void SHA256::final(unsigned char *digest)
m_block[m_len] = 0x80;
SHA2_UNPACK32(len_b, m_block + pm_len - 4);
transform(m_block, block_nb);
for (i = 0 ; i < 8; i++) {
SHA2_UNPACK32(m_h[i], &digest[i << 2]);
}
}
std::string sha256(std::string input)
std::string sha256(std::string const& _input, bool _hex)
{
if (!_hex)
{
string ret(SHA256::DIGEST_SIZE);
SHA256 ctx = SHA256();
ctx.init();
ctx.update( (unsigned char*)_input.c_str(), _input.length());
ctx.final(ret.data());
return ret;
}
unsigned char digest[SHA256::DIGEST_SIZE];
memset(digest,0,SHA256::DIGEST_SIZE);
SHA256 ctx = SHA256();
ctx.init();
ctx.update( (unsigned char*)input.c_str(), input.length());
ctx.update( (unsigned char*)_input.c_str(), _input.length());
ctx.final(digest);
char buf[2*SHA256::DIGEST_SIZE+1];
@ -169,3 +180,17 @@ std::string sha256(std::string input)
sprintf(buf+i*2, "%02x", digest[i]);
return std::string(buf);
}
uint256_t sha256(bytes const& _input)
{
uint256_t ret = 0;
SHA256 ctx = SHA256();
ctx.init();
ctx.update(_input.data(), _input.size());
uint8_t buf[SHA256::DIGEST_SIZE];
ctx.final(buf);
for (uint i = 0; i < 32; ++i)
ret = (ret << 8) | buf[i];
return ret;
}

5
sha256.h

@ -1,6 +1,8 @@
#pragma once
#include <string>
#incldue "Common.h"
#include "uint256_t.h"
namespace eth
{
@ -28,7 +30,8 @@ protected:
uint32 m_h[8];
};
std::string sha256(std::string input);
std::string sha256(std::string const& input, bool _hex);
uint256_t sha256(bytes const& input);
#define SHA2_SHFR(x, n) (x >> n)
#define SHA2_ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))

600
uint128_t.h

@ -0,0 +1,600 @@
/*
uint128_t.h
An unsigned 128 bit integer library for C++
By Jason Lee @ calccrypto@yahoo.com
with much help from Auston Sterling
And thanks to Stefan Deigmüller for finding
a bug in operator*.
From http://calccrypto.wikidot.com/programming:uint128-t
Licenced http://creativecommons.org/licenses/by-sa/3.0/
*/
#pragma once
#include <cstdlib>
#include <iostream>
#include <stdint.h>
class uint128_t{
private:
uint64_t UPPER, LOWER;
public:
// Constructors
uint128_t(){
UPPER = 0;
LOWER = 0;
}
template <typename T>
uint128_t(T rhs){
UPPER = 0;
LOWER = (uint64_t) rhs;
}
template <typename S, typename T>
uint128_t(const S upper_rhs, const T lower_rhs){
UPPER = (uint64_t) upper_rhs;
LOWER = (uint64_t) lower_rhs;
}
uint128_t(const uint128_t & rhs){
UPPER = rhs.UPPER;
LOWER = rhs.LOWER;
}
// RHS input args only
// Assignment Operator
template <typename T> uint128_t operator=(T rhs){
UPPER = 0;
LOWER = (uint64_t) rhs;
return *this;
}
uint128_t operator=(uint128_t rhs){
UPPER = rhs.UPPER;
LOWER = rhs.LOWER;
return *this;
}
// Typecast Operators
operator bool(){
return (bool) (UPPER | LOWER);
}
operator char(){
return (char) LOWER;
}
operator int(){
return (int) LOWER;
}
operator uint8_t(){
return (uint8_t) LOWER;
}
operator uint16_t(){
return (uint16_t) LOWER;
}
operator uint32_t(){
return (uint32_t) LOWER;
}
operator uint64_t(){
return LOWER;
}
// Bitwise Operators
template <typename T> uint128_t operator&(T rhs){
return uint128_t(0, LOWER & (uint64_t) rhs);
}
uint128_t operator&(uint128_t rhs){
return uint128_t(UPPER & rhs.UPPER, LOWER & rhs.LOWER);
}
template <typename T> uint128_t operator|(T rhs){
return uint128_t(UPPER, LOWER | (uint64_t) rhs);
}
uint128_t operator|(uint128_t rhs){
return uint128_t(UPPER | rhs.UPPER, LOWER | rhs.LOWER);
}
template <typename T> uint128_t operator^(T rhs){
return uint128_t(UPPER, LOWER ^ (uint64_t) rhs);
}
uint128_t operator^(uint128_t rhs){
return uint128_t(UPPER ^ rhs.UPPER, LOWER ^ rhs.LOWER);
}
template <typename T> uint128_t operator&=(T rhs){
UPPER = 0;
LOWER &= rhs;
return *this;
}
uint128_t operator&=(uint128_t rhs){
UPPER &= rhs.UPPER;
LOWER &= rhs.LOWER;
return *this;
}
template <typename T> uint128_t operator|=(T rhs){
LOWER |= (uint64_t) rhs;
return *this;
}
uint128_t operator|=(uint128_t rhs){
UPPER |= rhs.UPPER;
LOWER |= rhs.LOWER;
return *this;
}
template <typename T> uint128_t operator^=(T rhs){
LOWER ^= (uint64_t) rhs;
return *this;
}
uint128_t operator^=(const uint128_t rhs){
UPPER ^= rhs.UPPER;
LOWER ^= rhs.LOWER;
return *this;
}
uint128_t operator~(){
return uint128_t(~UPPER, ~LOWER);
}
// Bit Shift Operators
template <typename T>
uint128_t operator<<(const T shift){
if (shift >= 128)
return uint128_t(0, 0);
else if (shift == 64)
return uint128_t(LOWER, 0);
else if (shift == 0)
return *this;
else if (shift < 64)
return uint128_t((UPPER << shift) + (LOWER >> (64 - shift)), LOWER << shift);
else if ((128 > shift) && (shift > 64))
return uint128_t(LOWER << (shift - 64), 0);
else
return uint128_t(0);
}
template <typename T>
uint128_t operator>>(const T shift){
if (shift >= 128)
return uint128_t(0, 0);
else if (shift == 64)
return uint128_t(0, UPPER);
else if (shift == 0)
return *this;
else if (shift < 64)
return uint128_t(UPPER >> shift, (UPPER << (64 - shift)) + (LOWER >> shift));
else if ((128 > shift) && (shift > 64))
return uint128_t(0, (UPPER >> (shift - 64)));
else
return uint128_t(0);
}
uint128_t operator<<=(int shift){
*this = *this << shift;
return *this;
}
uint128_t operator>>=(int shift){
*this = *this >> shift;
return *this;
}
// Logical Operators
bool operator!(){
return !(bool) (UPPER | LOWER);
}
template <typename T> bool operator&&(T rhs){
return (bool) *this && rhs;
}
template <typename T> bool operator&&(uint128_t rhs){
return (bool) *this && (bool) rhs;
}
template <typename T> bool operator||(T rhs){
return ((bool) *this) || rhs;
}
template <typename T> bool operator||(uint128_t rhs){
return ((bool) *this) || (bool) rhs;
}
// Comparison Operators
template <typename T> bool operator==(T rhs){
return (!UPPER && (LOWER == (uint64_t) rhs));
}
bool operator==(uint128_t rhs){
return ((UPPER == rhs.UPPER) && (LOWER == rhs.LOWER));
}
template <typename T> bool operator!=(T rhs){
return (UPPER | (LOWER != (uint64_t) rhs));
}
bool operator!=(uint128_t rhs){
return ((UPPER != rhs.UPPER) | (LOWER != rhs.LOWER));
}
template <typename T> bool operator>(T rhs){
if (UPPER)
return true;
return (LOWER > (uint64_t) rhs);
}
bool operator>(uint128_t rhs){
if (UPPER == rhs.UPPER)
return (LOWER > rhs.LOWER);
if (UPPER > rhs.UPPER)
return true;
return false;
}
template <typename T> bool operator<(T rhs){
if (!UPPER)
return (LOWER < (uint64_t) rhs);
return false;
}
bool operator<(uint128_t rhs){
if (UPPER == rhs.UPPER)
return (LOWER < rhs.LOWER);
if (UPPER < rhs.UPPER)
return true;
return false;
}
template <typename T> bool operator>=(T rhs){
return ((*this > rhs) | (*this == rhs));
}
bool operator>=(uint128_t rhs){
return ((*this > rhs) | (*this == rhs));
}
template <typename T> bool operator<=(T rhs){
return ((*this < rhs) | (*this == rhs));
}
bool operator<=(uint128_t rhs){
return ((*this < rhs) | (*this == rhs));
}
// Arithmetic Operators
template <typename T> uint128_t operator+(T rhs){
return uint128_t(UPPER + ((LOWER + (uint64_t) rhs) < LOWER), LOWER + (uint64_t) rhs);
}
uint128_t operator+(uint128_t rhs){
return uint128_t(rhs.UPPER + UPPER + ((LOWER + rhs.LOWER) < LOWER), LOWER + rhs.LOWER);
}
template <typename T> uint128_t operator+=(T rhs){
UPPER = UPPER + ((LOWER + rhs) < LOWER);
LOWER = LOWER + rhs;
return *this;
}
uint128_t operator+=(uint128_t rhs){
UPPER = rhs.UPPER + UPPER + ((LOWER + rhs.LOWER) < LOWER);
LOWER = LOWER + rhs.LOWER;
return *this;
}
template <typename T> uint128_t operator-(T rhs){
return uint128_t((uint64_t) (UPPER - ((LOWER - rhs) > LOWER)), (uint64_t) (LOWER - rhs));
}
uint128_t operator-(uint128_t rhs){
return uint128_t(UPPER - rhs.UPPER - ((LOWER - rhs.LOWER) > LOWER), LOWER - rhs.LOWER);
}
template <typename T> uint128_t operator-=(T rhs){
*this = *this - rhs;
return *this;
}
uint128_t operator-=(uint128_t rhs){
*this = *this - rhs;
return *this;
}
template <typename T> uint128_t operator*(T rhs){
return *this * uint128_t(rhs);
}
uint128_t operator*(uint128_t rhs){
// split values into 4 32-bit parts
uint64_t top[4] = {UPPER >> 32, UPPER % 0x100000000ULL, LOWER >> 32, LOWER % 0x100000000ULL};
uint64_t bottom[4] = {rhs.upper() >> 32, rhs.upper() % 0x100000000ULL, rhs.lower() >> 32, rhs.lower() % 0x100000000ULL};
uint64_t products[4][4];
for(int y = 3; y > -1; y--)
for(int x = 3; x > -1; x--){
products[3 - x][y] = top[x] * bottom[y];
}
// initial row
uint64_t fourth32 = products[0][3] % 0x100000000ULL;
uint64_t third32 = products[0][2] % 0x100000000ULL + (products[0][3] >> 32);
uint64_t second32 = products[0][1] % 0x100000000ULL + (products[0][2] >> 32);
uint64_t first32 = products[0][0] % 0x100000000ULL + (products[0][1] >> 32);
// second row
third32 += products[1][3] % 0x100000000ULL;
second32 += (products[1][2] % 0x100000000ULL) + (products[1][3] >> 32);
first32 += (products[1][1] % 0x100000000ULL) + (products[1][2] >> 32);
// third row
second32 += products[2][3] % 0x100000000ULL;
first32 += (products[2][2] % 0x100000000ULL) + (products[2][3] >> 32);
// fourth row
first32 += products[3][3] % 0x100000000ULL;
// combines the values, taking care of carry over
return uint128_t(first32 << 32, 0) + uint128_t(third32 >> 32, third32 << 32) + uint128_t(second32, 0) + uint128_t(fourth32);
}
template <typename T> uint128_t operator*=(T rhs){
*this = *this * uint128_t(rhs);
return *this;
}
uint128_t operator*=(uint128_t rhs){
*this = *this * rhs;
return *this;
}
template <typename T> uint128_t operator/(T rhs){
return *this / uint128_t(rhs);
}
uint128_t operator/(uint128_t rhs){
// Save some calculations /////////////////////
if (rhs == 0){
std::cout << "Error: division or modulus by zero" << std::endl;
exit(1);
}
if (rhs == 1)
return *this;
if (*this == rhs)
return uint128_t(1);
if ((*this == 0) | (*this < rhs))
return uint128_t(0);
// Checks for divisors that are powers of two
uint16_t s = 0;
uint128_t copyd(rhs);
while ((copyd.LOWER & 1) == 0){
copyd >>= 1;
s++;
}
if (copyd == 1)
return *this >> s;
////////////////////////////////////////////////
uint128_t copyn(*this), quotient = 0;
while (copyn >= rhs){
uint128_t copyd(rhs), temp(1);
// shift the divsor to match the highest bit
while ((copyn >> 1) > copyd){
copyd <<= 1;
temp <<= 1;
}
copyn -= copyd;
quotient += temp;
}
return quotient;
}
template <typename T> uint128_t operator/=(T rhs){
*this = *this / uint128_t(rhs);
return *this;
}
uint128_t operator/=(uint128_t rhs){
*this = *this / rhs;
return *this;
}
template <typename T> uint128_t operator%(T rhs){
return *this - (rhs * (*this / rhs));
}
uint128_t operator%(uint128_t rhs){
return *this - (rhs * (*this / rhs));
}
template <typename T> uint128_t operator%=(T rhs){
*this = *this % uint128_t(rhs);
return *this;
}
uint128_t operator%=(uint128_t rhs){
*this = *this % rhs;
return *this;
}
// Increment Operator
uint128_t operator++(){
*this += 1;
return *this;
}
uint128_t operator++(int){
uint128_t temp(*this);
++*this;
return temp;
}
// Decrement Operator
uint128_t operator--(){
*this -= 1;
return *this;
}
uint128_t operator--(int){
uint128_t temp(*this);
--*this;
return temp;
}
// get private values
uint64_t upper(){
return UPPER;
}
uint64_t lower(){
return LOWER;
}
};
// lhs type T as first arguemnt
// Bitwise Operators
template <typename T> T operator&(T lhs, uint128_t rhs){
T out = lhs & (T) rhs.lower();
return out;
}
template <typename T> T operator|(T lhs, uint128_t rhs){
T out = lhs | (T) rhs.lower();
return out;
}
template <typename T> T operator^(T lhs, uint128_t rhs){
T out = lhs ^ (T) rhs.lower();
return out;
}
template <typename T> T operator&=(T & lhs, uint128_t rhs){
lhs &= (T) rhs.lower();
return lhs;
}
template <typename T> T operator|=(T & lhs, uint128_t rhs){
lhs |= (T) rhs.lower();
return lhs;
}
template <typename T> T operator^=(T & lhs, uint128_t rhs){
lhs ^= (T) rhs.lower();
return lhs;
}
// Comparison Operators
template <typename T> bool operator==(T lhs, uint128_t rhs){
return (!rhs.upper() && ((uint64_t) lhs == rhs.lower()));
}
template <typename T> bool operator!=(T lhs, uint128_t rhs){
return (rhs.upper() | ((uint64_t) lhs != rhs.lower()));
}
template <typename T> bool operator>(T lhs, uint128_t rhs){
if (rhs.upper())
return false;
return ((uint64_t) lhs > rhs.lower());
}
template <typename T> bool operator<(T lhs, uint128_t rhs){
if (rhs.upper())
return true;
return ((uint64_t) lhs < rhs.lower());
}
template <typename T> bool operator>=(T lhs, uint128_t rhs){
if (rhs.upper())
return false;
return ((uint64_t) lhs >= rhs.lower());
}
template <typename T> bool operator<=(T lhs, uint128_t rhs){
if (rhs.upper())
return true;
return ((uint64_t) lhs <= rhs.lower());
}
// Arithmetic Operators
template <typename T> T operator+(T lhs, uint128_t rhs){
return (T) (rhs + lhs);
}
template <typename T> T & operator+=(T & lhs, uint128_t rhs){
lhs = (T) (rhs + lhs);
return lhs;
}
template <typename T> T operator-(T lhs, uint128_t rhs){
return (T) (rhs - lhs);
}
template <typename T> T & operator-=(T & lhs, uint128_t rhs){
lhs = (T) (rhs - lhs);
return lhs;
}
template <typename T> T operator*(T lhs, uint128_t rhs){
return lhs * rhs.lower();
}
template <typename T> T & operator*=(T & lhs, uint128_t rhs){
lhs = (T) (rhs.lower() * lhs);
return lhs;
}
template <typename T> T operator/(T lhs, uint128_t rhs){
return (T) (uint128_t(lhs) / rhs);
}
template <typename T> T & operator/=(T & lhs, uint128_t rhs){
lhs = (T) (uint128_t(lhs) / rhs);
return lhs;
}
template <typename T> T operator%(T lhs, uint128_t rhs){
return (T) (uint128_t(lhs) % rhs);
}
template <typename T> T & operator%=(T & lhs, uint128_t rhs){
lhs = (T) (uint128_t(lhs) % rhs);
return lhs;
}
// IO Operator
inline std::ostream & operator<<(std::ostream & stream, uint128_t rhs){
std::string out = "";
if (rhs == 0)
out = "0";
else {
int div = 10;
if (stream.flags() & stream.oct)
div = 8;
if (stream.flags() & stream.dec)
div = 10;
if (stream.flags() & stream.hex)
div = 16;
while (rhs > 0){
out = "0123456789abcdef"[size_t(rhs % div)] + out;
rhs /= div;
}
}
stream << out;
return stream;
}

606
uint256_t.h

@ -0,0 +1,606 @@
/*
uint256_t.h
An unsigned 256 bit integer library for C++
By Jason Lee @ calccrypto@yahoo.com
with much help from Auston Sterling
From http://calccrypto.wikidot.com/programming:uint256-t
Licenced http://creativecommons.org/licenses/by-sa/3.0/
*/
#pragma once
#include <cstdlib>
#include <iostream>
#include <stdint.h>
#include "uint128_t.h"
class uint256_t{
private:
uint128_t UPPER, LOWER;
public:
// Constructors
uint256_t(){
UPPER = 0;
LOWER = 0;
}
template <typename T>
uint256_t(T rhs){
UPPER = 0;
LOWER = (uint128_t) rhs;
}
template <typename S, typename T>
uint256_t(const S upper_rhs, const T lower_rhs){
UPPER = (uint128_t) upper_rhs;
LOWER = (uint128_t) lower_rhs;
}
uint256_t(const uint256_t & rhs){
UPPER = rhs.UPPER;
LOWER = rhs.LOWER;
}
// RHS input args only
// Assignment Operator
template <typename T> uint256_t operator=(T rhs){
UPPER = 0;
LOWER = (uint128_t) rhs;
return *this;
}
uint256_t operator=(uint256_t rhs){
UPPER = rhs.UPPER;
LOWER = rhs.LOWER;
return *this;
}
// Typecast Operators
operator bool(){
return (bool) (UPPER | LOWER);
}
operator char(){
return (char) LOWER;
}
operator int(){
return (int) LOWER;
}
operator uint8_t(){
return (uint8_t) LOWER;
}
operator uint16_t(){
return (uint16_t) LOWER;
}
operator uint32_t(){
return (uint32_t) LOWER;
}
operator uint64_t(){
return (uint64_t) LOWER;
}
operator uint128_t(){
return LOWER;
}
// Bitwise Operators
template <typename T> uint256_t operator&(T rhs){
return uint256_t(0, LOWER & (uint128_t) rhs);
}
uint256_t operator&(uint256_t rhs){
return uint256_t(UPPER & rhs.UPPER, LOWER & rhs.LOWER);
}
template <typename T> uint256_t operator|(T rhs){
return uint256_t(UPPER, LOWER | uint128_t(rhs));
}
uint256_t operator|(uint256_t rhs){
return uint256_t(UPPER | rhs.UPPER, LOWER | rhs.LOWER);
}
template <typename T> uint256_t operator^(T rhs){
return uint256_t(UPPER, LOWER ^ (uint128_t) rhs);
}
uint256_t operator^(uint256_t rhs){
return uint256_t(UPPER ^ rhs.UPPER, LOWER ^ rhs.LOWER);
}
template <typename T> uint256_t operator&=(T rhs){
UPPER = 0;
LOWER &= rhs;
return *this;
}
uint256_t operator&=(uint256_t rhs){
UPPER &= rhs.UPPER;
LOWER &= rhs.LOWER;
return *this;
}
template <typename T> uint256_t operator|=(T rhs){
LOWER |= (uint128_t) rhs;
return *this;
}
uint256_t operator|=(uint256_t rhs){
UPPER |= rhs.UPPER;
LOWER |= rhs.LOWER;
return *this;
}
template <typename T> uint256_t operator^=(T rhs){
LOWER ^= (uint128_t) rhs;
return *this;
}
uint256_t operator^=(const uint256_t rhs){
UPPER ^= rhs.UPPER;
LOWER ^= rhs.LOWER;
return *this;
}
uint256_t operator~(){
return uint256_t(~UPPER, ~LOWER);
}
// Bit Shift Operators
uint256_t operator<<(int shift){
if (shift >= 256)
return uint256_t(0, 0);
else if (shift == 128)
return uint256_t(LOWER, 0);
else if (shift == 0)
return *this;
else if (shift < 128)
return uint256_t((UPPER << shift) + (LOWER >> (128 - shift)), LOWER << shift);
else if ((256 > shift) && (shift > 128))
return uint256_t(LOWER << (shift - 128), 0);
else
return uint256_t(0);
}
template <typename T>
uint256_t operator>>(const T shift){
if (shift >= 256)
return uint256_t(0, 0);
else if (shift == 128)
return uint256_t(0, UPPER);
else if (shift == 0)
return *this;
else if (shift < 128)
return uint256_t(UPPER >> shift, (UPPER << (128 - shift)) + (LOWER >> shift));
else if ((256 > shift) && (shift > 128))
return uint256_t(0, (UPPER >> (shift - 128)));
else
return uint256_t(0);
}
uint256_t operator<<=(const int shift){
*this = *this << shift;
return *this;
}
uint256_t operator>>=(int shift){
*this = *this >> shift;
return *this;
}
// Logical Operators
bool operator!(){
return !(bool) (UPPER | LOWER);
}
template <typename T> bool operator&&(T rhs){
return (bool) *this && rhs;
}
template <typename T> bool operator&&(uint256_t rhs){
return (bool) *this && (bool) rhs;
}
template <typename T> bool operator||(T rhs){
return ((bool) *this) || rhs;
}
template <typename T> bool operator||(uint256_t rhs){
return ((bool) *this) || (bool) rhs;
}
// Comparison Operators
template <typename T> bool operator==(T rhs){
return (!UPPER && (LOWER == uint128_t(rhs)));
}
bool operator==(uint256_t rhs){
return ((UPPER == rhs.UPPER) && (LOWER == rhs.LOWER));
}
template <typename T> bool operator!=(T rhs){
return (UPPER | (LOWER != (uint128_t) rhs));
}
bool operator==(uint128_t rhs){
return (!UPPER && (LOWER == rhs));
}
bool operator!=(uint256_t rhs){
return ((UPPER != rhs.UPPER) | (LOWER != rhs.LOWER));
}
template <typename T> bool operator>(T rhs){
if (UPPER)
return true;
return (LOWER > (uint128_t) rhs);
}
bool operator>(uint256_t rhs){
if (UPPER == rhs.UPPER)
return (LOWER > rhs.LOWER);
if (UPPER > rhs.UPPER)
return true;
return false;
}
template <typename T> bool operator<(T rhs){
if (!UPPER)
return (LOWER < (uint128_t) rhs);
return false;
}
bool operator<(uint256_t rhs){
if (UPPER == rhs.UPPER)
return (LOWER < rhs.LOWER);
if (UPPER < rhs.UPPER)
return true;
return false;
}
template <typename T> bool operator>=(T rhs){
return ((*this > rhs) | (*this == rhs));
}
bool operator>=(uint256_t rhs){
return ((*this > rhs) | (*this == rhs));
}
template <typename T> bool operator<=(T rhs){
return ((*this < rhs) | (*this == rhs));
}
bool operator<=(uint256_t rhs){
return ((*this < rhs) | (*this == rhs));
}
// Arithmetic Operators
template <typename T> uint256_t operator+(T rhs){
return uint256_t(UPPER + ((LOWER + (uint128_t) rhs) < LOWER), LOWER + (uint128_t) rhs);
}
uint256_t operator+(uint256_t rhs){
return uint256_t(rhs.UPPER + UPPER + ((LOWER + rhs.LOWER) < LOWER), LOWER + rhs.LOWER);
}
template <typename T> uint256_t operator+=(T rhs){
UPPER = UPPER + ((LOWER + rhs) < LOWER);
LOWER = LOWER + rhs;
return *this;
}
uint256_t operator+=(uint256_t rhs){
UPPER = rhs.UPPER + UPPER + ((LOWER + rhs.LOWER) < LOWER);
LOWER = LOWER + rhs.LOWER;
return *this;
}
template <typename T> uint256_t operator-(T rhs){
return uint256_t(UPPER - ((LOWER - rhs) > LOWER), LOWER - rhs);
}
uint256_t operator-(uint256_t rhs){
return uint256_t(UPPER - rhs.UPPER - ((LOWER - rhs.LOWER) > LOWER), LOWER - rhs.LOWER);;
}
template <typename T> uint256_t operator-=(T rhs){
*this = *this - rhs;
return *this;
}
uint256_t operator-=(uint256_t rhs){
*this = *this - rhs;
return *this;
}
template <typename T> uint256_t operator*(T rhs){
return *this * uint256_t(rhs);
}
uint256_t operator*(uint256_t rhs){
// split values into 4 64-bit parts
uint128_t top[4] = {UPPER >> 64, UPPER % uint128_t(1, 0), LOWER >> 64, LOWER % uint128_t(1, 0)};
uint128_t bottom[4] = {rhs.upper() >> 64, rhs.upper() % uint128_t(1, 0), rhs.lower() >> 64, rhs.lower() % uint128_t(1, 0)};
uint128_t products[4][4];
for(int y = 3; y > -1; y--)
for(int x = 3; x > -1; x--){
products[3 - x][y] = top[x] * bottom[y];
}
// initial row
uint128_t fourth64 = products[0][3] % uint128_t(1, 0);
uint128_t third64 = products[0][2] % uint128_t(1, 0) + (products[0][3] >> 64);
uint128_t second64 = products[0][1] % uint128_t(1, 0) + (products[0][2] >> 64);
uint128_t first64 = products[0][0] % uint128_t(1, 0) + (products[0][1] >> 64);
// second row
third64 += products[1][3] % uint128_t(1, 0);
second64 += (products[1][2] % uint128_t(1, 0)) + (products[1][3] >> 64);
first64 += (products[1][1] % uint128_t(1, 0)) + (products[1][2] >> 64);
// third row
second64 += products[2][3] % uint128_t(1, 0);
first64 += (products[2][2] % uint128_t(1, 0)) + (products[2][3] >> 64);
// fourth row
first64 += products[3][3] % uint128_t(1, 0);
// combines the values, taking care of carry over
return uint256_t(first64 << 64, 0) + uint256_t(third64 >> 64, third64 << 64) + uint256_t(second64, 0) + uint256_t(fourth64);
}
template <typename T> uint256_t operator*=(T rhs){
*this = *this * uint256_t(rhs);
return *this;
}
uint256_t operator*=(uint256_t rhs){
*this = *this * rhs;
return *this;
}
template <typename T> uint256_t operator/(T rhs){
return *this / uint256_t(rhs);
}
uint256_t operator/(uint256_t rhs){
// Save some calculations //////////////////////
if (rhs == 0){
std::cout << "Error: division or modulus by zero" << std::endl;
exit(1);
}
if (rhs == 1)
return *this;
if (*this == rhs)
return uint256_t(1);
if ((*this == 0) | (*this < rhs))
return uint256_t(0);
// Checks for divisors that are powers of two
uint16_t s = 0;
uint256_t copyd(rhs);
while ((copyd.LOWER & 1) == 0){
copyd >>= 1;
s++;
}
if (copyd == 1)
return *this >> s;
////////////////////////////////////////////////
uint256_t copyn(*this), quotient = 0;
while (copyn >= rhs){
uint256_t copyd(rhs), temp(1);
// shift the divosr to match the highest bit
while ((copyn >> 1) > copyd){
copyd <<= 1;
temp <<= 1;
}
copyn -= copyd;
quotient += temp;
}
return quotient;
}
template <typename T> uint256_t operator/=(T rhs){
*this = *this / uint256_t(rhs);
return *this;
}
uint256_t operator/=(uint256_t rhs){
*this = *this / rhs;
return *this;
}
template <typename T> uint256_t operator%(T rhs){
return *this % uint256_t(rhs);
}
uint256_t operator%(uint256_t rhs){
return *this - (rhs * (*this / rhs));
}
template <typename T> uint256_t operator%=(T rhs){
*this = *this % uint256_t(rhs);
return *this;
}
uint256_t operator%=(uint256_t rhs){
*this = *this % rhs;
return *this;
}
// Increment Operators
uint256_t operator++(){
*this += 1;
return *this;
}
uint256_t operator++(int){
uint256_t temp(*this);
++*this;
return temp;
}
// Decrement Operators
uint256_t operator--(){
*this -= 1;
return *this;
}
uint256_t operator--(int){
uint256_t temp(*this);
--*this;
return temp;
}
// get private values
uint128_t upper(){
return UPPER;
}
uint128_t lower(){
return LOWER;
}
};
// lhs type T as first arguemnt
// Bitwise Operators
template <typename T> T operator&(T lhs, uint256_t rhs){
T out = lhs & (T) rhs.lower();
return out;
}
template <typename T> T operator|(T lhs, uint256_t rhs){
T out = lhs | (T) rhs.lower();
return out;
}
template <typename T> T operator^(T lhs, uint256_t rhs){
T out = lhs ^ (T) rhs.lower();
return out;
}
template <typename T> T operator&=(T & lhs, uint256_t rhs){
lhs &= (T) rhs.lower();
return lhs;
}
template <typename T> T operator|=(T & lhs, uint256_t rhs){
lhs |= (T) rhs.lower();
return lhs;
}
template <typename T> T operator^=(T & lhs, uint256_t rhs){
lhs ^= (T) rhs.lower();
return lhs;
}
// Comparison Operators
template <typename T> bool operator==(T lhs, uint256_t rhs){
return (!rhs.upper() && (uint128_t) lhs == rhs.lower());
}
template <typename T> bool operator!=(T lhs, uint256_t rhs){
return (rhs.upper() | ((uint128_t) lhs != rhs.lower()));
}
template <typename T> bool operator>(T lhs, uint256_t rhs){
if (rhs.upper())
return false;
return ((uint128_t) lhs > rhs.lower());
}
template <typename T> bool operator<(T lhs, uint256_t rhs){
if (rhs.upper())
return true;
return ((uint128_t) lhs < rhs.lower());
}
template <typename T> bool operator>=(T lhs, uint256_t rhs){
if (rhs.upper())
return false;
return ((uint128_t) lhs >= rhs.lower());
}
template <typename T> bool operator<=(T lhs, uint256_t rhs){
if (rhs.upper())
return true;
return ((uint128_t) lhs <= rhs.lower());
}
// Arithmetic Operators
template <typename T> T operator+(T lhs, uint256_t rhs){
return (T) (rhs + lhs);
}
template <typename T> T & operator+=(T & lhs, uint256_t rhs){
lhs = (T) (rhs + lhs);
return lhs;
}
template <typename T> T operator-(T lhs, uint256_t rhs){
return (T) (rhs - lhs);
}
template <typename T> T & operator-=(T & lhs, uint256_t rhs){
lhs = (T) (rhs - lhs);
return lhs;
}
template <typename T> T operator*(T lhs, uint256_t rhs){
return lhs * rhs.lower();
}
template <typename T> T & operator*=(T & lhs, uint256_t rhs){
lhs = (T) (rhs.lower() * lhs);
return lhs;
}
template <typename T> T operator/(T lhs, uint256_t rhs){
return (T) (uint256_t(lhs) / rhs);
}
template <typename T> T & operator/=(T & lhs, uint256_t rhs){
lhs = (T) (uint256_t(lhs) / rhs);
return lhs;
}
template <typename T> T operator%(T lhs, uint256_t rhs){
return (T) (uint256_t(lhs) % rhs);
}
template <typename T> T & operator%=(T & lhs, uint256_t rhs){
lhs = (T) (uint256_t(lhs) % rhs);
return lhs;
}
// IO Operator
inline std::ostream & operator<<(std::ostream & stream, uint256_t rhs){
std::string out = "";
if (rhs == 0)
out = "0";
else {
int div;
if (stream.flags() & stream.oct)
div = 8;
if (stream.flags() & stream.dec)
div = 10;
if (stream.flags() & stream.hex)
div = 16;
while (rhs > 0){
out = "0123456789abcdef"[size_t(rhs % div)] + out;
rhs /= div;
}
}
stream << out;
return stream;
}
Loading…
Cancel
Save