mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
initial commit
This commit is contained in:
commit
c2da007f40
1610 changed files with 398047 additions and 0 deletions
200
crypto/common/AtomicRef.h
Normal file
200
crypto/common/AtomicRef.h
Normal 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
41
crypto/common/bigint.cpp
Normal 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
2525
crypto/common/bigint.hpp
Normal file
File diff suppressed because it is too large
Load diff
668
crypto/common/bitstring.cpp
Normal file
668
crypto/common/bitstring.cpp
Normal 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
662
crypto/common/bitstring.h
Normal 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
55
crypto/common/refcnt.cpp
Normal 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
474
crypto/common/refcnt.hpp
Normal 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
321
crypto/common/refint.cpp
Normal 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
127
crypto/common/refint.h
Normal 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
212
crypto/common/util.cpp
Normal 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
42
crypto/common/util.h
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue