XChain Platform SDK — Messaging Reference
This document covers the SDK’s messaging module: ECIES, ECDH, and AES encryption for MESSAGE actions, public key lookup, and high-level send/receive with automatic encryption and decryption.
Overview
The SDK provides a messaging module for encrypted and plaintext communication between addresses:
sdk.messaging(MessagingUtils) — ECIES/ECDH/AES encryption, public key resolution, high-level send and receive.
Available on the SDK instance and as top-level convenience methods:
const sdk = new XChainSDK({
network: 'bitcoin-mainnet',
explorerUrl: 'localhost',
encoderUrl: 'localhost'
});
// Namespaced access
sdk.messaging.eciesEncrypt('Hello', recipientPubkey);
sdk.messaging.send(params, sdk);
// Convenience access
sdk.sendMessage(params);
sdk.getPublicKey(address);
sdk.getMessagesForAddress(address, opts);
Encryption Methods
| Method | Constant | Name | Key Exchange | Multi-Device | Best For |
|---|---|---|---|---|---|
| 1 | ECIES |
Address Communication | None (uses recipient pubkey) | Yes | General messaging (default) |
| 2 | ECDH |
Session Communication | Format 0/1 handshake | No (device-bound) | Long-running sessions |
| 3 | AES |
Shared Secret | Out-of-band | Depends on key sharing | Password-protected messages |
ECIES (Method 1) — Address Communication
ECIES encrypts directly to the recipient’s public key. No prior key exchange is needed. Any device with the recipient’s private key can decrypt.
Encrypt
const result = sdk.messaging.eciesEncrypt(plaintext, recipientPubkey);
// result.ciphertext — hex-encoded ciphertext
Parameters:
plaintext(string) — Message to encryptrecipientPubkey(string|Buffer) — Recipient’s compressed public key (33 bytes hex)
The ciphertext contains: ephemeralPubkey(33) + iv(12) + authTag(16) + encryptedData
Decrypt
const result = sdk.messaging.eciesDecrypt(ciphertext, wif);
// result.plaintext — decrypted message string
Parameters:
ciphertext(string|Buffer) — Hex-encoded ciphertext fromeciesEncryptwif(string) — Recipient’s WIF private key
ECDH (Method 2) — Session Communication
ECDH requires a key exchange handshake. Both parties exchange public keys via format 0/1 MESSAGE actions, then derive a shared secret.
Generate Session Key
const result = sdk.messaging.generateSessionKey(wif);
// result.publicKey — hex-encoded compressed public key for key exchange
Derive Shared Secret
const result = sdk.messaging.deriveSharedSecret(wif, theirPublicKey);
// result.sharedSecret — hex-encoded 32-byte shared secret
Both parties derive the same shared secret from myPrivateKey + theirPublicKey.
Encrypt / Decrypt
const encrypted = sdk.messaging.sessionEncrypt(plaintext, sharedSecret);
// encrypted.ciphertext — hex-encoded ciphertext
const decrypted = sdk.messaging.sessionDecrypt(ciphertext, sharedSecret);
// decrypted.plaintext — original message
AES (Method 3) — Shared Secret Communication
AES uses a pre-shared key. If the key is not exactly 32 bytes, it is hashed with SHA-256 to derive the encryption key.
Encrypt / Decrypt
const encrypted = sdk.messaging.aesEncrypt(plaintext, sharedKey);
// encrypted.ciphertext — hex-encoded ciphertext
const decrypted = sdk.messaging.aesDecrypt(ciphertext, sharedKey);
// decrypted.plaintext — original message
Parameters:
sharedKey(string|Buffer) — Pre-shared key (hex string, Buffer, or passphrase)
Public Key Lookup
Look up the public key for any address that has sent at least one XChain transaction. The public key is extracted from the transaction’s scriptSig/witness data by the decoder and served via the explorer API.
// Via convenience method
const pubkey = await sdk.getPublicKey('1SomeAddress...');
// Via module directly
const pubkey = await sdk.messaging.getPublicKey(address, sdk.explorer);
Returns the hex-encoded compressed public key (66 characters), or null if not found.
High-Level Send
Send a message with automatic pubkey resolution, encryption, action creation, PSBT signing, and broadcasting.
const result = await sdk.sendMessage({
wif: senderWIF,
destination: recipientAddress,
coin: 'BTC', // BTC, LTC, or DOGE — destination address network
message: 'Hello!',
method: 1, // 1=ECIES (default), 2=ECDH, 3=AES, null=plaintext
sharedSecret: '...', // Required for method 2
sharedKey: '...', // Required for method 3
encoder: { pubkey: senderPubkey } // Encoder options
});
// result.txid — transaction ID
// result.actionString — the raw MESSAGE action string
Method Behavior
method |
Behavior |
|---|---|
1 (default) |
Looks up recipient pubkey via explorer, ECIES encrypts, creates format 2 MESSAGE |
2 |
Encrypts with provided sharedSecret (from prior ECDH key exchange), creates format 2 MESSAGE |
3 |
Encrypts with provided sharedKey, creates format 2 MESSAGE |
null |
No encryption, creates format 3 MESSAGE (plaintext) |
High-Level Receive / Read
Fetch and optionally decrypt messages for an address.
const messages = await sdk.getMessagesForAddress('1MyAddress...', {
wif: myWIF, // Optional: decrypt ECIES messages
type: 'received', // 'sent', 'received', or 'all' (default)
limit: 10,
page: 1,
sortorder: 'DESC'
});
Each message object:
| Field | Type | Description |
|---|---|---|
from |
string | Sender address |
to |
string | Recipient address |
text |
string|null | Decrypted/plaintext message, or null if not decryptable |
encrypted |
boolean | Whether the message was encrypted |
method |
number|null | Encryption method (1, 2, 3) or null for plaintext |
txid |
string | Transaction hash |
block |
number | Block height |
timestamp |
number | Block timestamp |
Auto-decryption only works for ECIES (method 1) when wif is provided. ECDH and AES messages require the application to supply the shared secret/key and decrypt manually using sessionDecrypt() or aesDecrypt().
Convenience Methods
| Method | Equivalent |
|---|---|
sdk.sendMessage(params) |
sdk.messaging.send(params, sdk) |
sdk.getPublicKey(address) |
sdk.messaging.getPublicKey(address, sdk.explorer) |
sdk.getMessagesForAddress(address, opts) |
sdk.messaging.getMessages(address, opts, sdk.explorer) |
Error Handling
The messaging module throws SDKMessagingError with the following codes:
| Code | When |
|---|---|
INVALID_MESSAGE |
Empty or non-string plaintext |
INVALID_PUBKEY |
Invalid or missing public key |
INVALID_WIF |
Invalid or network-mismatched WIF |
INVALID_CIPHERTEXT |
Ciphertext too short or malformed |
INVALID_KEY |
Missing encryption key |
INVALID_COIN |
Missing or invalid COIN value (must be BTC, LTC, or DOGE) |
INVALID_DESTINATION |
Missing destination address |
INVALID_METHOD |
Unknown encryption method |
PUBKEY_NOT_FOUND |
No public key found for recipient (ECIES send) |
DECRYPTION_FAILED |
AES-GCM decryption failure (wrong key or corrupted data) |
EXPLORER_REQUIRED |
Explorer not configured for pubkey lookup |
ENCODER_REQUIRED |
Encoder options missing for send |
SDK_REQUIRED |
SDK instance not provided to send() |
SHARED_SECRET_REQUIRED |
ECDH method used without shared secret |
SHARED_KEY_REQUIRED |
AES method used without shared key |
NETWORK_NOT_CONFIGURED |
Network not set in SDK options |
Copyright © 2025–2026 Dankest, LLC
Based on XChain Platform by Dankest, LLC – https://dankest.llc
Licensed under the GNU Affero General Public License v3.0 (AGPL-3.0-or-later) with a commercial license available for proprietary use.
You may use, modify, and distribute this material under the terms of the License. See LICENSE and NOTICE for full terms. See the licensing overview.