static void mul(const uint8_t* a, const uint8_t* b, uint8_t* res) {
    uint64_t a0, b0;
    uint64_t hi, lo;

    a0 = SWAP64LE(((uint64_t*) a)[0]);
    b0 = SWAP64LE(((uint64_t*) b)[0]);
    lo = mul128(a0, b0, &hi);
    ((uint64_t*) res)[0] = SWAP64LE(hi);
    ((uint64_t*) res)[1] = SWAP64LE(lo);
}
bool tx_extra_message::decrypt(size_t index, const Crypto::PublicKey &txkey, const Crypto::SecretKey *recepient_secret_key, std::string &message) const {
  size_t mlen = data.size();
  if (mlen < TX_EXTRA_MESSAGE_CHECKSUM_SIZE) {
    return false;
  }
  const char *buf;
  std::unique_ptr<char[]> ptr;
  if (recepient_secret_key != nullptr) {
    ptr.reset(new char[mlen]);
    assert(ptr);
    message_key_data key_data;
    if (!generate_key_derivation(txkey, *recepient_secret_key, key_data.derivation)) {
      return false;
    }
    key_data.magic1 = 0x80;
    key_data.magic2 = 0;
    Hash h = cn_fast_hash(&key_data, sizeof(message_key_data));
    uint64_t nonce = SWAP64LE(index);
    chacha(10, data.data(), mlen, reinterpret_cast<uint8_t *>(&h), reinterpret_cast<uint8_t *>(&nonce), ptr.get());
    buf = ptr.get();
  } else {
    buf = data.data();
  }
  mlen -= TX_EXTRA_MESSAGE_CHECKSUM_SIZE;
  for (size_t i = 0; i < TX_EXTRA_MESSAGE_CHECKSUM_SIZE; i++) {
    if (buf[mlen + i] != 0) {
      return false;
    }
  }
  message.assign(buf, mlen);
  return true;
}
static void sum_half_blocks(uint8_t* a, const uint8_t* b) {
    uint64_t a0, a1, b0, b1;

    a0 = SWAP64LE(((uint64_t*) a)[0]);
    a1 = SWAP64LE(((uint64_t*) a)[1]);
    b0 = SWAP64LE(((uint64_t*) b)[0]);
    b1 = SWAP64LE(((uint64_t*) b)[1]);
    a0 += b0;
    a1 += b1;
    ((uint64_t*) a)[0] = SWAP64LE(a0);
    ((uint64_t*) a)[1] = SWAP64LE(a1);
}
bool tx_extra_message::encrypt(size_t index, const std::string &message, const AccountPublicAddress *recipient, const KeyPair &txkey) {
  size_t mlen = message.size();
  std::unique_ptr<char[]> buf(new char[mlen + TX_EXTRA_MESSAGE_CHECKSUM_SIZE]);
  memcpy(buf.get(), message.data(), mlen);
  memset(buf.get() + mlen, 0, TX_EXTRA_MESSAGE_CHECKSUM_SIZE);
  mlen += TX_EXTRA_MESSAGE_CHECKSUM_SIZE;
  if (recipient) {
    message_key_data key_data;
    if (!generate_key_derivation(recipient->spendPublicKey, txkey.secretKey, key_data.derivation)) {
      return false;
    }
    key_data.magic1 = 0x80;
    key_data.magic2 = 0;
    Hash h = cn_fast_hash(&key_data, sizeof(message_key_data));
    uint64_t nonce = SWAP64LE(index);
    chacha(10, buf.get(), mlen, reinterpret_cast<uint8_t *>(&h), reinterpret_cast<uint8_t *>(&nonce), buf.get());
  }
  data.assign(buf.get(), mlen);
  return true;
}