1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-03-09 15:40:10 +00:00

initial commit

This commit is contained in:
initial commit 2019-09-07 14:03:22 +04:00 committed by vvaltman
commit c2da007f40
1610 changed files with 398047 additions and 0 deletions

200
crypto/common/AtomicRef.h Normal file
View file

@ -0,0 +1,200 @@
/*
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 "td/utils/SpinLock.h"
#include "common/refcnt.hpp"
#include <type_traits>
namespace td {
template <class T>
class AtomicRefSpinlock {
public:
AtomicRefSpinlock() = default;
AtomicRefSpinlock(Ref<T>&& ref) : ref_(ref.release()) {
}
~AtomicRefSpinlock() {
Ref<T>(ref_.load(std::memory_order_relaxed), typename Ref<T>::acquire_t{});
}
AtomicRefSpinlock(AtomicRefSpinlock&&) = delete;
AtomicRefSpinlock& operator=(AtomicRefSpinlock&&) = delete;
AtomicRefSpinlock(const AtomicRefSpinlock&) = delete;
AtomicRefSpinlock& operator=(const AtomicRefSpinlock&) = delete;
Ref<T> load() const {
auto guard = spin_lock_.lock();
return Ref<T>(ref_.load(std::memory_order_relaxed));
}
Ref<T> extract() const {
auto guard = spin_lock_.lock();
return Ref<T>(ref_.exchange(nullptr, std::memory_order_release), typename Ref<T>::acquire_t{});
}
Ref<T> load_unsafe() const {
return Ref<T>(get_unsafe());
}
const T* get_unsafe() const {
return ref_.load(std::memory_order_acquire);
}
bool store_if_empty(Ref<T>& desired) {
auto guard = spin_lock_.lock();
if (ref_.load(std::memory_order_relaxed) == nullptr) {
ref_.store(desired.release(), std::memory_order_release);
return true;
}
return false;
}
void store(Ref<T>&& ref) {
auto guard = spin_lock_.lock();
Ref<T>(ref_.exchange(ref.release(), std::memory_order_acq_rel), typename Ref<T>::acquire_t{});
}
private:
mutable SpinLock spin_lock_;
std::atomic<T*> ref_{nullptr};
};
template <class T>
class AtomicRefLockfree {
public:
AtomicRefLockfree() = default;
static constexpr int BATCH_SIZE = 100;
AtomicRefLockfree(Ref<T>&& ref) : ptr_(Ptr(ref.release(), BATCH_SIZE)) {
Ref<T>::acquire_shared(ptr_.load(std::memory_order_relaxed).ptr(), BATCH_SIZE);
}
~AtomicRefLockfree() {
auto ptr = ptr_.load(std::memory_order_relaxed);
if (ptr.ptr()) {
Ref<T>::release_shared(ptr.ptr(), ptr.ref_cnt() + 1);
}
}
AtomicRefLockfree(AtomicRefLockfree&&) = delete;
AtomicRefLockfree& operator=(AtomicRefLockfree&&) = delete;
AtomicRefLockfree(const AtomicRefLockfree&) = delete;
AtomicRefLockfree& operator=(const AtomicRefLockfree&) = delete;
Ref<T> load() const {
auto ptr = ptr_.load();
while (ptr.ptr()) {
if (ptr.ref_cnt() == 0) {
td::this_thread::yield();
ptr = ptr_.load();
continue;
}
auto new_ptr = Ptr(ptr.ptr(), ptr.ref_cnt() - 1);
if (ptr_.compare_exchange_weak(ptr, new_ptr)) {
if (new_ptr.ref_cnt() < BATCH_SIZE / 2) {
try_reserve(ptr.ptr());
}
return Ref<T>(ptr.ptr(), typename Ref<T>::acquire_t{});
}
}
return {};
}
void try_reserve(T* raw_ptr) const {
int reserve_cnt = BATCH_SIZE;
Ref<T>::acquire_shared(raw_ptr, reserve_cnt);
auto ptr = ptr_.load();
while (ptr.ptr() == raw_ptr && ptr.ref_cnt() < BATCH_SIZE / 2) {
auto new_ptr = Ptr(ptr.ptr(), ptr.ref_cnt() + reserve_cnt);
if (ptr_.compare_exchange_weak(ptr, new_ptr)) {
return;
}
}
Ref<T>::release_shared(raw_ptr, reserve_cnt);
}
Ref<T> extract() {
auto ptr = ptr_.exchange({});
if (ptr.ref_cnt() != 0) {
Ref<T>::release_shared(ptr.ptr(), ptr.ref_cnt());
}
return Ref<T>(ptr.ptr(), typename Ref<T>::acquire_t{});
}
Ref<T> load_unsafe() const {
return load();
}
T* get_unsafe() const {
return ptr_.load().ptr();
}
bool store_if_empty(Ref<T>& desired) {
auto raw_ptr = desired.get();
Ref<T>::acquire_shared(raw_ptr, BATCH_SIZE + 1);
Ptr new_ptr{const_cast<T*>(raw_ptr), BATCH_SIZE};
auto ptr = ptr_.load();
while (ptr.ptr() == nullptr) {
if (ptr_.compare_exchange_weak(ptr, new_ptr)) {
return true;
}
}
Ref<T>::release_shared(raw_ptr, BATCH_SIZE + 1);
return false;
}
void store(Ref<T>&& ref) {
Ptr new_ptr = [&]() -> Ptr {
if (ref.is_null()) {
return {};
}
auto raw_ptr = ref.release();
Ref<T>::acquire_shared(raw_ptr, BATCH_SIZE);
return {raw_ptr, BATCH_SIZE};
}();
auto ptr = ptr_.load();
while (!ptr_.compare_exchange_weak(ptr, new_ptr)) {
}
if (ptr.ptr()) {
Ref<T>::release_shared(ptr.ptr(), ptr.ref_cnt() + 1);
}
}
private:
struct Ptr {
public:
Ptr() = default;
Ptr(T* ptr, int ref_cnt) {
data_ = reinterpret_cast<td::uint64>(ptr);
CHECK((data_ >> 48) == 0);
data_ |= static_cast<td::uint64>(ref_cnt) << 48;
}
T* ptr() const {
return reinterpret_cast<T*>(data_ & (std::numeric_limits<uint64>::max() >> 16));
}
int ref_cnt() const {
return static_cast<int>(data_ >> 48);
}
private:
td::uint64 data_{0};
};
static_assert(sizeof(Ptr) == 8, "sizeof(Ptr) must be 8 for atomic to work fine");
static_assert(std::is_trivially_copyable<Ptr>::value, "Ptr must be tribially copyable");
mutable std::atomic<Ptr> ptr_{Ptr()};
};
template <class T>
using AtomicRef = AtomicRefLockfree<T>;
} // namespace td

41
crypto/common/bigint.cpp Normal file
View file

@ -0,0 +1,41 @@
/*
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
*/
#include "common/bigint.hpp"
namespace td {
template class AnyIntView<BigIntInfo>;
template class BigIntG<257, BigIntInfo>;
namespace literals {
BigInt256 operator""_i256(const char* str, std::size_t str_len) {
BigInt256 x;
x.enforce(x.parse_dec(str, (int)str_len) == (int)str_len);
return x;
}
BigInt256 operator""_x256(const char* str, std::size_t str_len) {
BigInt256 x;
x.enforce(x.parse_hex(str, (int)str_len) == (int)str_len);
return x;
}
} // namespace literals
} // namespace td

2525
crypto/common/bigint.hpp Normal file

File diff suppressed because it is too large Load diff

668
crypto/common/bitstring.cpp Normal file
View file

@ -0,0 +1,668 @@
/*
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
*/
#include "common/bitstring.h"
#include <cstring>
#include <limits>
#include "td/utils/as.h"
#include "td/utils/bits.h"
#include "td/utils/misc.h"
#include "crypto/openssl/digest.h"
namespace td {
template class Ref<BitString>;
BitString::BitString(const BitSlice& bs, unsigned reserve_bits) {
if (!bs.size() && !reserve_bits) {
ptr = 0;
offs = len = bytes_alloc = 0;
} else {
offs = bs.get_offs();
len = bs.size();
bytes_alloc = (bs.get_offs() + bs.size() + reserve_bits + 7) >> 3;
ptr = static_cast<unsigned char*>(std::malloc(bytes_alloc));
CHECK(ptr);
if (bs.size()) {
std::memcpy(ptr, bs.get_ptr(), bs.byte_size());
}
}
}
BitString::BitString(unsigned reserve_bits) {
if (!reserve_bits) {
ptr = 0;
offs = len = bytes_alloc = 0;
} else {
bytes_alloc = (reserve_bits + 7) >> 3;
ptr = static_cast<unsigned char*>(std::malloc(bytes_alloc));
CHECK(ptr);
offs = len = 0;
}
}
BitString::operator BitSlice() const {
return BitSlice(BitStringRef{this}, ptr, offs, len);
}
BitString* BitString::make_copy() const {
if (!ptr) {
return new BitString(64); // reserve 64 bits
} else {
return new BitString(operator BitSlice(), 64);
}
}
BitString& BitString::reserve_bits(unsigned req_bits) {
req_bits += offs + len;
if (req_bits > bytes_alloc * 8) {
bytes_alloc = (req_bits + 7) >> 3;
ptr = (unsigned char*)std::realloc(ptr, bytes_alloc);
CHECK(ptr);
}
return *this;
}
BitSliceWrite BitString::reserve_bitslice(unsigned req_bits) {
reserve_bits(req_bits);
unsigned pos = offs + len;
len += req_bits;
return BitSliceWrite(Ref<BitString>(this), ptr, pos, req_bits);
}
BitString& BitString::append(const BitSlice& bs) {
reserve_bitslice(bs.size()) = bs;
return *this;
}
BitSlice BitString::subslice(unsigned from, unsigned bits) const {
return BitSlice{BitStringRef{this}, ptr, static_cast<int>(offs + from), bits};
}
BitSliceWrite BitString::subslice_write(unsigned from, unsigned bits) {
return BitSliceWrite{BitStringRef{this}, ptr, offs + from, bits};
}
const BitSliceWrite& BitSliceWrite::operator=(const BitSlice& bs) const {
if (size() != bs.size()) {
throw LengthMismatch();
}
bitstring::bits_memcpy(get_ptr(), get_offs(), bs.get_ptr(), bs.get_offs(), size());
return *this;
}
const BitSliceWrite& BitSliceWrite::operator=(bool val) const {
bitstring::bits_memset(get_ptr(), get_offs(), val, size());
return *this;
}
std::ostream& operator<<(std::ostream& os, const BitString& bs) {
return os << bs.to_hex();
}
std::ostream& operator<<(std::ostream& os, Ref<BitString> bs_ref) {
return os << (bs_ref.is_null() ? "(null-bs)" : bs_ref->to_hex());
}
namespace bitstring {
void bits_memcpy(unsigned char* to, int to_offs, const unsigned char* from, int from_offs, std::size_t bit_count) {
if (bit_count <= 0) {
return;
}
from += (from_offs >> 3);
to += (to_offs >> 3);
from_offs &= 7;
to_offs &= 7;
//fprintf(stderr, "bits_memcpy: from=%p (%02x) to=%p (%02x) from_offs=%d to_offs=%d count=%lu\n", from, *from, to, *to, from_offs, to_offs, bit_count);
int sz = (int)bit_count;
bit_count += from_offs;
if (from_offs == to_offs) {
if (bit_count < 8) {
int mask = (-0x100 >> bit_count) & (0xff >> to_offs);
*to = (unsigned char)((*to & ~mask) | (*from & mask));
return;
}
std::size_t l = (bit_count >> 3);
if (!to_offs) {
std::memcpy(to, from, l);
} else {
int mask = (0xff >> to_offs);
*to = (unsigned char)((*to & ~mask) | (*from & mask));
std::memcpy(to + 1, from + 1, l - 1);
}
if ((bit_count &= 7) != 0) {
int mask = (-0x100 >> bit_count);
to[l] = (unsigned char)((to[l] & ~mask) | (from[l] & mask));
}
} else {
int b = (int)to_offs;
unsigned long long acc = (b ? *to >> (8 - b) : 0);
if (bit_count < 8) {
acc <<= sz;
acc |= ((*from & (0xff >> from_offs)) >> (8 - bit_count));
b += sz;
} else {
unsigned ld = 8 - from_offs;
acc <<= ld;
acc |= (*from++ & (0xff >> from_offs));
b += ld;
bit_count -= 8;
// b <= 15 here
while (bit_count >= 32) {
acc <<= 32;
acc |= td::bswap32(as<unsigned>(from));
from += 4;
as<unsigned>(to) = td::bswap32((unsigned)(acc >> b));
to += 4;
bit_count -= 32;
}
// bit_count <= 31, b <= 15
while (bit_count >= 8) {
acc <<= 8;
acc |= *from++;
bit_count -= 8;
b += 8;
}
// b + bit_count = const <= 46
if (bit_count > 0) {
acc <<= bit_count;
acc |= (*from >> (8 - bit_count));
b += (int)bit_count;
}
}
while (b >= 8) {
b -= 8;
*to++ = (unsigned char)(acc >> b);
}
if (b > 0) {
*to = (unsigned char)((*to & (0xff >> b)) | ((int)acc << (8 - b)));
}
}
}
void bits_memcpy(BitPtr to, ConstBitPtr from, std::size_t bit_count) {
bits_memcpy(to.ptr, to.offs, from.ptr, from.offs, bit_count);
}
void bits_memset(unsigned char* to, int to_offs, bool val, std::size_t bit_count) {
if (bit_count <= 0) {
return;
}
to += (to_offs >> 3);
to_offs &= 7;
int sz = (int)bit_count;
bit_count += to_offs;
int c = *to;
if (bit_count <= 8) {
int mask = (((-0x100 >> sz) & 0xff) >> to_offs);
if (val) {
*to = (unsigned char)(c | mask);
} else {
*to = (unsigned char)(c & ~mask);
}
return;
}
if (val) {
*to = (unsigned char)(c | (0xff >> to_offs));
} else {
*to = (unsigned char)(c & (-0x100 >> to_offs));
}
std::size_t l = (bit_count >> 3);
std::memset(to + 1, val ? 0xff : 0, l - 1);
if ((bit_count &= 7) != 0) {
if (val) {
to[l] = (unsigned char)(to[l] | (-0x100 >> bit_count));
} else {
to[l] = (unsigned char)(to[l] & (0xff >> bit_count));
}
}
}
void bits_memset(BitPtr to, bool val, std::size_t bit_count) {
bits_memset(to.ptr, to.offs, val, bit_count);
}
std::size_t bits_memscan_rev(const unsigned char* ptr, int offs, std::size_t bit_count, bool cmp_to) {
if (!bit_count) {
return 0;
}
int xor_val = (cmp_to ? -1 : 0);
ptr += ((offs + bit_count) >> 3);
offs = (int)((offs + bit_count) & 7);
std::size_t res = offs;
if (offs) {
unsigned v = (*ptr >> (8 - offs)) ^ xor_val;
unsigned c = td::count_trailing_zeroes32(v);
if (c < (unsigned)offs || res >= bit_count) {
return std::min(c, (unsigned)bit_count);
}
}
bit_count -= res;
while (bit_count >= 32) {
ptr -= 4;
unsigned v = td::bswap32(as<unsigned>(ptr)) ^ xor_val;
if (v) {
return td::count_trailing_zeroes_non_zero32(v) + res;
}
res += 32;
bit_count -= 32;
}
xor_val &= 0xff;
while (bit_count >= 8) {
unsigned v = *--ptr ^ xor_val;
if (v) {
return td::count_trailing_zeroes_non_zero32(v) + res;
}
res += 8;
bit_count -= 8;
}
if (bit_count > 0) {
unsigned v = *--ptr ^ xor_val;
return std::min((unsigned)td::count_trailing_zeroes32(v), (unsigned)bit_count) + res;
} else {
return res;
}
}
std::size_t bits_memscan(const unsigned char* ptr, int offs, std::size_t bit_count, bool cmp_to) {
if (!bit_count) {
return 0;
}
int xor_val = -static_cast<int>(cmp_to);
ptr += (offs >> 3);
offs &= 7;
std::size_t rem = bit_count;
unsigned v, c;
if (offs) {
v = ((unsigned)(ptr[0] ^ xor_val) << (24 + offs));
// std::cerr << "[A] rem=" << rem << " ptr=" << (const void*)ptr << " v=" << std::hex << v << std::dec << std::endl;
c = td::count_leading_zeroes32(v);
unsigned l = (unsigned)(8 - offs);
if (c < l || bit_count <= l) {
return std::min<std::size_t>(c, bit_count);
}
rem -= l;
ptr++;
}
while (rem >= 8 && !td::is_aligned_pointer<8>(ptr)) {
v = ((*ptr++ ^ xor_val) << 24);
// std::cerr << "[B] rem=" << rem << " ptr=" << (const void*)(ptr - 1) << " v=" << std::hex << v << std::dec << std::endl;
if (v) {
return bit_count - rem + td::count_leading_zeroes_non_zero32(v);
}
rem -= 8;
}
td::uint64 xor_val_l = (cmp_to ? ~0LL : 0LL);
while (rem >= 64) {
td::uint64 z = td::bswap64(as<td::uint64>(ptr)) ^ xor_val_l;
// std::cerr << "[C] rem=" << rem << " ptr=" << (const void*)ptr << " z=" << std::hex << z << std::dec << std::endl;
if (z) {
return bit_count - rem + td::count_leading_zeroes_non_zero64(z);
}
ptr += 8;
rem -= 64;
}
while (rem >= 8) {
v = ((*ptr++ ^ xor_val) << 24);
// std::cerr << "[D] rem=" << rem << " ptr=" << (const void*)(ptr - 1) << " v=" << std::hex << v << std::dec << std::endl;
if (v) {
return bit_count - rem + td::count_leading_zeroes_non_zero32(v);
}
rem -= 8;
}
if (rem > 0) {
v = ((*ptr ^ xor_val) << 24);
// std::cerr << "[E] rem=" << rem << " ptr=" << (const void*)ptr << " v=" << std::hex << v << std::dec << std::endl;
c = td::count_leading_zeroes32(v);
return c < rem ? bit_count - rem + c : bit_count;
} else {
return bit_count;
}
}
std::size_t bits_memscan(ConstBitPtr bs, std::size_t bit_count, bool cmp_to) {
return bits_memscan(bs.ptr, bs.offs, bit_count, cmp_to);
}
std::size_t bits_memscan_rev(ConstBitPtr bs, std::size_t bit_count, bool cmp_to) {
return bits_memscan_rev(bs.ptr, bs.offs, bit_count, cmp_to);
}
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) {
if (!bit_count) {
return 0;
}
bs1 += (bs1_offs >> 3);
bs2 += (bs2_offs >> 3);
bs1_offs &= 7;
bs2_offs &= 7;
//fprintf(stderr, "bits_memcmp: bs1=%02x%02x offs=%d bs2=%02x%02x offs=%d cnt=%lu\n", bs1[0], bs1[1], bs1_offs, bs2[0], bs2[1], bs2_offs, bit_count);
unsigned long long acc1 = (((unsigned long long)*bs1++) << (56 + bs1_offs));
int z1 = 8 - bs1_offs;
unsigned long long acc2 = (((unsigned long long)*bs2++) << (56 + bs2_offs));
int z2 = 8 - bs2_offs;
std::size_t processed = 0;
while (bit_count >= 40) {
acc1 |= ((unsigned long long)td::bswap32(as<unsigned>(bs1)) << (32 - z1));
bs1 += 4;
acc2 |= ((unsigned long long)td::bswap32(as<unsigned>(bs2)) << (32 - z2));
bs2 += 4;
if ((acc1 ^ acc2) & (~0ULL << 32)) {
if (same_upto) {
*same_upto = processed + td::count_leading_zeroes64(acc1 ^ acc2);
}
return acc1 < acc2 ? -1 : 1;
}
acc1 <<= 32;
acc2 <<= 32;
processed += 32;
bit_count -= 32;
}
// now 0 <= bit_count <= 39
bs1_offs += (int)bit_count - 8; // = bit_count - z1, bits to load from bs1
while (bs1_offs >= 8) {
acc1 |= ((unsigned long long)(*bs1++) << (56 - z1));
z1 += 8;
bs1_offs -= 8;
}
if (bs1_offs > 0) {
acc1 |= ((unsigned long long)(*bs1) << (56 - z1));
}
z1 += bs1_offs; // NB: bs1_offs may be negative
bs2_offs += (int)bit_count - 8; // bits to load from bs2
while (bs2_offs >= 8) {
acc2 |= ((unsigned long long)(*bs2++) << (56 - z2));
z2 += 8;
bs2_offs -= 8;
}
if (bs2_offs > 0) {
acc2 |= ((unsigned long long)(*bs2) << (56 - z2));
}
z2 += bs2_offs;
CHECK(z1 == z2);
CHECK(z1 < 64);
//fprintf(stderr, "acc1=%016llx acc2=%016llx z1=z2=%d\n", acc1, acc2, z1);
if (z1) {
if ((acc1 ^ acc2) & (~0ULL << (64 - z1))) {
if (same_upto) {
*same_upto = processed + td::count_leading_zeroes64(acc1 ^ acc2);
}
return acc1 < acc2 ? -1 : 1;
}
}
if (same_upto) {
*same_upto = processed + bit_count;
}
return 0;
}
int bits_memcmp(ConstBitPtr bs1, ConstBitPtr bs2, std::size_t bit_count, std::size_t* same_upto) {
return bits_memcmp(bs1.ptr, bs1.offs, bs2.ptr, bs2.offs, bit_count, same_upto);
}
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 res = bits_memcmp(bs1, bs1_offs, bs2, bs2_offs, std::min(bs1_bit_count, bs2_bit_count), 0);
if (res || bs1_bit_count == bs2_bit_count) {
return res;
}
return bs1_bit_count < bs2_bit_count ? -1 : 1;
}
int bits_lexcmp(ConstBitPtr bs1, std::size_t bs1_bit_count, ConstBitPtr bs2, std::size_t bs2_bit_count) {
return bits_lexcmp(bs1.ptr, bs1.offs, bs1_bit_count, bs2.ptr, bs2.offs, bs2_bit_count);
}
void bits_store_long_top(unsigned char* to, int to_offs, unsigned long long val, unsigned top_bits) {
CHECK(top_bits <= 64);
if (top_bits <= 0) {
return;
}
to += (to_offs >> 3);
to_offs &= 7;
if (!to_offs && !(top_bits & 7)) {
// good only on little-endian machines!
unsigned long long tmp = td::bswap64(val);
std::memcpy(to, &tmp, top_bits >> 3);
return;
}
unsigned long long z = (unsigned long long)(*to & (-0x100 >> to_offs)) << 56;
z |= (val >> to_offs);
top_bits += to_offs;
if (top_bits > 64) {
as<unsigned long long>(to) = td::bswap64(z);
z = (val << (8 - to_offs));
int mask = (0xff >> (top_bits - 64));
to[8] = (unsigned char)((to[8] & mask) | ((int)z & ~mask));
} else {
int p = 56, q = 64 - top_bits;
if (q <= 32) {
as<unsigned>(to) = td::bswap32((unsigned)(z >> 32));
to += 4;
p -= 32;
}
while (p >= q) {
*to++ = (unsigned char)(z >> p);
p -= 8;
}
top_bits = p + 8 - q;
if (top_bits > 0) {
int mask = (0xff >> top_bits);
*to = (unsigned char)((*to & mask) | ((z >> p) & ~mask));
}
}
}
void bits_store_long_top(BitPtr to, unsigned long long val, unsigned top_bits) {
bits_store_long_top(to.ptr, to.offs, val, top_bits);
}
void bits_store_long(BitPtr to, unsigned long long val, unsigned bits) {
bits_store_long_top(to, val << (64 - bits), bits);
}
unsigned long long bits_load_long_top(const unsigned char* from, int from_offs, unsigned top_bits) {
CHECK(top_bits <= 64);
if (!top_bits) {
return 0;
}
from += (from_offs >> 3);
from_offs &= 7;
if ((unsigned)from_offs + top_bits <= 64) {
unsigned long long tmp;
std::memcpy(&tmp, from, (from_offs + top_bits + 7) >> 3);
return (td::bswap64(tmp) << from_offs) & (std::numeric_limits<td::uint64>::max() << (64 - top_bits));
} else {
unsigned long long z = td::bswap64(as<unsigned long long>(from));
z <<= from_offs;
z |= (from[8] >> (8 - from_offs));
return z & (std::numeric_limits<td::uint64>::max() << (64 - top_bits));
}
}
unsigned long long bits_load_long_top(ConstBitPtr from, unsigned top_bits) {
return bits_load_long_top(from.ptr, from.offs, top_bits);
}
unsigned long long bits_load_ulong(ConstBitPtr from, unsigned bits) {
return bits_load_long_top(from, bits) >> (64 - bits);
}
long long bits_load_long(ConstBitPtr from, unsigned bits) {
return (long long)bits_load_long_top(from, bits) >> (64 - bits);
}
std::string bits_to_binary(const unsigned char* ptr, int offs, std::size_t len) {
if (!len) {
return "";
}
std::string s;
s.reserve(len);
ptr += (offs >> 3);
unsigned mask = (0x80 >> (offs & 7));
unsigned value = *ptr++;
do {
s.push_back(value & mask ? '1' : '0');
if (!(mask >>= 1)) {
value = *ptr++;
mask = 0x80;
}
} while (--len > 0);
return s;
}
std::string bits_to_binary(ConstBitPtr bs, std::size_t len) {
return bits_to_binary(bs.ptr, bs.offs, len);
}
static const char hex_digits[] = "0123456789ABCDEF";
std::string bits_to_hex(const unsigned char* ptr, int offs, std::size_t len) {
if (!len) {
return "";
}
std::string s;
s.reserve((len + 7) >> 2);
ptr += (offs >> 3);
offs &= 7;
unsigned long long acc = *ptr++ & (0xff >> offs);
unsigned bits = 8 - offs;
if (bits > len) {
acc >>= bits - (unsigned)len;
bits = (unsigned)len;
} else {
len -= bits;
while (len >= 8) {
while (len >= 8 && bits <= 56) {
acc <<= 8;
acc |= *ptr++;
bits += 8;
len -= 8;
}
while (bits >= 4) {
bits -= 4;
s.push_back(hex_digits[(acc >> bits) & 15]);
}
}
if (len > 0) {
acc <<= len;
acc |= (*ptr >> (8 - len));
bits += (unsigned)len;
}
}
int f = bits & 3;
if (f) {
acc = (2 * acc + 1) << (3 - f);
bits += 4 - f;
}
while (bits >= 4) {
bits -= 4;
s.push_back(hex_digits[(acc >> bits) & 15]);
}
CHECK(!bits);
if (f) {
s.push_back('_');
}
return s;
}
std::string bits_to_hex(ConstBitPtr bs, std::size_t len) {
return bits_to_hex(bs.ptr, bs.offs, len);
}
long parse_bitstring_hex_literal(unsigned char* buff, std::size_t buff_size, const char* str, const char* str_end) {
std::size_t hex_digits_count = 0;
bool cmpl = false;
unsigned char* ptr = buff;
const char* rptr = str;
while (rptr < str_end) {
int c = *rptr++;
if (c == ' ' || c == '\t') {
continue;
}
if (cmpl) {
return td::narrow_cast<long>(str - rptr);
}
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
int val = (c <= '9') ? c - '0' : ((c | 0x20) - 'a' + 10);
if (hex_digits_count >= 2 * buff_size) {
return td::narrow_cast<long>(str - rptr);
}
if (!(hex_digits_count & 1)) {
*ptr = (unsigned char)(val << 4);
} else {
*ptr = (unsigned char)(*ptr | val);
ptr++;
}
hex_digits_count++;
continue;
}
if (c == '_') {
cmpl = true;
} else {
return td::narrow_cast<long>(str - rptr);
}
}
std::size_t bits = 4 * hex_digits_count;
if (cmpl && bits) {
int t = (hex_digits_count & 1) ? (0x100 + *ptr) >> 4 : (0x100 + *--ptr);
while (bits > 0) {
--bits;
if (t & 1) {
break;
}
t >>= 1;
if (t == 1) {
t = 0x100 + *--ptr;
}
}
}
return bits;
}
long parse_bitstring_binary_literal(BitPtr buff, std::size_t buff_size, const char* str, const char* str_end) {
const char* ptr = str;
while (ptr < str_end && buff_size && (*ptr == '0' || *ptr == '1')) {
*buff++ = (bool)(*ptr++ & 1);
--buff_size;
}
return td::narrow_cast<long>(ptr == str_end ? ptr - str : str - ptr - 1);
}
void bits_sha256(BitPtr to, ConstBitPtr from, std::size_t size) {
if (from.byte_aligned() && !(size & 7)) {
if (to.byte_aligned()) {
digest::hash_str<digest::SHA256>(to.get_byte_ptr(), from.get_byte_ptr(), size >> 3);
} else {
unsigned char buffer[32];
digest::hash_str<digest::SHA256>(buffer, from.get_byte_ptr(), size >> 3);
to.copy_from(BitPtr{buffer}, 256);
}
} else {
throw BitstringError{};
}
}
} // namespace bitstring
} // namespace td

662
crypto/common/bitstring.h Normal file
View file

@ -0,0 +1,662 @@
/*
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);
}
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();
}
unsigned size() const {
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

55
crypto/common/refcnt.cpp Normal file
View file

@ -0,0 +1,55 @@
/*
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
*/
#include "refcnt.hpp"
#include "td/utils/ScopeGuard.h"
namespace td {
namespace detail {
struct SafeDeleter {
public:
void retire(const CntObject *ptr) {
if (is_active_) {
to_delete_.push_back(ptr);
return;
}
is_active_ = true;
SCOPE_EXIT {
is_active_ = false;
};
delete ptr;
while (!to_delete_.empty()) {
auto *ptr = to_delete_.back();
to_delete_.pop_back();
delete ptr;
}
}
private:
std::vector<const CntObject *> to_delete_;
bool is_active_{false};
};
TD_THREAD_LOCAL SafeDeleter *deleter;
void safe_delete(const CntObject *ptr) {
init_thread_local<SafeDeleter>(deleter);
deleter->retire(ptr);
}
} // namespace detail
} // namespace td

474
crypto/common/refcnt.hpp Normal file
View file

@ -0,0 +1,474 @@
/*
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 <cassert>
#include <utility>
#include <atomic>
#include <iostream>
#include "td/utils/StringBuilder.h"
#include "td/utils/logging.h"
namespace td {
template <class T>
class Ref;
class CntObject {
private:
mutable std::atomic<int> cnt_;
template <class T>
friend class Ref;
void inc() const {
cnt_.fetch_add(1, std::memory_order_relaxed);
}
bool dec() const {
return cnt_.fetch_sub(1, std::memory_order_acq_rel) == 1;
}
void inc(int cnt) const {
cnt_.fetch_add(cnt, std::memory_order_relaxed);
}
bool dec(int cnt) const {
return cnt_.fetch_sub(cnt, std::memory_order_acq_rel) == cnt;
}
public:
struct WriteError {};
CntObject() : cnt_(1) {
}
CntObject(const CntObject& other) : CntObject() {
}
CntObject(CntObject&& other) : CntObject() {
}
CntObject& operator=(const CntObject& other) {
return *this;
}
CntObject& operator=(CntObject&& other) {
return *this;
}
virtual ~CntObject() {
auto cnt = cnt_.load(std::memory_order_relaxed);
(void)cnt;
//TODO: assert(cnt == 0) will fail if object is allocated on stack
assert(cnt == 0 || cnt == 1);
}
virtual CntObject* make_copy() const {
throw WriteError();
}
bool is_unique() const {
return cnt_.load(std::memory_order_acquire) == 1;
}
int get_refcnt() const {
// use std::memory_order_acquire
return cnt_.load(std::memory_order_acquire);
}
void assert_unique() const {
assert(is_unique());
}
};
typedef Ref<CntObject> RefAny;
template <class T>
class Cnt : public CntObject {
T value;
public:
template <typename... Args>
Cnt(Args&&... args) : value(std::forward<Args>(args)...) {
///std::cout << "(N " << (void*)this << ")";
}
Cnt(const Cnt& x) : CntObject(), value(x.value) {
///std::cout << "(C)";
}
virtual ~Cnt() {
///std::cout << "(D " << (void*)this << ")";
}
T* operator->() {
return &value;
}
const T* operator->() const {
return &value;
}
T& operator*() {
return value;
}
const T& operator*() const {
return value;
}
Cnt* make_copy() const override {
///std::cout << "(c " << (const void*)this << ")";
return new Cnt{value};
}
};
template <class T>
struct RefValue {
using Type = T;
static Type& make_ref(T* ptr) {
return *ptr;
}
static const Type& make_const_ref(const T* ptr) {
return *ptr;
}
static Type* make_ptr(T* ptr) {
return ptr;
}
static const Type* make_const_ptr(const T* ptr) {
return ptr;
}
};
template <class T>
struct RefValue<Cnt<T>> {
using Type = T;
static Type& make_ref(Cnt<T>* ptr) {
return **ptr;
}
static const Type& make_const_ref(const Cnt<T>* ptr) {
return **ptr;
}
static Type* make_ptr(Cnt<T>* ptr) {
return &(**ptr);
}
static const Type* make_const_ptr(const Cnt<T>* ptr) {
return &(**ptr);
}
};
struct static_cast_ref {};
namespace detail {
void safe_delete(const CntObject* ptr);
}
template <class T>
class Ref {
T* ptr;
template <class S>
friend class Ref;
public:
struct NullRef {};
Ref() : ptr(0) {
}
//explicit Ref(bool init) : ptr(init ? new T : 0) {
//}
template <typename... Args>
explicit Ref(bool init, Args&&... args) : ptr(0) {
//assert(init);
ptr = new T(std::forward<Args>(args)...);
}
/*
explicit Ref(const T& c) : ptr(&c) {
ptr.inc();
}
*/
explicit Ref(T* pc) : ptr(pc) {
if (ptr) {
acquire_shared(ptr);
}
}
explicit Ref(const T* pc) : ptr(const_cast<T*>(pc)) {
if (ptr) {
acquire_shared(ptr);
}
}
explicit Ref(const T& obj) : ptr(obj.make_copy()) {
}
Ref(const Ref& r) : ptr(r.ptr) {
if (ptr) {
acquire_shared(ptr);
///std::cout << "(rc+ " << (const void*)ptr << ")";
}
}
Ref(Ref&& r) noexcept : ptr(std::move(r.ptr)) {
r.ptr = 0;
}
T* release() {
auto res = ptr;
ptr = nullptr;
return res;
}
struct acquire_t {};
Ref(T* ptr, acquire_t) : ptr(ptr) {
}
template <class S>
Ref(const Ref<S>& r, std::enable_if_t<std::is_base_of<T, S>::value, int> t = 0) : ptr(static_cast<T*>(r.ptr)) {
static_assert(std::is_base_of<T, S>::value, "Invalid static Ref conversion");
if (ptr) {
acquire_shared(ptr);
}
}
template <class S>
explicit Ref(const Ref<S>& r,
std::enable_if_t<!std::is_base_of<T, S>::value && std::is_base_of<S, T>::value, int> t = 0)
: ptr(dynamic_cast<T*>(r.ptr)) {
static_assert(std::is_base_of<S, T>::value, "Invalid dynamic Ref conversion");
if (ptr) {
acquire_shared(ptr);
//std::cout << "(rv+ " << (const void*)ptr << ")";
} else {
//std::cout << "(error converting " << (const void*)r.ptr << ")";
}
}
template <class S>
Ref(static_cast_ref, const Ref<S>& r, std::enable_if_t<std::is_base_of<S, T>::value, int> t = 0)
: ptr(static_cast<T*>(r.ptr)) {
static_assert(std::is_base_of<S, T>::value, "Invalid static Ref downcast");
if (r.ptr) {
acquire_shared(ptr);
} else {
ptr = nullptr;
}
}
template <class S>
Ref(Ref<S>&& r, std::enable_if_t<std::is_base_of<T, S>::value, int> t = 0) : ptr(static_cast<T*>(r.ptr)) {
static_assert(std::is_base_of<T, S>::value, "Invalid static Ref conversion");
r.ptr = nullptr;
}
template <class S>
explicit Ref(Ref<S>&& r, std::enable_if_t<!std::is_base_of<T, S>::value && std::is_base_of<S, T>::value, int> t = 0)
: ptr(dynamic_cast<T*>(r.ptr)) {
static_assert(std::is_base_of<S, T>::value, "Invalid dynamic Ref conversion");
if (!ptr && r.ptr) {
release_shared(r.ptr);
}
r.ptr = nullptr;
}
template <class S>
Ref(static_cast_ref, Ref<S>&& r, std::enable_if_t<std::is_base_of<S, T>::value, int> t = 0) noexcept
: ptr(static_cast<T*>(r.ptr)) {
static_assert(std::is_base_of<S, T>::value, "Invalid static Ref downcast");
if (r.ptr) {
r.ptr = nullptr;
} else {
ptr = nullptr;
}
}
~Ref() {
clear();
}
Ref& operator=(const Ref& r);
template <class S>
Ref& operator=(const Ref<S>& r);
Ref& operator=(Ref&& r);
template <class S>
Ref& operator=(Ref<S>&& r);
const typename RefValue<T>::Type* operator->() const {
if (!ptr) {
CHECK(ptr && "deferencing null Ref");
throw NullRef{};
}
return RefValue<T>::make_const_ptr(ptr);
}
const typename RefValue<T>::Type& operator*() const {
if (!ptr) {
CHECK(ptr && "deferencing null Ref");
throw NullRef{};
}
return RefValue<T>::make_const_ref(ptr);
}
const T* get() const {
return ptr;
}
bool is_null() const {
return ptr == 0;
}
bool not_null() const {
return ptr != 0;
}
bool is_unique() const {
if (!ptr) {
CHECK(ptr && "defererencing null Ref");
throw NullRef{};
}
return ptr->is_unique();
}
void clear() {
if (ptr) {
///std::cout << "(r- " << (const void*)ptr << ")";
release_shared(ptr);
ptr = 0;
}
}
void swap(Ref& r) {
std::swap(ptr, r.ptr);
}
Ref& operator^=(const Ref& r);
Ref& operator^=(Ref&& r);
Ref& operator&=(bool retain);
bool operator==(const Ref& r) const;
bool operator!=(const Ref& r) const;
typename RefValue<T>::Type& write();
typename RefValue<T>::Type& unique_write() const;
public:
template <class S>
static void release_shared(S* obj, int cnt = 1) {
if (obj->dec(cnt)) {
detail::safe_delete(obj);
}
}
template <class S>
static void acquire_shared(S* obj, int cnt = 1) {
obj->inc(cnt);
}
private:
void assign(T* p) {
ptr = p;
if (p) {
acquire_shared(p);
///std::cout << "(r+ " << (const void*)ptr << ")";
}
}
};
template <class T, typename... Args>
Ref<T> make_ref(Args&&... args) {
return Ref<T>{true, std::forward<Args>(args)...};
}
template <class T, typename... Args>
Ref<Cnt<T>> make_cnt_ref(Args&&... args) {
return Ref<Cnt<T>>{true, std::forward<Args>(args)...};
}
template <class T>
td::StringBuilder& operator<<(td::StringBuilder& sb, const Ref<T>& ref) {
if (ref.is_null()) {
return sb << "nullptr";
}
return sb << *ref;
}
template <class T>
Ref<T>& Ref<T>::operator=(const Ref<T>& r) {
if (ptr != r.ptr) {
clear();
assign(r.ptr);
}
return *this;
}
template <class T>
template <class S>
Ref<T>& Ref<T>::operator=(const Ref<S>& r) {
if (ptr != static_cast<T*>(r.ptr)) {
clear();
assign(r.ptr);
}
return *this;
}
template <class T>
Ref<T>& Ref<T>::operator=(Ref<T>&& r) {
clear();
ptr = r.ptr;
r.ptr = 0;
return *this;
}
template <class T>
template <class S>
Ref<T>& Ref<T>::operator=(Ref<S>&& r) {
clear();
ptr = r.ptr;
r.ptr = 0;
return *this;
}
template <class T>
typename RefValue<T>::Type& Ref<T>::write() {
if (!ptr) {
throw CntObject::WriteError();
}
if (!ptr->is_unique()) {
T* copy = dynamic_cast<T*>(ptr->make_copy());
if (!copy) {
throw CntObject::WriteError();
}
release_shared(ptr);
ptr = copy;
}
return RefValue<T>::make_ref(ptr);
}
template <class T>
typename RefValue<T>::Type& Ref<T>::unique_write() const {
if (!ptr || !ptr->is_unique()) {
throw CntObject::WriteError();
}
return RefValue<T>::make_ref(ptr);
}
template <class T>
Ref<T>& Ref<T>::operator^=(const Ref<T>& r) {
if (r.ptr && r.ptr != ptr) {
clear();
assign(r.ptr);
}
return *this;
}
template <class T>
Ref<T>& Ref<T>::operator^=(Ref<T>&& r) {
if (r.ptr && r.ptr != ptr) {
clear();
ptr = r.ptr;
r.ptr = 0;
}
return *this;
}
template <class T>
Ref<T>& Ref<T>::operator&=(bool retain) {
if (!retain && ptr) {
clear();
}
return *this;
}
template <class T>
bool Ref<T>::operator==(const Ref<T>& r) const {
return ptr == r.ptr;
}
template <class T>
bool Ref<T>::operator!=(const Ref<T>& r) const {
return ptr != r.ptr;
}
template <class T>
void swap(Ref<T>& r1, Ref<T>& r2) {
r1.swap(r2);
}
} // namespace td

321
crypto/common/refint.cpp Normal file
View file

@ -0,0 +1,321 @@
/*
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
*/
#include "common/refint.h"
#include <utility>
#include <iostream>
#include "td/utils/StringBuilder.h"
#include "td/utils/Slice.h"
namespace td {
template class Cnt<BigInt256>;
template class Ref<Cnt<BigInt256>>;
RefInt256 operator+(RefInt256 x, RefInt256 y) {
(x.write() += *y).normalize();
return x;
}
RefInt256 operator+(RefInt256 x, long long y) {
x.write().add_tiny(y).normalize();
return x;
}
RefInt256 operator-(RefInt256 x, RefInt256 y) {
(x.write() -= *y).normalize();
return x;
}
RefInt256 operator-(RefInt256 x, long long y) {
x.write().add_tiny(-y).normalize();
return x;
}
RefInt256 operator-(RefInt256 x) {
x.write().negate().normalize();
return x;
}
RefInt256 operator~(RefInt256 x) {
x.write().logical_not().normalize();
return x;
}
RefInt256 operator*(RefInt256 x, RefInt256 y) {
RefInt256 z{true, 0};
z.write().add_mul(*x, *y).normalize();
return z;
}
RefInt256 operator*(RefInt256 x, long long y) {
x.write().mul_short_opt(y).normalize();
return x;
}
RefInt256 operator/(RefInt256 x, RefInt256 y) {
RefInt256 quot{true};
x.write().mod_div(*y, quot.write());
quot.write().normalize();
return quot;
}
RefInt256 div(RefInt256 x, RefInt256 y, int round_mode) {
RefInt256 quot{true};
x.write().mod_div(*y, quot.write(), round_mode);
quot.write().normalize();
return quot;
}
RefInt256 operator%(RefInt256 x, RefInt256 y) {
BigInt256 quot;
x.write().mod_div(*y, quot);
return x;
}
RefInt256 mod(RefInt256 x, RefInt256 y, int round_mode) {
BigInt256 quot;
x.write().mod_div(*y, quot, round_mode);
return x;
}
std::pair<RefInt256, RefInt256> divmod(RefInt256 x, RefInt256 y, int round_mode) {
RefInt256 quot{true};
x.write().mod_div(*y, quot.write(), round_mode);
quot.write().normalize();
return std::make_pair(std::move(quot), std::move(x));
}
RefInt256 operator&(RefInt256 x, RefInt256 y) {
x.write() &= *y;
return x;
}
RefInt256 operator|(RefInt256 x, RefInt256 y) {
x.write() |= *y;
return x;
}
RefInt256 operator^(RefInt256 x, RefInt256 y) {
x.write() ^= *y;
return x;
}
RefInt256 operator<<(RefInt256 x, int y) {
(x.write() <<= y).normalize();
return x;
}
RefInt256 operator>>(RefInt256 x, int y) {
(x.write() >>= y).normalize();
return x;
}
RefInt256 rshift(RefInt256 x, int y, int round_mode) {
x.write().rshift(y, round_mode).normalize();
return x;
}
RefInt256& operator+=(RefInt256& x, RefInt256 y) {
(x.write() += *y).normalize();
return x;
}
RefInt256& operator+=(RefInt256& x, long long y) {
x.write().add_tiny(y).normalize();
return x;
}
RefInt256& operator-=(RefInt256& x, RefInt256 y) {
(x.write() -= *y).normalize();
return x;
}
RefInt256& operator-=(RefInt256& x, long long y) {
x.write().add_tiny(-y).normalize();
return x;
}
RefInt256& operator*=(RefInt256& x, RefInt256 y) {
RefInt256 z{true, 0};
z.write().add_mul(*x, *y).normalize();
return x = z;
}
RefInt256& operator*=(RefInt256& x, long long y) {
x.write().mul_short_opt(y).normalize();
return x;
}
RefInt256& operator/=(RefInt256& x, RefInt256 y) {
RefInt256 quot{true};
x.write().mod_div(*y, quot.write());
quot.write().normalize();
return x = quot;
}
RefInt256& operator%=(RefInt256& x, RefInt256 y) {
BigInt256 quot;
x.write().mod_div(*y, quot);
return x;
}
RefInt256& operator&=(RefInt256& x, RefInt256 y) {
x.write() &= *y;
return x;
}
RefInt256& operator|=(RefInt256& x, RefInt256 y) {
x.write() |= *y;
return x;
}
RefInt256& operator^=(RefInt256& x, RefInt256 y) {
x.write() ^= *y;
return x;
}
RefInt256& operator<<=(RefInt256& x, int y) {
(x.write() <<= y).normalize();
return x;
}
RefInt256& operator>>=(RefInt256& x, int y) {
(x.write() >>= y).normalize();
return x;
}
int cmp(RefInt256 x, RefInt256 y) {
return x->cmp(*y);
}
int cmp(RefInt256 x, long long y) {
return x->cmp(y);
}
int sgn(RefInt256 x) {
return x->sgn();
}
extern RefInt256 make_refint(long long x) {
auto xx = td::RefInt256{true, x};
xx.unique_write().normalize();
return xx;
}
std::string dec_string(RefInt256 x) {
return x.is_null() ? "(null)" : (x.is_unique() ? x.unique_write().to_dec_string_destroy() : x->to_dec_string());
}
std::string dec_string2(RefInt256&& x) {
return x.is_null() ? "(null)" : (x.is_unique() ? x.unique_write().to_dec_string_destroy() : x->to_dec_string());
}
std::string hex_string(RefInt256 x, bool upcase) {
return x.is_null() ? "(null)" : x->to_hex_string(upcase);
}
std::string binary_string(RefInt256 x) {
return x.is_null() ? "(null)" : x->to_binary_string();
}
std::ostream& operator<<(std::ostream& os, const RefInt256& x) {
//std::cout << "<a|";
return os << dec_string(std::move(x));
//std::cout << "|a>";
//return os;
}
std::ostream& operator<<(std::ostream& os, RefInt256&& x) {
//std::cout << "<A|";
return os << dec_string2(std::move(x));
//std::cout << "|A>";
//return os;
}
StringBuilder& operator<<(StringBuilder& sb, const RefInt256& x) {
return sb << dec_string(x);
}
RefInt256 dec_string_to_int256(const std::string& s) {
return dec_string_to_int256(td::Slice{s});
}
RefInt256 dec_string_to_int256(td::Slice s) {
if (s.size() > 255) {
return {};
}
RefInt256 x{true};
if (x.unique_write().parse_dec(s.begin(), (int)s.size()) == (int)s.size()) {
return x;
} else {
return {};
}
}
RefInt256 hex_string_to_int256(const std::string& s) {
return hex_string_to_int256(td::Slice{s});
}
RefInt256 hex_string_to_int256(td::Slice s) {
if (s.size() > 255) {
return {};
}
RefInt256 x{true};
if (x.unique_write().parse_hex(s.begin(), (int)s.size()) == (int)s.size()) {
return x;
} else {
return {};
}
}
RefInt256 string_to_int256(const std::string& s) {
return string_to_int256(td::Slice{s});
}
RefInt256 string_to_int256(td::Slice s) {
if (s.size() >= 3 && s[0] == '-' && s[1] == '0' && s[2] == 'x') {
auto x = hex_string_to_int256(td::Slice(s.begin() + 3, s.end()));
if (x.not_null()) {
x.write().negate();
}
return x;
} else if (s.size() >= 2 && s[0] == '0' && s[1] == 'x') {
return hex_string_to_int256(td::Slice(s.begin() + 2, s.end()));
} else {
return dec_string_to_int256(s);
}
}
namespace literals {
RefInt256 operator""_ri256(const char* str, std::size_t str_len) {
RefInt256 x{true};
x->enforce(x.unique_write().parse_dec(str, (int)str_len) == (int)str_len);
return x;
}
RefInt256 operator""_rx256(const char* str, std::size_t str_len) {
RefInt256 x{true};
x->enforce(x.unique_write().parse_hex(str, (int)str_len) == (int)str_len);
return x;
}
} // namespace literals
} // namespace td

127
crypto/common/refint.h Normal file
View file

@ -0,0 +1,127 @@
/*
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 "common/bigint.hpp"
#include <utility>
#include <string>
namespace td {
class StringBuilder;
extern template class Cnt<BigInt256>;
extern template class Ref<Cnt<BigInt256>>;
typedef Cnt<BigInt256> CntInt256;
typedef Ref<CntInt256> RefInt256;
extern RefInt256 operator+(RefInt256 x, RefInt256 y);
extern RefInt256 operator+(RefInt256 x, long long y);
extern RefInt256 operator-(RefInt256 x, RefInt256 y);
extern RefInt256 operator-(RefInt256 x, long long y);
extern RefInt256 operator*(RefInt256 x, RefInt256 y);
extern RefInt256 operator*(RefInt256 x, long long y);
extern RefInt256 operator/(RefInt256 x, RefInt256 y);
extern RefInt256 operator%(RefInt256 x, RefInt256 y);
extern RefInt256 div(RefInt256 x, RefInt256 y, int round_mode = -1);
extern RefInt256 mod(RefInt256 x, RefInt256 y, int round_mode = -1);
extern std::pair<RefInt256, RefInt256> divmod(RefInt256 x, RefInt256 y, int round_mode = -1);
extern RefInt256 operator-(RefInt256 x);
extern RefInt256 operator&(RefInt256 x, RefInt256 y);
extern RefInt256 operator|(RefInt256 x, RefInt256 y);
extern RefInt256 operator^(RefInt256 x, RefInt256 y);
extern RefInt256 operator~(RefInt256 x);
extern RefInt256 operator<<(RefInt256 x, int y);
extern RefInt256 operator>>(RefInt256 x, int y);
extern RefInt256 rshift(RefInt256 x, int y, int round_mode = -1);
extern RefInt256& operator+=(RefInt256& x, RefInt256 y);
extern RefInt256& operator+=(RefInt256& x, long long y);
extern RefInt256& operator-=(RefInt256& x, RefInt256 y);
extern RefInt256& operator-=(RefInt256& x, long long y);
extern RefInt256& operator*=(RefInt256& x, RefInt256 y);
extern RefInt256& operator*=(RefInt256& x, long long y);
extern RefInt256& operator/=(RefInt256& x, RefInt256 y);
extern RefInt256& operator%=(RefInt256& x, RefInt256 y);
extern RefInt256& operator&=(RefInt256& x, RefInt256 y);
extern RefInt256& operator|=(RefInt256& x, RefInt256 y);
extern RefInt256& operator^=(RefInt256& x, RefInt256 y);
extern RefInt256& operator<<=(RefInt256& x, int y);
extern RefInt256& operator>>=(RefInt256& x, int y);
template <typename T>
bool operator==(RefInt256 x, T y) {
return cmp(x, y) == 0;
}
template <typename T>
bool operator!=(RefInt256 x, T y) {
return cmp(x, y) != 0;
}
template <typename T>
bool operator<(RefInt256 x, T y) {
return cmp(x, y) < 0;
}
template <typename T>
bool operator>(RefInt256 x, T y) {
return cmp(x, y) > 0;
}
template <typename T>
bool operator<=(RefInt256 x, T y) {
return cmp(x, y) <= 0;
}
template <typename T>
bool operator>=(RefInt256 x, T y) {
return cmp(x, y) >= 0;
}
extern int cmp(RefInt256 x, RefInt256 y);
extern int cmp(RefInt256 x, long long y);
extern int sgn(RefInt256 x);
extern RefInt256 make_refint(long long x);
extern std::string dec_string(RefInt256 x);
extern std::string dec_string2(RefInt256&& x);
extern std::string hex_string(RefInt256 x, bool upcase = false);
extern std::string binary_string(RefInt256 x);
extern RefInt256 dec_string_to_int256(const std::string& s);
extern RefInt256 dec_string_to_int256(td::Slice s);
extern RefInt256 hex_string_to_int256(const std::string& s);
extern RefInt256 hex_string_to_int256(td::Slice s);
extern RefInt256 string_to_int256(const std::string& s);
extern RefInt256 string_to_int256(td::Slice s);
extern std::ostream& operator<<(std::ostream& os, const RefInt256& x);
extern std::ostream& operator<<(std::ostream& os, RefInt256&& x);
extern td::StringBuilder& operator<<(td::StringBuilder& os, const RefInt256& x);
namespace literals {
extern RefInt256 operator""_ri256(const char* str, std::size_t str_len);
extern RefInt256 operator""_rx256(const char* str, std::size_t str_len);
} // namespace literals
} // namespace td

212
crypto/common/util.cpp Normal file
View file

@ -0,0 +1,212 @@
/*
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
*/
#include "util.h"
#include <limits>
namespace td {
std::size_t compute_base64_encoded_size(size_t bindata_size) {
return ((bindata_size + 2) / 3) << 2;
}
const char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const char base64_url_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
const unsigned char base64_dec_table[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0x7e, 0, 0xbe, 0, 0x7f, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc,
0xfd, 0, 0, 0, 1, 0, 0, 0, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca,
0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0, 0, 0, 0,
0xbf, 0, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0, 0, 0, 0, 0};
std::size_t buff_base64_encode(td::MutableSlice buffer, td::Slice raw, bool base64_url) {
std::size_t orig_size = raw.size(), res_size = compute_base64_encoded_size(orig_size);
if (res_size > buffer.size()) {
return 0;
}
const char *table = base64_url ? base64_url_table : base64_table;
char *wptr = buffer.data();
unsigned x;
std::size_t i;
for (i = 0; i < orig_size - 2; i += 3) {
x = (((unsigned)(unsigned char)raw[i]) << 16) | (((unsigned)(unsigned char)raw[i + 1]) << 8) |
((unsigned)(unsigned char)raw[i + 2]);
*wptr++ = table[(x >> 18) & 0x3f];
*wptr++ = table[(x >> 12) & 0x3f];
*wptr++ = table[(x >> 6) & 0x3f];
*wptr++ = table[x & 0x3f];
}
switch (orig_size - i) {
case 1:
x = (((unsigned)(unsigned char)raw[i]) << 16);
*wptr++ = table[(x >> 18) & 0x3f];
*wptr++ = table[(x >> 12) & 0x3f];
*wptr++ = '=';
*wptr++ = '=';
break;
case 2:
x = (((unsigned)(unsigned char)raw[i]) << 16) | (((unsigned)(unsigned char)raw[i + 1]) << 8);
*wptr++ = table[(x >> 18) & 0x3f];
*wptr++ = table[(x >> 12) & 0x3f];
*wptr++ = table[(x >> 6) & 0x3f];
*wptr++ = '=';
}
CHECK(wptr == buffer.data() + res_size);
return res_size;
}
std::string str_base64_encode(std::string raw, bool base64_url) {
return str_base64_encode(td::Slice{raw}, base64_url);
}
std::string str_base64_encode(td::Slice raw, bool base64_url) {
std::size_t res_size = compute_base64_encoded_size(raw.size());
std::string s;
s.resize(res_size);
if (res_size) {
buff_base64_encode(td::MutableSlice{const_cast<char *>(s.data()), s.size()}, raw, base64_url);
}
return s;
}
bool is_valid_base64(std::string encoded, bool allow_base64_url) {
return is_valid_base64(td::Slice{encoded}, allow_base64_url);
}
bool is_valid_base64(td::Slice encoded, bool allow_base64_url) {
const unsigned char *ptr = (const unsigned char *)encoded.data(), *end = ptr + encoded.size();
if (encoded.size() & 3) {
return false;
}
unsigned mode = (allow_base64_url ? 0xc0 : 0x40);
while (ptr < end && (base64_dec_table[*ptr] & mode)) {
ptr++;
}
std::size_t d = end - ptr;
if (d > 2) {
return false;
}
while (ptr < end && *ptr == '=') {
ptr++;
}
return ptr == end;
}
td::int32 decoded_base64_size(std::string encoded, bool allow_base64_url) {
return decoded_base64_size(td::Slice{encoded}, allow_base64_url);
}
td::int32 decoded_base64_size(td::Slice encoded, bool allow_base64_url) {
const unsigned char *ptr = (const unsigned char *)encoded.data(), *end = ptr + encoded.size();
if (encoded.size() & 3) {
return -1;
}
if (encoded.size() > static_cast<size_t>(std::numeric_limits<td::int32>::max())) {
return -1;
}
if (end == ptr) {
return 0;
}
auto s = static_cast<td::int32>((encoded.size() >> 2) * 3);
if (end[-1] == '=') {
s--;
if (end[-2] == '=') {
s--;
}
}
return s;
}
std::size_t buff_base64_decode(td::MutableSlice buffer, td::Slice encoded, bool allow_base64_url) {
if ((encoded.size() & 3) || !encoded.size()) {
return 0;
}
std::size_t n = (encoded.size() >> 2);
const unsigned char *ptr = (const unsigned char *)encoded.data(), *end = ptr + encoded.size();
unsigned q = (end[-1] == '=' ? (end[-2] == '=' ? 2 : 1) : 0);
if (buffer.size() + q < n * 3) {
return 0;
}
unsigned char *wptr = (unsigned char *)buffer.data(), *wend = wptr + buffer.size();
unsigned mode = (allow_base64_url ? 0xc0 : 0x40);
for (std::size_t i = 0; i < n; i++) {
unsigned x = 0;
for (std::size_t j = 0; j < 4; j++) {
unsigned z = base64_dec_table[ptr[4 * i + j]];
if (!(z & mode) && z != 1 && (i < n - 1 || j + q < 4)) {
return 0;
}
x = (x << 6) | (z & 0x3f);
}
if (i < n - 1) {
*wptr++ = (unsigned char)(x >> 16);
*wptr++ = (unsigned char)(x >> 8);
*wptr++ = (unsigned char)x;
} else {
for (; q < 3; q++) {
*wptr++ = (unsigned char)(x >> 16);
x <<= 8;
}
break;
}
}
CHECK(wptr <= wend);
return wptr - (unsigned char *)buffer.data();
}
td::BufferSlice base64_decode(std::string encoded, bool allow_base64_url) {
return base64_decode(td::Slice{encoded}, allow_base64_url);
}
td::BufferSlice base64_decode(td::Slice encoded, bool allow_base64_url) {
auto s = decoded_base64_size(encoded, allow_base64_url);
if (s <= 0) {
return td::BufferSlice{};
}
td::BufferSlice res{static_cast<std::size_t>(s)};
auto r = buff_base64_decode(res.as_slice(), encoded, allow_base64_url);
if (!r) {
return td::BufferSlice{};
}
CHECK(r == static_cast<std::size_t>(s));
return res;
}
std::string str_base64_decode(std::string encoded, bool allow_base64_url) {
return str_base64_decode(td::Slice{encoded}, allow_base64_url);
}
std::string str_base64_decode(td::Slice encoded, bool allow_base64_url) {
auto s = decoded_base64_size(encoded, allow_base64_url);
if (s <= 0) {
return std::string{};
}
std::string res;
res.resize(static_cast<std::size_t>(s));
auto r = buff_base64_decode(td::MutableSlice{const_cast<char *>(res.data()), res.size()}, encoded, allow_base64_url);
if (!r) {
return std::string{};
}
CHECK(r == static_cast<std::size_t>(s));
return res;
}
} // namespace td

42
crypto/common/util.h Normal file
View file

@ -0,0 +1,42 @@
/*
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 <string>
#include "td/utils/Slice.h"
#include "td/utils/buffer.h"
namespace td {
std::size_t compute_base64_encoded_size(size_t bindata_size);
std::size_t buff_base64_encode(td::MutableSlice buffer, td::Slice raw, bool base64_url = false);
std::string str_base64_encode(std::string raw, bool base64_url = false);
std::string str_base64_encode(td::Slice raw, bool base64_url = false);
bool is_valid_base64(std::string encoded, bool allow_base64_url = true);
bool is_valid_base64(td::Slice encoded, bool allow_base64_url = true);
td::int32 decoded_base64_size(std::string encoded, bool allow_base64_url = true);
td::int32 decoded_base64_size(td::Slice encoded, bool allow_base64_url = true);
std::size_t buff_base64_decode(td::MutableSlice buffer, td::Slice data, bool allow_base64_url = true);
td::BufferSlice base64_decode(std::string encoded, bool allow_base64_url = true);
td::BufferSlice base64_decode(td::Slice encoded, bool allow_base64_url = true);
std::string str_base64_decode(std::string encoded, bool allow_base64_url = true);
std::string str_base64_decode(td::Slice encoded, bool allow_base64_url = true);
} // namespace td