RippleMessengerClient
Features
- Accounts are generated locally — no phone number verification, no biometric identification required. "I am who I am" — no need to prove your identity to anyone. With proper usage, full anonymity toward everyone is possible; you can also choose to reveal your real identity to specific individuals in the physical world.
- All data is stored locally — including bulletins (announcements), private chat messages, group chat messages, files, and everything else. With proper usage, your data remains secure under your control. Instead of complaining about service providers losing or deleting your data, keep it safe yourself.
- Data exchange servers can be privately deployed. See the source code at RippleMessengerServer. Deployment is simple and low-cost. No need to worry about service downtime. Users with resources are encouraged to deploy public servers or contribute computing power.
- The Bulletin function can replicate features of Twitter, Weibo, blogs, forum posts, and similar platforms. Thanks to points 1, 2, and 3 above, your bulletin data truly follows you (remains under your control).
- Chat supports end-to-end encryption (256-bit AES). Only participants can read the content. Again, thanks to points 1, 2, and 3, chat history stays with you.
- Both bulletins and chats support file attachments (current max file size: 64 MB). Chat file transfers are also end-to-end encrypted.
- The client executable is only ~5 MB — small, open-source, green, and secure.
Welcome to star, fork, contribute code, recommend to others, or donate. Thank you!
Bulletin Function
Data format:
const BulletinSchema = {
"type": "object",
"required": ["ObjectType", "Sequence", "PreHash", "Content", "Timestamp", "PublicKey", "Signature"],
"maxProperties": 10,
"properties": {
"ObjectType": { "type": "number", "const": ObjectType.Bulletin },
"Sequence": { "type": "number" },
"PreHash": { "type": "string" },
"Content": { "type": "string" },
"Tag": {
"type": "array",
"minItems": 1,
"items": { "type": "string" }
},
"Quote": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": ["Address", "Sequence", "Hash"],
"properties": {
"Address": { "type": "string" },
"Sequence": { "type": "number" },
"Hash": { "type": "string" }
}
}
},
"File": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": ["Name", "Ext", "Size", "Hash"],
"properties": {
"Name": { "type": "string" },
"Ext": { "type": "string" },
"Size": { "type": "number" },
"Hash": { "type": "string" }
}
}
},
"Timestamp": { "type": "number" },
"PublicKey": { "type": "string" },
"Signature": { "type": "string" }
}
}
Field explanations:
-
Core fields (ObjectType, Sequence, PreHash, Timestamp, PublicKey, Signature):
- ObjectType: Indicates data type
- Sequence: Sequence number for this account (PublicKey) under this type (starts at 1, increments by 1) — forms a logical chain per account per type
-
PreHash: Hash of the previous item; first item uses fixed value
44F8764BCACFF5424D4044B784549A1B— combined with Sequence creates a tamper-resistant chain - Timestamp: Creation time (must be later than any referenced items)
- PublicKey: Publisher's account
- Signature: Cryptographic signature ensuring integrity, non-forgability, and non-repudiation
-
Content fields (Content, Tag, Quote, File):
- Content: Main text content (user-provided)
- Tag: Array of tags for future search/retrieval
- Quote: References to other bulletins (Address + Sequence + Hash) — enables cross-chain replies and interactions
- File: File metadata (Name, Ext, Size, Hash) — bulletin does not contain file data; only hash reference for separate file transfer
Minimum validation rules before any node/person stores a Bulletin:
- Verify signature → confirm integrity and publisher
- Check that the current last Sequence in this chain is Sequence - 1
- Verify hash of previous item (Sequence - 1) matches PreHash → allows appending to chain tail
Private Chat Function
End-to-end encrypted chat is implemented in two steps:
- Both parties securely negotiate a shared symmetric key (256-bit AES session key) using DH (Diffie-Hellman) algorithm
- Use the session key to encrypt/decrypt private messages
Step 1: DH Handshake (Session Key Negotiation) Format
const ECDHHandshakeSchema = {
"type": "object",
"required": ["ObjectType", "Partition", "Sequence", "Self", "Pair", "To", "Timestamp", "PublicKey", "Signature"],
"maxProperties": 9,
"properties": {
"ObjectType": { "type": "number", "const": ObjectType.ECDH },
"Partition": { "type": "number" },
"Sequence": { "type": "number" },
"Self": { "type": "string" },
"Pair": { "type": "string" },
"To": { "type": "string" },
"Timestamp": { "type": "number" },
"PublicKey": { "type": "string" },
"Signature": { "type": "string" }
}
}
- Partition: Fixed 90-day window (90 × 24 × 3600 seconds)
- Sequence: Sequence number within the session window (start time is fixed 2011-11-11 11:11:11 + per-pair offset to avoid congestion)
- Self / Pair: DH public keys of self and peer — allows computing the same shared secret
- To: Target account (PublicKey is self)
Step 2: Private Message Format
const PrivateMessageSchema = {
"type": "object",
"required": ["ObjectType", "Sequence", "PreHash", "Content", "To", "Timestamp", "PublicKey", "Signature"],
"maxProperties": 9,
"properties": {
"ObjectType": { "type": "number", "const": ObjectType.PrivateMessage },
"Sequence": { "type": "number" },
"PreHash": { "type": "string" },
"Confirm": {
"type": "object",
"required": ["Sequence", "Hash"],
"maxProperties": 2,
"properties": {
"Sequence": { "type": "number" },
"Hash": { "type": "string" }
}
},
"Content": { "type": "string" },
"To": { "type": "string" },
"Timestamp": { "type": "number" },
"PublicKey": { "type": "string" },
"Signature": { "type": "string" }
}
}
- Confirm: Acknowledgment of received message (Sequence + Hash from peer)
- Content: Plaintext before encryption / after decryption; during transmission it is AES-encrypted with session key. Can contain: text, bulletin reference, file reference
- To: Recipient account
Before storing, nodes must decrypt Content with the session key, then perform chain validation.
Group Chat Function
Built on the principles of private chat, group chat functionality is implemented in two steps:
- Create a group
- Group members send encrypted group messages using pairwise session keys (established via private chat DH handshakes).
Step 1: Group Creation Format
const GroupCreateSchema = {
"type": "object",
"required": ["ObjectType", "Hash", "Name", "Member", "Timestamp", "PublicKey", "Signature"],
"maxProperties": 7,
"properties": {
"ObjectType": { "type": "number", "const": ObjectType.GroupCreate },
"Hash": { "type": "string" },
"Name": { "type": "string" },
"Member": {
"type": "array",
"minItems": 2,
"maxItems": 16,
"items": { "type": "string" }
},
"Timestamp": { "type": "number" },
"PublicKey": { "type": "string" },
"Signature": { "type": "string" }
}
}
Field explanations:
- ObjectType, Timestamp, PublicKey, Signature are core/base fields (same roles as previously described; no further explanation here).
-
Hash, Name, Member are specific to group creation:
- Hash: Unique group identifier, computed as the hash of group name + member addresses + random value.
- Name: Group name. Since it is not encrypted, it is recommended to use desensitized/obscure wording that group members can understand but outsiders cannot easily guess.
- Member: Array of member public keys (minimum 2 members + the creator indicated by PublicKey, so at least 3 members in total).
Step 2: Group Message Format
const GroupMessageSchema = {
"type": "object",
"required": ["ObjectType", "GroupHash", "Sequence", "PreHash", "Content", "To", "Timestamp", "PublicKey", "Signature"],
"maxProperties": 10,
"properties": {
"ObjectType": { "type": "number", "const": ObjectType.GroupMessage },
"GroupHash": { "type": "string" },
"Sequence": { "type": "number" },
"PreHash": { "type": "string" },
"Confirm": {
"type": "object",
"required": ["Address", "Sequence", "Hash"],
"maxProperties": 2,
"properties": {
"Address": { "type": "string" },
"Sequence": { "type": "number" },
"Hash": { "type": "string" }
}
},
"Content": { "type": "string" },
"To": { "type": "string" },
"Timestamp": { "type": "number" },
"PublicKey": { "type": "string" },
"Signature": { "type": "string" }
}
}
Field explanations:
- ObjectType, Sequence, PreHash, Timestamp, PublicKey, Signature are core/base fields (same roles as previously described; no further explanation here).
-
GroupHash, Confirm, Content, To are specific to group messages:
- GroupHash: Identifies the unique group this message belongs to.
- Confirm: Acknowledgment that the sender has already received a group message from Address with Sequence and Hash. Used for message ordering confirmation and preventing replay.
- Content: The actual group message content (filled by the user).
- Stored, displayed, and signed in plaintext form.
- During transmission, it is encrypted using the pairwise session key (AES-256) established with each recipient → ensures confidentiality.
-
Content can be:
- plain text string
- reference to a Bulletin (announcement)
- reference to file metadata
- To: The recipient's account (PublicKey). (Note: In group context, this is typically the group itself or broadcast semantics, but schema uses per-recipient for encryption routing.)
Any individual or system must first decrypt the Content using the corresponding session key (derived from the DH handshake with the sender) to restore the original plaintext message, then perform chain validation before storing a group message.
Validation Rules for Group Messages (before acceptance/storage)
Signature Verification
Verify Signature using sender's PublicKey to confirm integrity and authenticity.-
Chain Integrity Check
- Retrieve the last stored group message for this PublicKey + GroupHash.
- Ensure current Sequence = previous Sequence + 1.
- Ensure current PreHash = hash of the previous message (or fixed initial hash for the first message in this per-sender-per-group chain).
Decryption & Content Validation
Decrypt Content using the session key shared with the sender.
The decrypted content must be valid (string, bulletin reference, file reference, etc.).Confirm Field Validation (if present)
Verify that the referenced Address + Sequence + Hash corresponds to a previously received valid group message from that sender.
This completes the data format and validation specification for group chat messages in RippleMessenger.
Top comments (0)