feat(chat): larger messages — multi-output chunking in one transaction (tier 2)
A message whose ciphertext exceeds one 512-byte memo is now split across up to kHushChatMaxMessageParts (16) payload outputs in a SINGLE transaction, lifting the ~239-byte cap to a few KB while staying atomic, instant (0-conf), and one-fee. The crypto is untouched (one secretstream push/pull); chunking is a transport concern: - Header gains an optional part count `n` (emitted only when >1, so a 1-part message stays byte-identical on the wire); bounded in the parser. - Each chunk is a 2-hex part-index prefix + its ciphertext slice, so the receiver reorders them after the daemon's output shuffle. - OutgoingChatMemos carries a payload vector; chatSendOutputs emits header + N payloads (both broadcast call sites already iterate the result). - The grouper gains a multi-part pre-scan: a lone Message header with n>1 → collect the N indexed chunks, sort, strip, concat → one pair; anything else falls through to the classic single-pair path (older clients mis-pair and drop — graceful). A body beyond the cap is refused as TooLong (tier 3 later). Round-trip (shuffled outputs), 1-part byte-identical, and cap all unit-tested. Larger-messages tier 2; tier 3 (multi-tx) + the denser raw-memo encoding remain. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -25,6 +25,10 @@ struct HushChatHeader {
|
||||
std::string op; // Control only ("del" / "res" / "sensitive" / "unsensitive" / future ops); empty otherwise
|
||||
std::string secretstream_header_hex;
|
||||
std::string public_key_hex;
|
||||
// Message only: how many payload outputs this message's ciphertext is split across (header "n").
|
||||
// 1 = the classic single-payload message (field omitted on the wire). >1 means the payloads are
|
||||
// index-prefixed ciphertext chunks reassembled in order (larger-messages tier 2, one transaction).
|
||||
int parts = 1;
|
||||
// Optional sender-stamped compose time (header "ts", Unix seconds). 0 = absent (older sender) → the
|
||||
// receiver falls back to the tx/receive time. Lets both sides show the SAME (send) time.
|
||||
std::int64_t sent_at = 0;
|
||||
@@ -98,6 +102,13 @@ struct HushChatTransactionExtractionResult {
|
||||
|
||||
constexpr int kHushChatSupportedVersion = 0;
|
||||
constexpr std::size_t kHushChatMemoByteLimit = 512;
|
||||
// Larger-messages tier 2: the most payload outputs a single message may be split across (one tx).
|
||||
// Keeps the chat tx well under the shielded max_tx_size after Sietch decoy padding + proving cost.
|
||||
// A message that would need more parts than this is refused at compose time (tier 3 would lift it).
|
||||
constexpr int kHushChatMaxMessageParts = 16;
|
||||
// Each multi-part payload chunk is prefixed with a 2-hex-char (1-byte) part index so the receiver can
|
||||
// reorder chunks after the daemon shuffles a tx's outputs. 2 hex covers indices 0..255 (>> the cap).
|
||||
constexpr std::size_t kHushChatPartIndexHexLen = 2;
|
||||
constexpr std::size_t kHushChatPublicKeyHexLength = 64;
|
||||
constexpr std::size_t kHushChatSecretstreamHeaderHexLength = 48;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user