@neuraiproject/neurai-depin-msg
v2.1.3
Published
Build and serialize DePIN encrypted messages for Neurai blockchain
Maintainers
Readme
@neuraiproject/neurai-depin-msg
Build, encrypt, sign, and serialize DePIN messages compatible with Neurai Core.
This library produces the hex payload for the Neurai RPC method depinsubmitmsg.
It runs fully client-side (browser / local scripts) and does not require a backend.
What you get
Given:
- A plaintext message
- Your sender address + private key
- The compressed public keys of all recipients
It returns:
hex: a serializedCDepinMessageready to submit viadepinsubmitmsgmessageHash: the message hash as typically displayed by Neurai Core
Install
npm install @neuraiproject/neurai-depin-msgUsage (Browser)
Include the bundled build (IIFE). It exposes a global neuraiDepinMsg object.
<script src="./dist/neurai-depin-msg.min.js"></script>
<script>
async function build() {
const res = await neuraiDepinMsg.buildDepinMessage({
token: 'MYTOKEN',
senderAddress: 'NxxxxYourAddress',
senderPubKey: '02abcdef... (66 hex chars)',
privateKey: 'L... (WIF) OR 64-hex private key',
timestamp: Math.floor(Date.now() / 1000),
message: 'Hello from the browser!',
recipientPubKeys: [
'02deadbeef... (recipient 1 compressed pubkey)',
'03cafebabe... (recipient 2 compressed pubkey)'
],
messageType: 'group'
});
console.log('depinsubmitmsg hex:', res.hex);
console.log('messageHash:', res.messageHash);
}
build();
</script>Submit it to your node:
neurai-cli depinsubmitmsg "<HEX_FROM_LIBRARY>"Usage (Node.js)
The published build is browser-style (IIFE) and attaches to globalThis.neuraiDepinMsg.
Node must have WebCrypto available.
// Node 18+ usually has WebCrypto; if not, enable it explicitly:
import { webcrypto } from 'node:crypto';
if (!globalThis.crypto?.subtle) globalThis.crypto = webcrypto;
// This executes the IIFE bundle and sets globalThis.neuraiDepinMsg
import '@neuraiproject/neurai-depin-msg/dist/neurai-depin-msg.js';
const { buildDepinMessage } = globalThis.neuraiDepinMsg;
const res = await buildDepinMessage({
token: 'MYTOKEN',
senderAddress: 'NxxxxYourAddress',
senderPubKey: '02abcdef...(66 hex chars)',
privateKey: 'L... (WIF) OR 64-hex private key',
timestamp: Math.floor(Date.now() / 1000),
message: 'Hello from Node!',
recipientPubKeys: ['02deadbeef...'],
messageType: 'private'
});
console.log(res.hex);API
neuraiDepinMsg.buildDepinMessage(params)
The browser/IIFE global is neuraiDepinMsg.
Builds a complete serialized CDepinMessage (as hex) suitable for depinsubmitmsg.
Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| token | string | yes | Token/asset name for the DePIN channel |
| senderAddress | string | yes | Sender Neurai address (string as used by Core RPC) |
| senderPubKey | string | yes | Sender compressed public key as hex (66 chars / 33 bytes) |
| privateKey | string | yes | Sender private key as WIF or 64-hex (32 bytes) |
| timestamp | number | yes | Unix time (seconds) |
| message | string | yes | Plaintext message (UTF-8) |
| recipientPubKeys | string[] | yes | Recipient compressed pubkeys as hex (66 chars each). The sender pubkey is automatically added if missing so you can decrypt your own messages. |
| messageType | "private" \| "group" | yes | Message type: "private" allows only one recipient plus the sender, "group" allows multiple recipients. |
neuraiDepinMsg.decryptDepinReceiveEncryptedPayload(encryptedPayloadHex, recipientPrivateKey)
Decrypts the encrypted_payload_hex returned by Neurai Core RPC depinreceivemsg.
encryptedPayloadHex: hex string for the serializedCECIESEncryptedMessage.recipientPrivateKey: recipient private key as WIF or 64-hex.
Returns string | null (it returns null if the message is not for that key or authentication fails).
Notes:
- Public keys must be compressed (start with
02or03). - This library does not discover recipients for a token; it only encrypts for the pubkeys you provide.
Returns
| Property | Type | Description |
|----------|------|-------------|
| hex | string | Hex-encoded serialized CDepinMessage |
| messageHash | string | Double-SHA256 signing hash displayed in the typical Core-style (byte-reversed) |
| messageHashBytes | string | Raw 32-byte digest as hex (not reversed) |
| encryptedSize | number | Size of the serialized CECIESEncryptedMessage in bytes |
| recipientCount | number | Number of recipients (including sender if auto-added) |
| messageType | "private" \| "group" | The message type that was specified in the parameters. |
How it works (Core-compatible)
Encryption (Hybrid ECIES with AES-256-GCM)
This matches Neurai Core's CECIESEncryptedMessage format (v2.0+):
- Ephemeral keypair is generated per message.
- Message encryption:
- AES-256-GCM encrypts plaintext with a derived AES key (no padding).
- Payload is stored as
[Nonce(12) || ciphertext || AuthTag(16)].
- Per-recipient key wrapping:
- ECDH derives a shared secret from ephemeral privkey + recipient pubkey.
- A per-recipient
encKeyis derived and used to AES-256-GCM encrypt the 32-byte AES key. - Recipient package is
[Nonce(12) || encryptedAESKey(32) || AuthTag(16)](60 bytes).
Serialization
All fields are serialized using Bitcoin-style rules:
- CompactSize prefixes for vectors/strings
- Little-endian integers
Message structure:
[token (string)]
[senderAddress (string)]
[timestamp (int64)]
[messageType (uint8)] // 0x01 = private, 0x02 = group
[encryptedPayload (vector)]
[signature (vector)]Signing
The signature hash is:
doubleSHA256( serialize(token) || serialize(senderAddress) || int64(timestamp) || uint8(messageType) || vector(encryptedPayloadBytes) )
messageHash is the display-friendly byte-reversed form (similar to how Core prints uint256).
Demo
Open demo.html in a browser (a local server is recommended):
python3 -m http.server 8080
# Open http://localhost:8080/demo.htmlDevelopment
npm run build:dev # dist/neurai-depin-msg.js
npm run build # dist/neurai-depin-msg.min.jsLicense
MIT
