1
0
mirror of https://github.com/danog/ton.git synced 2024-12-02 17:38:33 +01:00
ton/crypto/common/bitstring.h
ton 13140ddf29 updated block header
1. Updated block header, proofs now contain more data
   Notice, that old proofs may become invalid in the future
2. Fixed message routing
3. Fixed block creator id in block header
4. Support for full proofs in tonlib
5. Support for partial state download
6. Some other bugfixes
2019-09-18 21:46:32 +04:00

666 lines
19 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-2019 Telegram Systems LLP
*/
#pragma once
#include "common/refcnt.hpp"
#include <utility>
#include <array>
#include <string>
#include <ostream>
#include <cstdlib>
#include "td/utils/bits.h"
namespace td {
template <class Pt>
struct BitPtrGen;
typedef BitPtrGen<unsigned char> BitPtr;
typedef BitPtrGen<const unsigned char> ConstBitPtr;
struct BitstringError {};
namespace bitstring {
void bits_memcpy(unsigned char* to, int to_offs, const unsigned char* from, int from_offs, std::size_t bit_count);
void bits_memcpy(BitPtr to, ConstBitPtr from, std::size_t bit_count);
void bits_memset(unsigned char* to, int to_offs, bool val, std::size_t bit_count);
void bits_memset(BitPtr to, bool val, std::size_t bit_count);
int bits_memcmp(const unsigned char* bs1, int bs1_offs, const unsigned char* bs2, int bs2_offs, std::size_t bit_count,
std::size_t* same_upto = 0);
int bits_memcmp(ConstBitPtr bs1, ConstBitPtr bs2, std::size_t bit_count, std::size_t* same_upto = 0);
int bits_lexcmp(const unsigned char* bs1, int bs1_offs, std::size_t bs1_bit_count, const unsigned char* bs2,
int bs2_offs, std::size_t bs2_bit_count);
int bits_lexcmp(ConstBitPtr bs1, std::size_t bs1_bit_count, ConstBitPtr bs2, std::size_t bs2_bit_count);
std::size_t bits_memscan(const unsigned char* ptr, int offs, std::size_t bit_count, bool cmp_to);
std::size_t bits_memscan_rev(const unsigned char* ptr, int offs, std::size_t bit_count, bool cmp_to);
std::size_t bits_memscan(ConstBitPtr bs, std::size_t bit_count, bool cmp_to);
std::size_t bits_memscan_rev(ConstBitPtr bs, std::size_t bit_count, bool cmp_to);
void bits_store_long_top(unsigned char* to, int to_offs, unsigned long long val, unsigned top_bits);
void bits_store_long_top(BitPtr to, unsigned long long val, unsigned top_bits);
void bits_store_long(BitPtr to, unsigned long long val, unsigned bits);
unsigned long long bits_load_long_top(const unsigned char* from, int from_offs, unsigned top_bits);
unsigned long long bits_load_long_top(ConstBitPtr from, unsigned top_bits);
long long bits_load_long(ConstBitPtr from, unsigned bits);
unsigned long long bits_load_ulong(ConstBitPtr from, unsigned bits);
long parse_bitstring_hex_literal(unsigned char* buff, std::size_t buff_size, const char* str, const char* str_end);
long parse_bitstring_binary_literal(BitPtr buff, std::size_t buff_size, const char* str, const char* str_end);
void bits_sha256(BitPtr to, ConstBitPtr from, std::size_t size);
std::string bits_to_binary(const unsigned char* ptr, int offs, std::size_t len);
std::string bits_to_binary(ConstBitPtr bs, std::size_t len);
std::string bits_to_hex(const unsigned char* ptr, int offs, std::size_t len);
std::string bits_to_hex(ConstBitPtr bs, std::size_t len);
} // namespace bitstring
template <class Pt>
struct BitPtrGen {
Pt* ptr;
int offs;
BitPtrGen(Pt* _ptr, int _offs = 0) : ptr(_ptr), offs(_offs) {
}
template <class Pt2>
BitPtrGen(BitPtrGen<Pt2> val) : ptr(val.ptr), offs(val.offs) {
}
BitPtrGen& operator+=(int _offs) {
offs += _offs;
return *this;
}
BitPtrGen& operator-=(int _offs) {
offs -= _offs;
return *this;
}
void advance(int _offs) {
offs += _offs;
}
bool byte_aligned() const {
return !(offs & 7);
}
Pt* get_byte_ptr() const {
return ptr + (offs >> 3);
}
void copy_from(BitPtrGen<const Pt> from, unsigned size) const {
bitstring::bits_memcpy(*this, from, size);
}
BitPtrGen& concat(BitPtrGen<const Pt> from, unsigned size) {
bitstring::bits_memcpy(*this, from, size);
offs += size;
return *this;
}
template <typename T>
void copy_from(const T& from) const {
copy_from(from.bits(), from.size());
}
template <typename T>
BitPtrGen& concat(const T& from) {
return concat(from.bits(), from.size());
}
void fill(bool bit, unsigned size) {
bitstring::bits_memset(*this, bit, size);
}
BitPtrGen& concat_same(bool bit, unsigned size) {
bitstring::bits_memset(*this, bit, size);
offs += size;
return *this;
}
int compare(BitPtrGen<const Pt> other, std::size_t size, std::size_t* same_upto = nullptr) const {
return bitstring::bits_memcmp(*this, other, size, same_upto);
}
bool equals(BitPtrGen<const Pt> other, std::size_t size) const {
return !bitstring::bits_memcmp(*this, other, size);
}
std::size_t scan(bool value, std::size_t len) const {
return bitstring::bits_memscan(*this, len, value);
}
bool is_zero(std::size_t len) const {
return scan(false, len) == len;
}
long long get_int(unsigned bits) const {
return bitstring::bits_load_long(*this, bits);
}
unsigned long long get_uint(unsigned bits) const {
return bitstring::bits_load_ulong(*this, bits);
}
void store_uint(unsigned long long val, unsigned n) const {
bitstring::bits_store_long(*this, val, n);
}
void store_int(long long val, unsigned n) const {
bitstring::bits_store_long(*this, val, n);
}
BitPtrGen operator+(int _offs) const {
return BitPtrGen{ptr, offs + _offs};
}
BitPtrGen operator-(int _offs) const {
return BitPtrGen{ptr, offs - _offs};
}
BitPtrGen operator++() {
++offs;
return *this;
}
BitPtrGen operator--() {
--offs;
return *this;
}
BitPtrGen operator++(int) {
return BitPtrGen{ptr, offs++};
}
BitPtrGen operator--(int) {
return BitPtrGen{ptr, offs--};
}
bool is_null() const {
return !ptr;
}
bool not_null() const {
return ptr;
}
class BitSelector {
Pt* ptr;
unsigned char mask;
public:
BitSelector(Pt* _ptr, int offs) {
ptr = _ptr + (offs >> 3);
mask = (unsigned char)(0x80 >> (offs & 7));
}
bool clear() {
*ptr = (unsigned char)(*ptr & ~mask);
return false;
}
bool set() {
*ptr = (unsigned char)(*ptr | mask);
return true;
}
bool operator=(bool val) {
return val ? set() : clear();
}
operator bool() const {
return *ptr & mask;
}
};
BitSelector operator*() const {
return BitSelector{ptr, offs};
}
BitSelector operator[](int i) const {
return BitSelector{ptr, offs + i};
}
std::string to_hex(std::size_t len) const {
return bitstring::bits_to_hex(*this, len);
}
std::string to_binary(std::size_t len) const {
return bitstring::bits_to_binary(*this, len);
}
};
template <class Rf, class Pt>
class BitSliceGen {
Rf ref;
Pt* ptr;
unsigned offs, len;
public:
struct BitSliceError {};
BitSliceGen() : ref(), ptr(0), offs(0), len(0) {
}
BitSliceGen(Rf _ref, Pt* _ptr, int _offs, unsigned _len)
: ref(std::move(_ref)), ptr(_ptr + (_offs >> 3)), offs(_offs & 7), len(_len) {
}
BitSliceGen(const BitSliceGen& bs, unsigned _offs, unsigned _len);
BitSliceGen(BitSliceGen&& bs, unsigned _offs, unsigned _len);
BitSliceGen(Pt* _ptr, unsigned _len) : ref(), ptr(_ptr), offs(0), len(_len) {
}
~BitSliceGen() {
}
Pt* get_ptr() const {
return ptr;
}
BitPtrGen<Pt> bits() const {
return BitPtrGen<Pt>{ptr, (int)offs};
}
bool is_valid() const {
return ptr != 0;
}
unsigned char cur_byte() const {
return *ptr;
}
unsigned get_offs() const {
return offs;
}
unsigned size() const {
return len;
}
unsigned byte_size() const {
return (offs + len + 7) >> 3;
}
void ensure_throw(bool cond) const {
if (!cond) {
throw BitSliceError{};
}
}
BitSliceGen& assign(Rf _ref, Pt* _ptr, unsigned _offs, unsigned _len);
void forget() {
ref.clear();
ptr = 0;
offs = len = 0;
}
bool operator[](unsigned i) const {
i += offs;
return ptr[i >> 3] & (0x80 >> (i & 7));
}
bool at(unsigned i) const {
ensure_throw(i < len);
return operator[](i);
}
bool advance_bool(unsigned bits);
bool set_size_bool(unsigned bits) {
if (bits > len) {
return false;
}
len = bits;
return true;
}
BitSliceGen& advance(unsigned bits) {
ensure_throw(advance_bool(bits));
return *this;
}
BitSliceGen& set_size(unsigned bits) {
ensure_throw(set_size_bool(bits));
return *this;
}
BitSliceGen subslice(unsigned from, unsigned bits) const& {
return BitSliceGen(*this, from, bits);
}
BitSliceGen subslice(unsigned from, unsigned bits) && {
return BitSliceGen(*this, from, bits);
}
void copy_to(BitPtr to) const {
bitstring::bits_memcpy(to, bits(), size());
}
int compare(ConstBitPtr other) const {
return bitstring::bits_memcmp(bits(), other, size());
}
bool operator==(ConstBitPtr other) const {
return !compare(other);
}
bool operator!=(ConstBitPtr other) const {
return compare(other);
}
std::string to_binary() const {
return bitstring::bits_to_binary(ptr, offs, len);
}
std::string to_hex() const {
return bitstring::bits_to_hex(ptr, offs, len);
}
void dump(std::ostream& stream, bool nocr = false) const {
stream << "[" << offs << "," << len << "]";
if (!nocr) {
stream << std::endl;
}
}
protected:
inline Pt& cur_byte_w() const {
return *ptr;
}
};
template <class Rf, class Pt>
BitSliceGen<Rf, Pt>::BitSliceGen(const BitSliceGen<Rf, Pt>& bs, unsigned from, unsigned bits) : ref() {
if (from >= bs.size() || bits > bs.size() - from) {
ptr = 0;
offs = len = 0;
return;
}
//bs.dump(std::cout, true);
//std::cout << ".subslice(" << from << "," << bits << ") = ";
ref = bs.ref;
offs = bs.offs + from;
ptr = bs.ptr + (offs >> 3);
offs &= 7;
len = bits;
//dump(std::cout);
}
template <class Rf, class Pt>
BitSliceGen<Rf, Pt>::BitSliceGen(BitSliceGen&& bs, unsigned from, unsigned bits) : ref() {
if (from >= bs.size() || bits > bs.size() - from) {
ptr = 0;
offs = len = 0;
return;
}
ref = std::move(bs.ref);
offs = bs.offs + from;
ptr = bs.ptr + (offs >> 3);
offs &= 7;
len = bits;
}
template <class Rf, class Pt>
BitSliceGen<Rf, Pt>& BitSliceGen<Rf, Pt>::assign(Rf _ref, Pt* _ptr, unsigned _offs, unsigned _len) {
ref = std::move(_ref);
ptr = _ptr + (_offs >> 3);
offs = (_offs & 7);
len = _len;
return *this;
}
template <class Rf, class Pt>
inline bool BitSliceGen<Rf, Pt>::advance_bool(unsigned bits) {
if (len < bits) {
return false;
}
len -= bits;
offs += bits;
ptr += (offs >> 3);
offs &= 7;
return true;
}
typedef BitSliceGen<RefAny, const unsigned char> BitSlice;
static inline std::string to_hex(const BitSlice& bs) {
return bs.to_hex();
}
static inline std::string to_binary(const BitSlice& bs) {
return bs.to_binary();
}
class BitSliceWrite : public BitSliceGen<RefAny, unsigned char> {
public:
struct LengthMismatch {};
BitSliceWrite(RefAny _ref, unsigned char* _ptr, unsigned _offs, unsigned _len)
: BitSliceGen<RefAny, unsigned char>(_ref, _ptr, _offs, _len) {
}
BitSliceWrite() : BitSliceGen<RefAny, unsigned char>() {
}
BitSliceWrite(unsigned char* _ptr, unsigned _len) : BitSliceGen<RefAny, unsigned char>(_ptr, _len) {
}
operator BitSlice&() {
return *reinterpret_cast<BitSlice*>(this);
}
operator const BitSlice&() const {
return *reinterpret_cast<const BitSlice*>(this);
}
const BitSliceWrite& operator=(const BitSlice& bs) const;
const BitSliceWrite& operator=(bool val) const;
};
class BitString : public CntObject {
unsigned char* ptr;
unsigned offs, len, bytes_alloc;
public:
BitString() : ptr(0), offs(0), len(0), bytes_alloc(0) {
}
explicit BitString(const BitSlice& bs, unsigned reserve_bits = 0);
explicit BitString(unsigned reserve_bits);
BitString(const BitString&) = delete;
BitString& operator=(const BitString&) = delete;
BitString(BitString&&) = delete;
BitString& operator=(BitString&&) = delete;
~BitString() {
if (ptr) {
std::free(ptr);
}
}
operator BitSlice() const;
BitString* make_copy() const override;
unsigned size() const {
return len;
}
unsigned byte_size() const {
return (offs + len + 7) >> 3;
}
ConstBitPtr cbits() const {
return ConstBitPtr{ptr, (int)offs};
}
ConstBitPtr bits() const {
return ConstBitPtr{ptr, (int)offs};
}
BitPtr bits() {
return BitPtr{ptr, (int)offs};
}
BitString& reserve_bits(unsigned req_bits);
BitSliceWrite reserve_bitslice(unsigned req_bits);
BitString& append(const BitSlice& bs);
BitSlice subslice(unsigned from, unsigned bits) const;
BitSliceWrite subslice_write(unsigned from, unsigned bits);
std::string to_hex() const {
return bitstring::bits_to_hex(cbits(), size());
}
std::string to_binary() const {
return bitstring::bits_to_binary(cbits(), size());
}
};
extern std::ostream& operator<<(std::ostream& stream, const BitString& bs);
extern std::ostream& operator<<(std::ostream& stream, Ref<BitString> bs_ref);
extern template class Ref<BitString>;
typedef Ref<BitString> BitStringRef;
template <unsigned n>
class BitArray {
static constexpr unsigned m = (n + 7) >> 3;
typedef std::array<unsigned char, m> byte_array_t;
typedef unsigned char raw_byte_array_t[m];
byte_array_t bytes;
public:
const unsigned char* data() const {
return bytes.data();
}
unsigned char* data() {
return bytes.data();
}
static unsigned size() {
return n;
}
const byte_array_t& as_array() const {
return bytes;
}
byte_array_t& as_array() {
return bytes;
}
Slice as_slice() const {
return Slice{data(), m};
}
MutableSlice as_slice() {
return MutableSlice{data(), m};
}
ConstBitPtr cbits() const {
return ConstBitPtr{data()};
}
ConstBitPtr bits() const {
return ConstBitPtr{data()};
}
BitPtr bits() {
return BitPtr{data()};
}
BitArray() = default;
BitArray(const BitArray&) = default;
BitArray(const byte_array_t& init_bytes) : bytes(init_bytes) {
}
explicit BitArray(const raw_byte_array_t init_bytes) {
std::memcpy(data(), init_bytes, m);
}
BitArray(ConstBitPtr from) {
bitstring::bits_memcpy(bits(), from, n);
}
template <int N = n, typename X = std::enable_if_t<N == n && N <= 64, int>>
explicit BitArray(long long val) {
bitstring::bits_store_long(bits(), val, n);
}
BitArray& operator=(const BitArray&) = default;
BitArray& operator=(const byte_array_t& set_bytes) {
bytes = set_bytes;
return *this;
}
BitArray& operator=(ConstBitPtr from) {
bitstring::bits_memcpy(bits(), from, n);
return *this;
}
BitArray& operator=(const raw_byte_array_t set_byte_array) {
std::memcpy(data(), set_byte_array, m);
return *this;
}
BitSliceWrite write_bitslice() {
return BitSliceWrite{data(), n};
}
BitSlice as_bitslice() const {
return BitSlice{data(), n};
}
//operator BitString() const {
//return BitString{as_bitslice()};
//}
Ref<BitString> make_bitstring_ref() const {
return td::make_ref<BitString>(as_bitslice());
}
unsigned long long to_ulong() const {
return bitstring::bits_load_ulong(bits(), n);
}
long long to_long() const {
return bitstring::bits_load_long(bits(), n);
}
void store_ulong(unsigned long long val) {
bitstring::bits_store_long(bits(), val, n);
}
void store_long(long long val) {
bitstring::bits_store_long(bits(), val, n);
}
void set_same(bool v) {
bytes.fill(static_cast<unsigned char>(v ? -1 : 0));
}
void set_zero() {
set_same(0);
}
void set_zero_s() {
volatile uint8* p = data();
auto x = m;
while (x--) {
*p++ = 0;
}
}
void set_ones() {
set_same(1);
}
void clear() {
set_zero();
}
bool is_zero() const {
return bitstring::bits_memscan(cbits(), n, 0) == n;
}
std::string to_hex() const {
return bitstring::bits_to_hex(cbits(), size());
}
std::string to_binary() const {
return bitstring::bits_to_binary(cbits(), size());
}
int compare(const BitArray& other) const {
return (n % 8 == 0) ? std::memcmp(data(), other.data(), n / 8) : bitstring::bits_memcmp(bits(), other.bits(), n);
}
bool operator==(const BitArray& other) const {
return (n % 8 == 0) ? (bytes == other.bytes) : !bitstring::bits_memcmp(bits(), other.bits(), n);
}
bool operator!=(const BitArray& other) const {
return (n % 8 == 0) ? (bytes != other.bytes) : bitstring::bits_memcmp(bits(), other.bits(), n);
}
bool operator<(const BitArray& other) const {
return (n % 8 == 0) ? (bytes < other.bytes) : (bitstring::bits_memcmp(bits(), other.bits(), n) < 0);
}
int compare(ConstBitPtr other) const {
return bitstring::bits_memcmp(bits(), other, n);
}
bool operator==(ConstBitPtr other) const {
return !compare(other);
}
bool operator!=(ConstBitPtr other) const {
return compare(other);
}
BitPtr::BitSelector operator[](int i) {
return bits()[i];
}
bool operator[](int i) const {
return cbits()[i];
}
void compute_sha256(BitPtr to) const {
bitstring::bits_sha256(to, cbits(), n);
}
void compute_sha256(BitArray<256>& to) const {
bitstring::bits_sha256(to.bits(), cbits(), n);
}
static inline BitArray zero() {
BitArray x;
x.set_zero();
return x;
}
static inline BitArray ones() {
BitArray x;
x.set_ones();
return x;
}
BitArray operator^(const BitArray& with) const {
BitArray res;
for (unsigned i = 0; i < m; i++) {
res.bytes[i] = bytes[i] ^ with.bytes[i];
}
return res;
}
unsigned scan(bool value) const {
return (unsigned)cbits().scan(value, n);
}
unsigned count_leading_zeroes() const {
return scan(false);
}
unsigned count_matching(ConstBitPtr other) const {
std::size_t cnt;
bitstring::bits_memcmp(cbits(), other, n, &cnt);
return (unsigned)cnt;
}
unsigned count_matching(const BitArray& other) const {
return count_matching(other.bits());
}
};
using Bits256 = BitArray<256>;
using Bits128 = BitArray<128>;
template <unsigned n>
std::ostream& operator<<(std::ostream& stream, BitArray<n> bits) {
return stream << bits.to_hex();
}
template <unsigned N>
Slice as_slice(const BitArray<N>& value) {
return value.as_slice();
}
template <unsigned N>
MutableSlice as_slice(BitArray<N>& value) {
return value.as_slice();
}
template <unsigned N>
Ref<BitString> make_bitstring_ref(const BitArray<N>& value) {
return value.make_bitstring_ref();
}
} // namespace td