diff --git td/generate/tl-parser/crc32.c td/generate/tl-parser/crc32.c
index b7e0218..4f7fe4a 100644
--- td/generate/tl-parser/crc32.c
+++ td/generate/tl-parser/crc32.c
@@ -298,43 +298,15 @@ unsigned int crc32_table0[256] = {
 };
 
 static unsigned int crc32_partial (const void *data, int len, unsigned crc) {
-  const int *p = (const int *) data;
-  int x;
-#define DO_ONE(v) crc ^= v; crc = crc32_table0[crc & 0xff] ^ crc32_table1[(crc & 0xff00) >> 8] ^ crc32_table2[(crc & 0xff0000) >> 16] ^ crc32_table[crc >> 24];
-#define DO_FOUR(p) DO_ONE((p)[0]); DO_ONE((p)[1]); DO_ONE((p)[2]); DO_ONE((p)[3]);
-
-  for (x = (len >> 5); x > 0; x--) {
-    DO_FOUR (p);
-    DO_FOUR (p + 4);
-    p += 8;
-  }
-  if (len & 16) {
-    DO_FOUR (p);
-    p += 4;
-  }
-  if (len & 8) {
-    DO_ONE (p[0]);
-    DO_ONE (p[1]);
-    p += 2;
-  }
-  if (len & 4) {
-    DO_ONE (*p++);
-  }
-  /*
-  for (x = (len >> 2) & 7; x > 0; x--) {
-    DO_ONE (*p++);
-  }
-  */
-#undef DO_ONE
-#undef DO_FOUR
-  const char *q = (const char *) p;
-  if (len & 2) {
-    crc = crc32_table[(crc ^ q[0]) & 0xff] ^ (crc >> 8);
-    crc = crc32_table[(crc ^ q[1]) & 0xff] ^ (crc >> 8);
-    q += 2;
-  }
-  if (len & 1) {
-    crc = crc32_table[(crc ^ *q++) & 0xff] ^ (crc >> 8);
+  // NB: the original word-at-a-time (slicing-by-4) loop reads 32-bit words from
+  // the buffer and is only correct on little-endian hosts; on big-endian PPC it
+  // effectively byte-swaps each word and computes wrong CRC32 values (e.g. the
+  // TL `Vector` constructor id, breaking generated *_api code). Use a portable
+  // byte-wise CRC32 that yields the canonical little-endian result everywhere.
+  const unsigned char *q = (const unsigned char *) data;
+  int i;
+  for (i = 0; i < len; i++) {
+    crc = crc32_table[(crc ^ q[i]) & 0xff] ^ (crc >> 8);
   }
   return crc;
 }
diff --git td/mtproto/CryptoStorer.h td/mtproto/CryptoStorer.h
index fde1644..a3a1a45 100644
--- td/mtproto/CryptoStorer.h
+++ td/mtproto/CryptoStorer.h
@@ -47,7 +47,7 @@ class ObjectImpl {
     if (empty()) {
       return;
     }
-    storer.store_binary(message_id_);
+    storer.store_binary(message_id_.get());
     storer.store_binary(seq_no_);
     storer.store_binary(static_cast<int32>(object_storer_.size()));
     storer.store_storer(object_storer_);
@@ -140,7 +140,7 @@ class QueryImpl {
 
   template <class StorerT>
   void do_store(StorerT &storer) const {
-    storer.store_binary(query_.message_id);
+    storer.store_binary(query_.message_id.get());
     storer.store_binary(query_.seq_no);
 
     InvokeAfter invoke_after(query_.invoke_after_message_ids);
@@ -318,7 +318,7 @@ class CryptoImpl {
         return storer.store_storer(destroy_key_storer_);
 
       default:
-        storer.store_binary(message_id_);
+        storer.store_binary(message_id_.get());
         storer.store_binary(seq_no_);
         storer.store_binary(static_cast<int32>(container_storer_.size()));
         storer.store_storer(container_storer_);
diff --git td/mtproto/DhHandshake.cpp td/mtproto/DhHandshake.cpp
index b2d224a..0341157 100644
--- td/mtproto/DhHandshake.cpp
+++ td/mtproto/DhHandshake.cpp
@@ -9,6 +9,7 @@
 #include "td/mtproto/DhCallback.h"
 
 #include "td/utils/as.h"
+#include "td/utils/endian_load.h"
 #include "td/utils/crypto.h"
 #include "td/utils/logging.h"
 #include "td/utils/Slice.h"
@@ -225,7 +226,7 @@ std::pair<int64, string> DhHandshake::gen_key() {
 int64 DhHandshake::calc_key_id(Slice auth_key) {
   UInt<160> auth_key_sha1;
   sha1(auth_key, auth_key_sha1.raw);
-  return as<int64>(auth_key_sha1.raw + 12);
+  return le_load_int64(auth_key_sha1.raw + 12);
 }
 
 }  // namespace mtproto
diff --git td/mtproto/Handshake.cpp td/mtproto/Handshake.cpp
index 1478e3c..aa89270 100644
--- td/mtproto/Handshake.cpp
+++ td/mtproto/Handshake.cpp
@@ -13,6 +13,7 @@
 #include "td/mtproto/utils.h"
 
 #include "td/utils/as.h"
+#include "td/utils/endian_load.h"
 #include "td/utils/common.h"
 #include "td/utils/crypto.h"
 #include "td/utils/format.h"
@@ -24,6 +25,7 @@
 #include "td/utils/tl_parsers.h"
 
 #include <algorithm>
+#include <cstdio>
 
 namespace td {
 namespace mtproto {
@@ -248,7 +250,7 @@ Status AuthKeyHandshake::on_server_dh_params(Slice message, Callback *connection
   }
   auth_key_.set_created_at(dh_inner_data.server_time_);
 
-  server_salt_ = as<int64>(new_nonce_.raw) ^ as<int64>(server_nonce_.raw);
+  server_salt_ = le_load_int64(new_nonce_.raw) ^ le_load_int64(server_nonce_.raw);
 
   state_ = State::DHGenResponse;
   return Status::OK();
diff --git td/mtproto/RSA.cpp td/mtproto/RSA.cpp
index c5e54e2..7e3d32f 100644
--- td/mtproto/RSA.cpp
+++ td/mtproto/RSA.cpp
@@ -9,6 +9,7 @@
 #include "td/mtproto/mtproto_api.h"
 
 #include "td/utils/as.h"
+#include "td/utils/endian_load.h"
 #include "td/utils/common.h"
 #include "td/utils/crypto.h"
 #include "td/utils/misc.h"
@@ -119,7 +120,7 @@ int64 RSA::get_fingerprint() const {
   CHECK(size == tmp.size());
   unsigned char key_sha1[20];
   sha1(Slice(tmp.data(), tmp.size()), key_sha1);
-  return as<int64>(key_sha1 + 12);
+  return le_load_int64(key_sha1 + 12);
 }
 
 size_t RSA::size() const {
diff --git td/mtproto/SessionConnection.cpp td/mtproto/SessionConnection.cpp
index 05b1556..cf6b917 100644
--- td/mtproto/SessionConnection.cpp
+++ td/mtproto/SessionConnection.cpp
@@ -17,6 +17,7 @@
 
 #include "td/utils/algorithm.h"
 #include "td/utils/as.h"
+#include "td/utils/endian_load.h"
 #include "td/utils/common.h"
 #include "td/utils/format.h"
 #include "td/utils/Gzip.h"
@@ -506,7 +507,7 @@ Status SessionConnection::on_slice_packet(const MsgInfo &info, Slice packet) {
     return Status::Error(PSLICE() << "Receive packet of size " << packet.size());
   }
 
-  int32 constructor_id = as<int32>(packet.begin());
+  int32 constructor_id = le_load_int32(packet.begin());
   if (constructor_id == mtproto_api::msg_container::ID) {
     return on_packet_container(info, packet.substr(4));
   }
diff --git td/mtproto/TcpTransport.cpp td/mtproto/TcpTransport.cpp
index 2d1b651..7422e66 100644
--- td/mtproto/TcpTransport.cpp
+++ td/mtproto/TcpTransport.cpp
@@ -7,6 +7,7 @@
 #include "td/mtproto/TcpTransport.h"
 
 #include "td/utils/as.h"
+#include "td/utils/bits.h"
 #include "td/utils/common.h"
 #include "td/utils/Random.h"
 #include "td/utils/Slice.h"
@@ -17,6 +18,27 @@ namespace td {
 namespace mtproto {
 namespace tcp {
 
+// TDLib's TCP transport framing (length prefix, obfuscation header fields) is
+// little-endian on the wire. On big-endian PPC these helpers byte-swap; on
+// little-endian hosts they are identity.
+namespace {
+#if defined(__BIG_ENDIAN__) || defined(__ppc__) || defined(__powerpc__) || defined(__POWERPC__)
+inline uint32 wire_le32(uint32 x) {
+  return bswap32(x);
+}
+inline uint16 wire_le16(uint16 x) {
+  return static_cast<uint16>((x >> 8) | (x << 8));
+}
+#else
+inline uint32 wire_le32(uint32 x) {
+  return x;
+}
+inline uint16 wire_le16(uint16 x) {
+  return x;
+}
+#endif
+}  // namespace
+
 size_t IntermediateTransport::read_from_stream(ChainBufferReader *stream, BufferSlice *message, uint32 *quick_ack) {
   CHECK(message);
   size_t stream_size = stream->size();
@@ -27,6 +49,7 @@ size_t IntermediateTransport::read_from_stream(ChainBufferReader *stream, Buffer
   uint32 data_size;
   auto it = stream->clone();
   it.advance(header_size, MutableSlice(reinterpret_cast<uint8 *>(&data_size), sizeof(data_size)));
+  data_size = wire_le32(data_size);
   if (data_size & (1u << 31)) {
     if (quick_ack) {
       *quick_ack = data_size;
@@ -69,7 +92,7 @@ void IntermediateTransport::write_prepare_inplace(BufferWriter *message, bool qu
     message->confirm_append(append.size());
   }
 
-  as<uint32>(message->as_mutable_slice().begin()) = static_cast<uint32>(size + append_size);
+  as<uint32>(message->as_mutable_slice().begin()) = wire_le32(static_cast<uint32>(size + append_size));
 }
 
 void IntermediateTransport::init_output_stream(ChainBufferWriter *stream) {
@@ -95,12 +118,12 @@ void ObfuscatedTransport::init(ChainBufferReader *input, ChainBufferWriter *outp
     if (as<uint8>(header.data()) == 0xef) {
       continue;
     }
-    uint32 first_int = as<uint32>(header.data());
+    uint32 first_int = wire_le32(as<uint32>(header.data()));
     if (first_int == 0x44414548 || first_int == 0x54534f50 || first_int == 0x20544547 || first_int == 0x4954504f ||
         first_int == 0xdddddddd || first_int == 0xeeeeeeee || first_int == 0x02010316) {
       continue;
     }
-    uint32 second_int = as<uint32>(header.data() + sizeof(uint32));
+    uint32 second_int = wire_le32(as<uint32>(header.data() + sizeof(uint32)));
     if (second_int == 0) {
       continue;
     }
@@ -108,7 +131,7 @@ void ObfuscatedTransport::init(ChainBufferReader *input, ChainBufferWriter *outp
   }
   as<uint32>(header_slice.begin() + 56) = impl_.with_padding() ? 0xdddddddd : 0xeeeeeeee;
   if (dc_id_ != 0) {
-    as<int16>(header_slice.begin() + 60) = dc_id_;
+    as<int16>(header_slice.begin() + 60) = static_cast<int16>(wire_le16(static_cast<uint16>(dc_id_)));
   }
 
   string rheader = header;
diff --git td/mtproto/Transport.cpp td/mtproto/Transport.cpp
index 1a98182..64212f0 100644
--- td/mtproto/Transport.cpp
+++ td/mtproto/Transport.cpp
@@ -11,6 +11,7 @@
 #include "td/mtproto/MessageId.h"
 
 #include "td/utils/as.h"
+#include "td/utils/endian_load.h"
 #include "td/utils/crypto.h"
 #include "td/utils/format.h"
 #include "td/utils/logging.h"
@@ -224,7 +225,7 @@ Status Transport::read_crypto_impl(int X, MutableSlice message, const AuthKey &a
   auto to_decrypt = MutableSlice(header->encrypt_begin(), message.uend());
   to_decrypt.remove_suffix(to_decrypt.size() & 15);
 
-  if (header->auth_key_id != auth_key.id()) {
+  if (le_swap64(header->auth_key_id) != auth_key.id()) {
     return Status::Error(PSLICE() << "Invalid MTProto message: auth_key_id mismatch [found = "
                                   << format::as_hex(header->auth_key_id)
                                   << "] [expected = " << format::as_hex(auth_key.id()) << "]");
@@ -247,12 +248,12 @@ Status Transport::read_crypto_impl(int X, MutableSlice message, const AuthKey &a
   //FIXME: rewrite without reinterpret cast
   auto *prefix = reinterpret_cast<PrefixT *>(header->data);
   *prefix_ptr = prefix;
-  size_t data_size = prefix->message_data_length + sizeof(PrefixT);
+  size_t data_size = le_swap32(prefix->message_data_length) + sizeof(PrefixT);
   bool is_length_bad = false;
   UInt128 real_message_key;
 
   if (packet_info->version == 1) {
-    is_length_bad |= packet_info->check_mod4 && prefix->message_data_length % 4 != 0;
+    is_length_bad |= packet_info->check_mod4 && le_swap32(prefix->message_data_length) % 4 != 0;
     auto expected_size = calc_crypto_size<HeaderT>(data_size);
     is_length_bad |= expected_size != message.size();
     auto check_size = data_size * (1 - is_length_bad) + tail_size * is_length_bad;
@@ -272,26 +273,26 @@ Status Transport::read_crypto_impl(int X, MutableSlice message, const AuthKey &a
   }
 
   if (packet_info->version == 2) {
-    if (packet_info->check_mod4 && prefix->message_data_length % 4 != 0) {
+    if (packet_info->check_mod4 && le_swap32(prefix->message_data_length) % 4 != 0) {
       return Status::Error(PSLICE() << "Invalid MTProto message: invalid length (not divisible by four)"
                                     << tag("total_size", message.size())
-                                    << tag("message_data_length", prefix->message_data_length));
+                                    << tag("message_data_length", le_swap32(prefix->message_data_length)));
     }
-    if (tail_size - sizeof(PrefixT) < prefix->message_data_length) {
+    if (tail_size - sizeof(PrefixT) < le_swap32(prefix->message_data_length)) {
       return Status::Error(PSLICE() << "Invalid MTProto message: invalid length (message_data_length is too big)"
                                     << tag("total_size", message.size())
-                                    << tag("message_data_length", prefix->message_data_length));
+                                    << tag("message_data_length", le_swap32(prefix->message_data_length)));
     }
     size_t pad_size = tail_size - data_size;
     if (pad_size < 12 || pad_size > 1024) {
       return Status::Error(PSLICE() << "Invalid MTProto message: invalid length (invalid padding length)"
                                     << tag("padding_size", pad_size) << tag("total_size", message.size())
-                                    << tag("message_data_length", prefix->message_data_length));
+                                    << tag("message_data_length", le_swap32(prefix->message_data_length)));
     }
   } else {
     if (is_length_bad) {
       return Status::Error(PSLICE() << "Invalid MTProto message: invalid length " << tag("total_size", message.size())
-                                    << tag("message_data_length", prefix->message_data_length));
+                                    << tag("message_data_length", le_swap32(prefix->message_data_length)));
     }
   }
 
@@ -308,10 +309,10 @@ Status Transport::read_crypto(MutableSlice message, const AuthKey &auth_key, Pac
   CHECK(prefix != nullptr);
   CHECK(packet_info != nullptr);
   packet_info->type = PacketInfo::Common;
-  packet_info->salt = header->salt;
-  packet_info->session_id = header->session_id;
-  packet_info->message_id = MessageId(prefix->msg_id);
-  packet_info->seq_no = prefix->seq_no;
+  packet_info->salt = le_swap64(header->salt);
+  packet_info->session_id = le_swap64(header->session_id);
+  packet_info->message_id = MessageId(le_swap64(prefix->msg_id));
+  packet_info->seq_no = le_swap32(prefix->seq_no);
   return Status::OK();
 }
 Status Transport::read_e2e_crypto(MutableSlice message, const AuthKey &auth_key, PacketInfo *packet_info,
@@ -378,9 +379,9 @@ BufferWriter Transport::write_crypto(const Storer &storer, const AuthKey &auth_k
 
   //FIXME: rewrite without reinterpret cast
   auto &header = *reinterpret_cast<CryptoHeader *>(packet.as_mutable_slice().begin());
-  header.auth_key_id = auth_key.id();
-  header.salt = packet_info->salt;
-  header.session_id = packet_info->session_id;
+  header.auth_key_id = le_swap64(auth_key.id());
+  header.salt = le_swap64(packet_info->salt);
+  header.session_id = le_swap64(packet_info->session_id);
 
   write_crypto_impl(0, storer, auth_key, packet_info, &header, data_size, padded_size);
 
@@ -400,7 +401,7 @@ BufferWriter Transport::write_e2e_crypto(const Storer &storer, const AuthKey &au
 
   //FIXME: rewrite without reinterpret cast
   auto &header = *reinterpret_cast<EndToEndHeader *>(packet.as_mutable_slice().begin());
-  header.auth_key_id = auth_key.id();
+  header.auth_key_id = le_swap64(auth_key.id());
 
   write_crypto_impl(packet_info->is_creator || packet_info->version == 1 ? 0 : 8, storer, auth_key, packet_info,
                     &header, data_size, padded_size);
@@ -422,7 +423,7 @@ Result<Transport::ReadResult> Transport::read(MutableSlice message, const AuthKe
                                     << "]");
     }
 
-    int32 code = as<int32>(message.begin());
+    int32 code = le_load_int32(message.begin());
     if (code == 0) {
       return ReadResult::make_nop();
     } else if (code == -1 && message.size() >= 8) {
diff --git td/telegram/Td.cpp td/telegram/Td.cpp
index a313ce6..3edc385 100644
--- td/telegram/Td.cpp
+++ td/telegram/Td.cpp
@@ -427,10 +427,15 @@ void Td::on_result(NetQueryPtr query) {
 void Td::start_up() {
   uint64 check_endianness = 0x0706050403020100;
   auto check_endianness_raw = reinterpret_cast<const unsigned char *>(&check_endianness);
+  bool little_endian = true;
   for (unsigned char c = 0; c < 8; c++) {
     auto symbol = check_endianness_raw[static_cast<size_t>(c)];
-    LOG_IF(FATAL, symbol != c) << "TDLib requires little-endian platform";
+    if (symbol != c) {
+      little_endian = false;
+      break;
+    }
   }
+  LOG_IF(WARNING, !little_endian) << "Running TDLib on a big-endian platform; PPC compatibility mode enabled";
 
   requests_ = make_unique<Requests>(this);
 
diff --git tdtl/td/tl/tl_simple_parser.h tdtl/td/tl/tl_simple_parser.h
index d3c8edd..941f984 100644
--- tdtl/td/tl/tl_simple_parser.h
+++ tdtl/td/tl/tl_simple_parser.h
@@ -60,17 +60,28 @@ class tl_simple_parser {
 
   std::int32_t fetch_int() {
     check_len(sizeof(std::int32_t));
-    std::int32_t result = *reinterpret_cast<const std::int32_t *>(data);
+    const unsigned char *p = reinterpret_cast<const unsigned char *>(data);
+    std::uint32_t raw = static_cast<std::uint32_t>(p[0]) |
+                        (static_cast<std::uint32_t>(p[1]) << 8) |
+                        (static_cast<std::uint32_t>(p[2]) << 16) |
+                        (static_cast<std::uint32_t>(p[3]) << 24);
     data += sizeof(std::int32_t);
-    return result;
+    return static_cast<std::int32_t>(raw);
   }
 
   std::int64_t fetch_long() {
     check_len(sizeof(std::int64_t));
-    std::int64_t result;
-    std::memcpy(&result, data, sizeof(std::int64_t));
+    const unsigned char *p = reinterpret_cast<const unsigned char *>(data);
+    std::uint64_t raw = static_cast<std::uint64_t>(p[0]) |
+                        (static_cast<std::uint64_t>(p[1]) << 8) |
+                        (static_cast<std::uint64_t>(p[2]) << 16) |
+                        (static_cast<std::uint64_t>(p[3]) << 24) |
+                        (static_cast<std::uint64_t>(p[4]) << 32) |
+                        (static_cast<std::uint64_t>(p[5]) << 40) |
+                        (static_cast<std::uint64_t>(p[6]) << 48) |
+                        (static_cast<std::uint64_t>(p[7]) << 56);
     data += sizeof(std::int64_t);
-    return result;
+    return static_cast<std::int64_t>(raw);
   }
 
   std::string fetch_string() {
diff --git tdutils/td/utils/StringBuilder.cpp tdutils/td/utils/StringBuilder.cpp
index aa39c62..c9e3c44 100644
--- tdutils/td/utils/StringBuilder.cpp
+++ tdutils/td/utils/StringBuilder.cpp
@@ -9,6 +9,7 @@
 #include "td/utils/misc.h"
 #include "td/utils/port/thread_local.h"
 
+#include <cmath>
 #include <cstdio>
 #include <cstring>
 #include <limits>
@@ -192,28 +193,31 @@ StringBuilder &StringBuilder::operator<<(long long unsigned int x) {
 }
 
 StringBuilder &StringBuilder::operator<<(FixedDouble x) {
-  if (unlikely(!reserve(std::numeric_limits<double>::max_exponent10 + x.precision + 4))) {
-    return on_error();
+  // NB: the previous implementation used a std::stringstream and reserved
+  // max_exponent10 + precision + 4 bytes; when that large reservation could not
+  // be satisfied it emitted an EMPTY string, producing invalid JSON for some
+  // doubles (observed on big-endian PPC with out-of-range values). Format with
+  // snprintf and reserve exactly what is needed. Non-finite values have no JSON
+  // representation, so emit 0 to keep output valid.
+  if (unlikely(!std::isfinite(x.d))) {
+    if (unlikely(!reserve(1))) {
+      return on_error();
+    }
+    *current_ptr_++ = '0';
+    return *this;
   }
-
-  static TD_THREAD_LOCAL std::stringstream *ss;
-  if (init_thread_local<std::stringstream>(ss)) {
-    auto previous_locale = ss->imbue(std::locale::classic());
-    ss->setf(std::ios_base::fixed, std::ios_base::floatfield);
-  } else {
-    ss->str(std::string());
-    ss->clear();
+  int len = std::snprintf(nullptr, 0, "%.*f", x.precision, x.d);
+  if (unlikely(len <= 0)) {
+    if (unlikely(!reserve(1))) {
+      return on_error();
+    }
+    *current_ptr_++ = '0';
+    return *this;
   }
-  ss->precision(x.precision);
-  *ss << x.d;
-
-  auto len = narrow_cast<int>(static_cast<std::streamoff>(ss->tellp()));
-  auto left = end_ptr_ + RESERVED_SIZE - current_ptr_;
-  if (unlikely(len >= left)) {
-    error_flag_ = true;
-    len = left ? narrow_cast<int>(left - 1) : 0;
+  if (unlikely(!reserve(static_cast<size_t>(len) + 1))) {
+    return on_error();
   }
-  ss->read(current_ptr_, len);
+  std::snprintf(current_ptr_, static_cast<size_t>(len) + 1, "%.*f", x.precision, x.d);
   current_ptr_ += len;
   return *this;
 }
diff --git tdutils/td/utils/bits.h tdutils/td/utils/bits.h
index 2580543..1e5aa80 100644
--- tdutils/td/utils/bits.h
+++ tdutils/td/utils/bits.h
@@ -48,12 +48,18 @@ inline uint64 lower_bit64(uint64 x) {
 }
 
 inline uint64 host_to_big_endian64(uint64 x) {
-  // NB: works only for little-endian systems
+#if defined(__BIG_ENDIAN__) || defined(__ppc__) || defined(__powerpc__) || defined(__POWERPC__)
+  return x;
+#else
   return bswap64(x);
+#endif
 }
 inline uint64 big_endian_to_host64(uint64 x) {
-  // NB: works only for little-endian systems
+#if defined(__BIG_ENDIAN__) || defined(__ppc__) || defined(__powerpc__) || defined(__POWERPC__)
+  return x;
+#else
   return bswap64(x);
+#endif
 }
 
 //TODO: optimize
diff --git tdutils/td/utils/crypto.cpp tdutils/td/utils/crypto.cpp
index dee0e25..4492f15 100644
--- tdutils/td/utils/crypto.cpp
+++ tdutils/td/utils/crypto.cpp
@@ -6,6 +6,8 @@
 //
 #include "td/utils/crypto.h"
 
+#include <type_traits>
+
 #include "td/utils/as.h"
 #include "td/utils/BigNum.h"
 #include "td/utils/bits.h"
@@ -156,16 +158,18 @@ void init_crypto() {
 
 template <class FromT>
 static string as_big_endian_string(const FromT &from) {
+  // Endian-independent: emit the minimal big-endian byte representation. The
+  // previous implementation relied on little-endian memory layout via as<>.
   char res[sizeof(FromT)];
-  as<FromT>(res) = from;
-
-  size_t i = sizeof(FromT);
-  while (i && res[i - 1] == 0) {
-    i--;
+  typename std::make_unsigned<FromT>::type v = static_cast<typename std::make_unsigned<FromT>::type>(from);
+  for (size_t j = 0; j < sizeof(FromT); j++) {
+    res[sizeof(FromT) - 1 - j] = static_cast<char>((v >> (8 * j)) & 0xff);
   }
-
-  std::reverse(res, res + i);
-  return string(res, res + i);
+  size_t i = 0;
+  while (i < sizeof(FromT) && res[i] == 0) {
+    i++;
+  }
+  return string(res + i, res + sizeof(FromT));
 }
 
 static int pq_factorize_big(Slice pq_str, string *p_str, string *q_str) {
diff --git tdutils/td/utils/endian_load.h tdutils/td/utils/endian_load.h
new file mode 100644
index 0000000..23a1d3e
--- /dev/null
+++ tdutils/td/utils/endian_load.h
@@ -0,0 +1,44 @@
+//
+// Endian-independent little-endian integer loads from a byte buffer.
+//
+// MTProto/TL stores integers little-endian on the wire and in several places
+// reads them back with a native `as<intN>` cast. That cast is correct only on
+// little-endian hosts; on big-endian PPC it byte-swaps. These helpers always
+// read little-endian, so they match `as<intN>` on little-endian hosts and stay
+// correct on big-endian ones.
+//
+#pragma once
+
+#include "td/utils/common.h"
+#include "td/utils/bits.h"
+
+namespace td {
+
+inline int32 le_load_int32(const void *ptr) {
+  const unsigned char *p = static_cast<const unsigned char *>(ptr);
+  uint32 res = static_cast<uint32>(p[0]) | (static_cast<uint32>(p[1]) << 8) |
+               (static_cast<uint32>(p[2]) << 16) | (static_cast<uint32>(p[3]) << 24);
+  return static_cast<int32>(res);
+}
+
+inline int64 le_load_int64(const void *ptr) {
+  const unsigned char *p = static_cast<const unsigned char *>(ptr);
+  uint64 res = 0;
+  for (int i = 0; i < 8; i++) {
+    res |= static_cast<uint64>(p[i]) << (8 * i);
+  }
+  return static_cast<int64>(res);
+}
+
+// Swap between host order and little-endian wire order for integers that are
+// read/written through raw struct overlays (MTProto CryptoHeader/CryptoPrefix).
+// Identity on little-endian hosts; byte-swap on big-endian (PPC).
+#if defined(__BIG_ENDIAN__) || defined(__ppc__) || defined(__powerpc__) || defined(__POWERPC__)
+inline uint32 le_swap32(uint32 x) { return bswap32(x); }
+inline uint64 le_swap64(uint64 x) { return bswap64(x); }
+#else
+inline uint32 le_swap32(uint32 x) { return x; }
+inline uint64 le_swap64(uint64 x) { return x; }
+#endif
+
+}  // namespace td
diff --git tdutils/td/utils/port/path.cpp tdutils/td/utils/port/path.cpp
index 4d94ac5..5b7b205 100644
--- tdutils/td/utils/port/path.cpp
+++ tdutils/td/utils/port/path.cpp
@@ -344,6 +344,10 @@ Result<bool> walk_path_dir(string &path, DIR *subdir, const WalkFunction &func)
 }
 
 Result<bool> walk_path_dir(string &path, FileFd fd, const WalkFunction &func) {
+#if defined(__APPLE__)
+  (void)fd;
+  return walk_path_dir(path, func);
+#else
   auto native_fd = fd.move_as_native_fd();
   auto *subdir = fdopendir(native_fd.fd());
   if (subdir == nullptr) {
@@ -351,6 +355,7 @@ Result<bool> walk_path_dir(string &path, FileFd fd, const WalkFunction &func) {
   }
   native_fd.release();
   return walk_path_dir(path, subdir, func);
+#endif
 }
 
 Result<bool> walk_path_dir(string &path, const WalkFunction &func) {
diff --git tdutils/td/utils/tl_parsers.h tdutils/td/utils/tl_parsers.h
index f08009b..1d466d5 100644
--- tdutils/td/utils/tl_parsers.h
+++ tdutils/td/utils/tl_parsers.h
@@ -73,14 +73,16 @@ class TlParser {
   }
 
   int32 prefetch_int_unsafe() const {
-    int32 result;
-    std::memcpy(&result, data, sizeof(int32));
-    return result;
+    const unsigned char *p = data;
+    uint32 raw = static_cast<uint32>(p[0]) |
+                 (static_cast<uint32>(p[1]) << 8) |
+                 (static_cast<uint32>(p[2]) << 16) |
+                 (static_cast<uint32>(p[3]) << 24);
+    return static_cast<int32>(raw);
   }
 
   int32 fetch_int_unsafe() {
-    int32 result;
-    std::memcpy(&result, data, sizeof(int32));
+    int32 result = prefetch_int_unsafe();
     data += sizeof(int32);
     return result;
   }
@@ -91,10 +93,17 @@ class TlParser {
   }
 
   int64 fetch_long_unsafe() {
-    int64 result;
-    std::memcpy(&result, data, sizeof(int64));
+    const unsigned char *p = data;
+    uint64 raw = static_cast<uint64>(p[0]) |
+                 (static_cast<uint64>(p[1]) << 8) |
+                 (static_cast<uint64>(p[2]) << 16) |
+                 (static_cast<uint64>(p[3]) << 24) |
+                 (static_cast<uint64>(p[4]) << 32) |
+                 (static_cast<uint64>(p[5]) << 40) |
+                 (static_cast<uint64>(p[6]) << 48) |
+                 (static_cast<uint64>(p[7]) << 56);
     data += sizeof(int64);
-    return result;
+    return static_cast<int64>(raw);
   }
 
   int64 fetch_long() {
@@ -103,9 +112,9 @@ class TlParser {
   }
 
   double fetch_double_unsafe() {
+    uint64 raw = static_cast<uint64>(fetch_long_unsafe());
     double result;
-    std::memcpy(&result, data, sizeof(double));
-    data += sizeof(double);
+    std::memcpy(&result, &raw, sizeof(double));
     return result;
   }
 
diff --git tdutils/td/utils/tl_storers.h tdutils/td/utils/tl_storers.h
index 0ddecdd..5edd84e 100644
--- tdutils/td/utils/tl_storers.h
+++ tdutils/td/utils/tl_storers.h
@@ -12,6 +12,7 @@
 #include "td/utils/StorerBase.h"
 
 #include <cstring>
+#include <type_traits>
 
 namespace td {
 
@@ -27,8 +28,32 @@ class TlStorerUnsafe {
 
   template <class T>
   void store_binary(const T &x) {
+#if defined(__BIG_ENDIAN__) || defined(__ppc__) || defined(__powerpc__) || defined(__POWERPC__)
+    // TDLib's wire/storage format is little-endian. On big-endian PPC, emit the
+    // bytes of arithmetic values in little-endian order. Aggregate raw types such
+    // as UInt128/UInt256 are byte arrays and must be copied verbatim.
+    if constexpr (std::is_integral<T>::value) {
+      typename std::make_unsigned<T>::type u = static_cast<typename std::make_unsigned<T>::type>(x);
+      for (size_t i = 0; i < sizeof(T); i++) {
+        buf_[i] = static_cast<unsigned char>((u >> (8 * i)) & 0xff);
+      }
+      buf_ += sizeof(T);
+    } else if constexpr (std::is_floating_point<T>::value) {
+      static_assert(sizeof(T) == 4 || sizeof(T) == 8, "unexpected floating-point size");
+      typename std::conditional<sizeof(T) == 8, uint64, uint32>::type bits = 0;
+      std::memcpy(&bits, &x, sizeof(T));
+      for (size_t i = 0; i < sizeof(T); i++) {
+        buf_[i] = static_cast<unsigned char>((bits >> (8 * i)) & 0xff);
+      }
+      buf_ += sizeof(T);
+    } else {
+      std::memcpy(buf_, &x, sizeof(T));
+      buf_ += sizeof(T);
+    }
+#else
     std::memcpy(buf_, &x, sizeof(T));
     buf_ += sizeof(T);
+#endif
   }
 
   void store_int(int32 x) {
