Merge b8d83fc5f015476f90ff73a7178cd73b4dfd1ccd into c883557b8be84ec03b71c6cd85e25710ca899b8a

This commit is contained in:
Jazz Turner-Baggs 2025-07-14 06:42:38 -07:00 committed by GitHub
commit b3a78526ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 1211 additions and 1 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/rust/target

View File

@ -1 +1,23 @@
# chat_proto
# chat_proto
![State](https://img.shields.io/badge/State-WIP-red)
This repository contains the core implementation of the $CHAT_PROTO types.
To make them easy to use, implementations in Rust and Nim are provided developers can focus on building.
## Structure
- **proto:** Protobuf definitions for Core and Conversation types
- **nim:** nimble package for generated types in nim
- **rust:** cargo crate for generated types in rust
- **specs:** current home of the specifications - these will likely be moved out of the repo. They are currently in lockstep with the type definitions which minimizes desync.
## Related Repositories
- [Nim POC](https://github.com/waku-org/nim-chat-poc/tree/jazzz/inbox) - This is a demo of the types being consumed in`nim`
- Importing packages from a monorepo appears to be broken in `nimble`, as a short term work around. The `.proto` files have been embedded in the POC, and will be removed once resolved
- [Rust POC](https://github.com/jazzz/umbra) - This is demo of the types being consumed in `rust`

View File

@ -0,0 +1,14 @@
{
"name": "WapTypes",
"image": "nimlang/nim",
"customizations": {
"vscode": {
"extensions": [
"NimLang.nimlang", //Nim lang extension
"vadimcn.vscode-lldb", //for Nim debug
"streetsidesoftware.code-spell-checker" //spell checker
]
}
},
"postCreateCommand": "./.devcontainer/post_create.sh"
}

View File

@ -0,0 +1 @@
nimble install nimlangserver

2
nim/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
nimble.develop
nimble.paths

19
nim/chat_proto.nim Normal file
View File

@ -0,0 +1,19 @@
import protobuf_serialization
import protobuf_serialization/proto_parser
import_proto3 "../proto/umbra/encryption.proto"
import_proto3 "../proto/umbra/envelope.proto"
import_proto3 "../proto/umbra/inbox.proto"
import_proto3 "../proto/umbra/reliability.proto"
export protobuf_serialization
# TODO: Do the Objects have to be listed manually?
export EncryptedPayload
export HistoryEntry
export InboxV1Frame
export ReliablePayload
export UmbraEnvelopeV1

14
nim/chat_proto.nimble Normal file
View File

@ -0,0 +1,14 @@
# Package
packageName = "chat_proto"
version = "0.1.0"
author = "jazzz"
description = "Type definitions for the chat protocol"
license = "MIT"
# bin = @["chat_proto"]
# installDirs = @["../proto"]
# Dependencies
requires "nim >= 2.0.14"
requires "chronicles"
requires "protobuf_serialization"

4
nim/config.nims Normal file
View File

@ -0,0 +1,4 @@
# begin Nimble config (version 2)
when withDir(thisDir(), system.fileExists("nimble.paths")):
include "nimble.paths"
# end Nimble config

1
nim/tests/config.nims Normal file
View File

@ -0,0 +1 @@
switch("path", "$projectDir/../src")

View File

@ -0,0 +1,13 @@
import unittest
import chat_proto
suite "Type Encoding Tests":
test "HistoryEntry roundtrip":
let x = chat_proto.HistoryEntry(message_id: "12345", retrieval_hint: @[1'u8, 2, 3, 255])
let encoded = Protobuf.encode(x)
let decoded = Protobuf.decode(encoded, HistoryEntry)
check x.message_id == decoded.message_id
check x.retrieval_hint == decoded.retrieval_hint
check x == decoded

View File

@ -0,0 +1,9 @@
syntax = "proto3";
package wap.common_frames;
message ContentFrame {
uint32 domain = 1;
uint32 tag = 2;
bytes bytes = 3;
}

View File

@ -0,0 +1,22 @@
syntax = "proto3";
package wap.convos.private_v1;
import "common_frames.proto";
message Placeholder {
uint32 counter = 1;
}
message PrivateV1Frame {
string conversation_id = 1;
oneof frame_type {
common_frames.ContentFrame content = 10;
Placeholder placeholder = 11;
// ....
}
}

View File

@ -0,0 +1,15 @@
syntax = "proto3";
package wap.encryption;
message EncryptedPayload {
oneof encryption {
NoiseKN noise_KN = 3;
}
}
message NoiseKN {
bytes encrypted_bytes = 1;
bytes ephemeral_pubkey = 2;
}

16
proto/wap/envelope.proto Normal file
View File

@ -0,0 +1,16 @@
syntax = "proto3";
package wap.envelope;
///////////////////////////////////////////////////////////////////////////////
// Payload Framing Messages
///////////////////////////////////////////////////////////////////////////////
message WapEnvelopeV1 {
string conversation_hint = 1;
uint64 salt = 2;
bytes payload = 5;
}

12
proto/wap/inbox.proto Normal file
View File

@ -0,0 +1,12 @@
syntax = "proto3";
package wap.inbox;
import "invite.proto";
message InboxV1Frame {
string recipient = 1;
oneof frame_type {
invite.InvitePrivateV1 invite_private_v1 = 10;
}
}

7
proto/wap/invite.proto Normal file
View File

@ -0,0 +1,7 @@
syntax = "proto3";
package wap.invite;
message InvitePrivateV1 {
repeated string participants = 1;
}

View File

@ -0,0 +1,23 @@
syntax = "proto3";
package wap.reliability;
///////////////////////////////////////////////////////////////////////////////
// SDS Payloads
///////////////////////////////////////////////////////////////////////////////
message HistoryEntry {
string message_id = 1; // Unique identifier of the SDS message, as defined in `Message`
bytes retrieval_hint = 2; // Optional information to help remote parties retrieve this SDS
// message; For example, A Waku deterministic message hash or routing payload hash
}
message ReliablePayload {
string message_id = 2;
string channel_id = 3;
int32 lamport_timestamp = 10;
repeated HistoryEntry causal_history = 11;
bytes bloom_filter = 12;
// Optional field causes errors in nim protobuf generation. Removing for now as optional is implied anways.
bytes content = 20;
}

View File

@ -0,0 +1,12 @@
{
"name": "Rust-WapTypes",
"image": "mcr.microsoft.com/devcontainers/rust:latest",
"customizations": {
"vscode": {
"extensions": [
"pbkit.vscode-pbkit"
]
}
},
"postCreateCommand": "bash -i .devcontainer/postcreate.sh"
}

View File

@ -0,0 +1,2 @@
sudo apt-get update
sudo apt-get install -y protobuf-compiler

5
rust/.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,5 @@
{
"[rust]": {
"editor.formatOnSave": true
}
}

593
rust/Cargo.lock generated Normal file
View File

@ -0,0 +1,593 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "anyhow"
version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
[[package]]
name = "bitflags"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "bytes"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
dependencies = [
"byteorder",
"iovec",
]
[[package]]
name = "bytes"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]]
name = "cfg-if"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
[[package]]
name = "either"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "errno"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
dependencies = [
"libc",
"windows-sys 0.60.2",
]
[[package]]
name = "fastrand"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]]
name = "fixedbitset"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
[[package]]
name = "getrandom"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
dependencies = [
"cfg-if",
"libc",
"r-efi",
"wasi",
]
[[package]]
name = "hashbrown"
version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "home"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "indexmap"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "iovec"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
dependencies = [
"libc",
]
[[package]]
name = "itertools"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
dependencies = [
"either",
]
[[package]]
name = "libc"
version = "0.2.174"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
[[package]]
name = "linux-raw-sys"
version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
[[package]]
name = "linux-raw-sys"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
[[package]]
name = "log"
version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "memchr"
version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "multimap"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084"
[[package]]
name = "once_cell"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "petgraph"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772"
dependencies = [
"fixedbitset",
"indexmap",
]
[[package]]
name = "prettyplease"
version = "0.2.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "061c1221631e079b26479d25bbf2275bfe5917ae8419cd7e34f13bfc2aa7539a"
dependencies = [
"proc-macro2",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "prost"
version = "0.13.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5"
dependencies = [
"bytes 1.10.1",
"prost-derive",
]
[[package]]
name = "prost-build"
version = "0.13.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf"
dependencies = [
"heck",
"itertools",
"log",
"multimap",
"once_cell",
"petgraph",
"prettyplease",
"prost",
"prost-types",
"regex",
"syn",
"tempfile",
]
[[package]]
name = "prost-derive"
version = "0.13.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d"
dependencies = [
"anyhow",
"itertools",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "prost-types"
version = "0.13.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16"
dependencies = [
"prost",
]
[[package]]
name = "protobuf"
version = "2.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94"
[[package]]
name = "protobuf-codegen"
version = "2.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "033460afb75cf755fcfc16dfaed20b86468082a2ea24e05ac35ab4a099a017d6"
dependencies = [
"protobuf",
]
[[package]]
name = "protoc"
version = "2.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0218039c514f9e14a5060742ecd50427f8ac4f85a6dc58f2ddb806e318c55ee"
dependencies = [
"log",
"which",
]
[[package]]
name = "protoc-rust"
version = "2.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22f8a182bb17c485f20bdc4274a8c39000a61024cfe461c799b50fec77267838"
dependencies = [
"protobuf",
"protobuf-codegen",
"protoc",
"tempfile",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "r-efi"
version = "5.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
[[package]]
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rustix"
version = "0.38.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys 0.4.15",
"windows-sys 0.59.0",
]
[[package]]
name = "rustix"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys 0.9.4",
"windows-sys 0.59.0",
]
[[package]]
name = "syn"
version = "2.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tempfile"
version = "3.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
dependencies = [
"fastrand",
"getrandom",
"once_cell",
"rustix 1.0.7",
"windows-sys 0.59.0",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "wap-types"
version = "0.0.2-dev"
dependencies = [
"bytes 0.4.12",
"prost",
"prost-build",
"protoc-rust",
]
[[package]]
name = "wasi"
version = "0.14.2+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
dependencies = [
"wit-bindgen-rt",
]
[[package]]
name = "which"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
dependencies = [
"either",
"home",
"once_cell",
"rustix 0.38.44",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-sys"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
"windows-targets 0.53.2",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.6",
"windows_i686_gnullvm 0.52.6",
"windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc 0.52.6",
]
[[package]]
name = "windows-targets"
version = "0.53.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef"
dependencies = [
"windows_aarch64_gnullvm 0.53.0",
"windows_aarch64_msvc 0.53.0",
"windows_i686_gnu 0.53.0",
"windows_i686_gnullvm 0.53.0",
"windows_i686_msvc 0.53.0",
"windows_x86_64_gnu 0.53.0",
"windows_x86_64_gnullvm 0.53.0",
"windows_x86_64_msvc 0.53.0",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_aarch64_msvc"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnu"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_gnullvm"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_i686_msvc"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnu"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "windows_x86_64_msvc"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
[[package]]
name = "wit-bindgen-rt"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
dependencies = [
"bitflags",
]

18
rust/cargo.toml Normal file
View File

@ -0,0 +1,18 @@
[workspace]
members = [
"wap-types"
]
default-members = [
"wap-types"
]
resolver = "3"
[workspace.package]
version = "0.0.1-dev"
[workspace.dependencies]

12
rust/wap-types/Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "wap-types"
edition = "2024"
version = "0.0.2-dev"
[dependencies]
prost = "0.13.5"
bytes = "0.4"
[build-dependencies]
prost-build = "0.13.5"
protoc-rust = "2"

43
rust/wap-types/build.rs Normal file
View File

@ -0,0 +1,43 @@
extern crate protoc_rust;
use std::env;
use std::path::PathBuf;
fn get_proto_dir() -> PathBuf {
println!(
"Manifest dir: {:?}",
env::var("CARGO_MANIFEST_DIR").unwrap()
);
// protos are stored in ../../proto/
let mut proto_root_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
proto_root_dir.pop();
proto_root_dir.pop();
proto_root_dir.push("proto");
proto_root_dir.push("wap");
println!("proto_dir: {:?}", proto_root_dir);
proto_root_dir
}
fn main() {
let mut config = prost_build::Config::new();
// Create mod file to maintain import hierarchy
config.include_file("mod.rs");
config
.compile_protos(
&[
"envelope.proto",
"common_frames.proto",
"conversations/private_v1.proto",
"encryption.proto",
"inbox.proto",
"invite.proto",
"reliability.proto"
],
// set proto_path
&[get_proto_dir().to_str().unwrap()],
)
.unwrap();
}

24
rust/wap-types/src/lib.rs Normal file
View File

@ -0,0 +1,24 @@
pub mod payload;
pub use payload::types::wap::*;
#[cfg(test)]
mod tests {
use super::*;
use prost::Message;
#[test]
fn test_private_v1_roundtrip() {
convos::private_v1::PrivateV1Frame {
conversation_id: "conversationId".to_string(),
frame_type: Some(convos::private_v1::private_v1_frame::FrameType::Content(
common_frames::ContentFrame {
domain: 0,
tag: 0,
bytes: "Hello, World!".to_string().encode_to_vec(),
},
)),
};
}
}

View File

@ -0,0 +1,94 @@
pub mod types {
include!(concat!(env!("OUT_DIR"), "/mod.rs"));
}
use prost::Message;
pub use types::wap::*;
use crate::{
convos::private_v1::{PrivateV1Frame, private_v1_frame},
encryption::EncryptedPayload,
envelope::WapEnvelopeV1,
inbox::{InboxV1Frame, inbox_v1_frame},
};
impl PrivateV1Frame {
pub fn new(conversation_id: String, frame: private_v1_frame::FrameType) -> Self {
PrivateV1Frame {
conversation_id,
frame_type: Some(frame),
}
}
}
impl InboxV1Frame {
pub fn new(recipient: String, frame: inbox_v1_frame::FrameType) -> Self {
InboxV1Frame {
recipient: recipient,
// conversation_id,
frame_type: Some(frame),
}
}
}
pub trait ToEnvelope {
fn to_envelope(self, conversation_id: String, salt: u64) -> WapEnvelopeV1;
}
impl ToEnvelope for EncryptedPayload {
fn to_envelope(self, conversation_id: String, salt: u64) -> WapEnvelopeV1 {
WapEnvelopeV1 {
conversation_hint: conversation_id, // TODO
salt,
payload: self.encode_to_vec(), // Avoid allocation here?
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use prost::Message;
use crate::reliability::ReliablePayload;
use crate::common_frames::ContentFrame;
#[test]
fn test_private_v1_roundtrip() {
let text = "Hello, World!".to_string();
let msg = PrivateV1Frame {
conversation_id: "conversationId".to_string(),
frame_type: Some(private_v1_frame::FrameType::Content(
ContentFrame {
domain: 0,
tag: 0,
bytes: text.encode_to_vec(),
},
)),
};
let reliable = ReliablePayload {
message_id: "msg_id".into(),
channel_id: msg.conversation_id.clone(),
lamport_timestamp: 0,
causal_history: vec![],
bloom_filter: vec![1, 2, 3, 4],
content: msg.encode_to_vec(),
};
let buf = reliable.encode_to_vec();
let reliable_msg = ReliablePayload::decode(&*buf).unwrap();
let msg_from_bytes =
PrivateV1Frame::decode(&*reliable_msg.content)
.expect("Failed to decode message");
assert_eq!(
msg, msg_from_bytes,
"Encoded and decoded messages should match"
);
}
}

122
specs/<PROTO>.md Normal file
View File

@ -0,0 +1,122 @@
---
title: Waku Application Protocol
name: A private decentralized messaging protocol for multiple usecases.
category: Standards Track
status: raw
tags: chat
editor: Jazz Alyxzander<jazz@status.im>
contributors:
---
# Abstract
This specification defines a modular communication protocol designed to provide a privacy focused approach to common messaging patterns. The protocol employs a lean root layer that defers to independent sub-protocols for defining communication behavior, with versioning as a first-class concept for handling protocol evolution.
# Background / Rationale / Motivation
Traditionally communication protocols face several critical challenges as they grow.
Different communication scenarios have vastly different requirements. A protocol optimized for high-volume public broadcasts performs poorly for intimate encrypted conversations, and vice versa. Monolithic protocols cannot optimize for these diverse use cases simultaneously.
Once widely deployed, communication protocols become difficult to modify. Even minor changes can break compatibility across clients. As a result versioning becomes a complex negotiation problem, which makes deploying protocol updates difficult. At each stage protocols become increasingly difficult to modify, which slows down forward progress and eventually leads to ossification.
A preferred approach would be to practice resiliency at the protocol level by focusing on versioning from the beginning.
# Theory / Semantics
This protocol is a lean coordination layer which provides the backbone for smaller independent "Conversation" sub-protocols. Conversation protocols completely define a pathway for communication. This root protocol provides common functionality to support a wide array of communication use cases, and the remaining functionality is deferred to Conversation protocols to define.
```mermaid
flowchart TD
P(%PROTO) --> C1(Conversation)
P --> C2(Conversation)
P --> C3(....)
style C3 fill:#FFFFFF,stroke:#,stroke-width:1px,stroke-dasharray: 5 1
```
## Conversations
ConversationTypes are standalone methods to send and receive messages. While a full service "chat" protocol needs to provide additional features such as identity management, message history, backups and versioning, conversations are more narrowly scoped.
They can be created permissionlessly within the %PROTO, as there is no required registration. Developers are free to use any given conversation type as long as all intended participants support it.
ConversationTypes MUST adhere to the [Conversations](./conversations.md) specification in order to maintain compatibility, however network adoption is not a requirement.
## Versioning
Incompatible versions of a conversation protocol result in distinct conversationTypes (E.g. PrivateV1 vs PrivateV3). The opinionated strategy is to allow multiplexing at the conversation level, rather than requiring the entire network of clients to run the same version.
Individual conversationTypes can implement functionality to migrate participants to a conversation, but that is deferred to contributors. By making this a conversationType issue, different use cases can choose a system that works for them.
Developers wishing to interop with other projects will need to ensure they have overlapping support of ConversationTypes.
## Default Inbox
There exists a circular dependency in initializing a Conversation. Conversations require an established conversation to send an invitation, yet at the beginning no channel exists between contacts.
To resolve this all clients MUST implement a default [Inbox](./inbox.md) to receive initial messages. The default inbox allows clients to discover new conversations asynchronously without prior coordination. By listening in a static location.
The default inbox MUST be configured with the parameters:
- **inbox_addr:** `client_address`
- **discriminator:** "default"
As the clients address is directly linked to the content_topic there is some metadata leakage, and this pathway SHOULD only be used as a last resort.
## Envelopes
As clients can support multiple sub-protocols simultaneously, a mechanism is required to determine how decode messages.
All payloads sent MUST be deterministically decodable. Deterministic decoding means that clients can always classify a envelope as 1 of 3 states: Readable, BadlyFormed, Addressed to someone else. To support this %PROTO uses an Envelope to link encrypted payloads with the information required to process them. As this payload is sent in the clear the payloads cannot contain any identifiable information.
### Conversation Hinting
Conversation_ids are sufficient to allow clients to lookup the required encryption parameters and decrypt a message. However this would leak Conversation metadata. Instead a hint is used which allows clients to check if this message is of interest.
Messages with an unknown hint can be safely disregarded.
ConversationHints are computed by using a salted hash of the `conversationId`. specifically defined as `lowercase_hex(blake2s(salt || conversation_id))`
[TODO: Should conversations define their own hinting?]
## Wire Format Specification / Syntax
The wire format is specified using protocol buffers v3.
```protobuf
message WapEnvelopeV1 {
string conversation_hint = 1;
uint32 salt = 2;
EncryptedBytes encrypted_bytes = 3;
}
```
## Implementation Suggestions (optional)
### User level Conversations
Application developers should maintain standalone identifiers for user-level conversations that are separate from the protocol-level conversation_id. A single logical conversation from the user's perspective may utilize multiple ConversationTypes over time. As versions are considered different types, the underlying relationship is many to one. By maintaining application-level conversation identifiers, developers can provide users with consistent conversation continuity while the underlying protocol mechanisms handle version transitions and security upgrades transparently.
## (Further Optional Sections)
## Security/Privacy Considerations
Messages inherit the privacy and security properties of the ConversationType used to send them. Please refer to the corresponding specifications when analyzing properties.
### Default Inbox Privacy
Messages sent to the default inbox are linkable to an client (as it is derived from the clients address). This means that if a target client address is known to an observer, they can determine if any messages were sent to the target using the default inbox. In this case the Envelopes contain no sender information, so this does not leak social graph information.
## Copyright
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
## References
A list of references.

89
specs/conversations.md Normal file
View File

@ -0,0 +1,89 @@
---
title: CONVERSATIONS
name: Conversation based communications
category: Standards Track
status: raw
tags: chat
editor: Jazz Alyxzander<jazz@status.im>
contributors:
---
# Abstract
This specification outlines the requirements for defining a ConversationType
# Background / Rationale / Motivation
Modern communication systems require a reliable and flexible way to establish and manage conversations between participants.
While simple message-passing protocols exist, they lack the ability to manage state across a stream of messages.
The Conversations Protocol addresses this gap by defining a mechanism to establish long term communication sessions in decentralized environments.
# Theory / Semantics
A ConversationType is a specification which defines a method for clients to communicate.
Each ConversationType defines its own encryption, encoding, and message types which are necessary for operation.
A Conversation is an instance of a particular ConversationType which contains the associated state such as membership, encryption parameters, names etc.
## Requirements
To be considered valid, every ConversationType specification is required to define the operation completely.
A ConversationType MUST define which encryption scheme is used
A ConversationType MUST define which Frames are used.
A ConversationType MUST define which encoding is used.
A ConversationType MUST define which content topics are valid places to receive messages.
A ConversationType MUST define how to generate conversation_ids
A ConversationType SHOULD define membership requirements and limitations.
A ConversationType SHOULD define privacy and security guarantees.
A ConversationType SHOULD maintain a deterministic decoding tree.
## ConversationType Identifiers
ConversationTypes are identified by the title of the specification. This allows developers to lookup the associated specification.
[TODO: This doesn't make any sense, as its been mentioned that new versions of a conversationType are distinct types. Which is it? ]
E.g. inbox.md -> InboxV1
## Conversation Identifiers
conversation_ids allow for the efficient lookup of encryption state.
Care should be taken to ensure that conversation_ids do not conflict.
[TODO: Should more guidance be added later? e,g mandating a format to ensure uniqueness between conversationTypes -- /<convo_name>/<version>/<ident>]
[TODO: touch on the nuance of generating conversation_ids from participant lists?]
## Framing
To disambiguate between different logical layers, payload types sent by a Conversation are referred to as `Frames`.
Conversations are free to determine which frames are needed for their specific use cases.
## Encryption
Conversation types are free to choose which ever encryption mechanism works best for their application.
[TODO: Expand on recomendations]
## Content Topics
Content topics are how ConversationTypes define where an how messages are discovered by participants.
When developing new ConversationTypes contributors should consider:
- Privacy impacts of the chosen topic policy.
- Channel binding and the impacts on message security.
## Security/Privacy Considerations
This approach puts heavy requirements on ConversationTypes to build their own cryptography without providing much guidance. Finding mechanisms that provide safety while maintaining the flexibility should be prioritized in follow up work.
## Copyright
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
## References
A list of references.

1
specs/inbox.md Normal file
View File

@ -0,0 +1 @@
Moved to WakuSpecs - https://github.com/waku-org/specs/pull/72