bitchat-protocol 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,39 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ tags: ['v*']
7
+ pull_request:
8
+ branches: [main]
9
+
10
+ jobs:
11
+ test:
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ matrix:
15
+ python-version: ['3.10', '3.11', '3.12']
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: ${{ matrix.python-version }}
21
+ - run: pip install -e ".[dev]"
22
+ - run: pytest
23
+ - run: mypy bitchat_protocol
24
+
25
+ publish:
26
+ needs: test
27
+ runs-on: ubuntu-latest
28
+ if: startsWith(github.ref, 'refs/tags/v')
29
+ environment: pypi
30
+ permissions:
31
+ id-token: write
32
+ steps:
33
+ - uses: actions/checkout@v4
34
+ - uses: actions/setup-python@v5
35
+ with:
36
+ python-version: '3.12'
37
+ - run: pip install hatch
38
+ - run: hatch build
39
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,14 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .eggs/
5
+ dist/
6
+ build/
7
+ .venv/
8
+ venv/
9
+ .pytest_cache/
10
+ .mypy_cache/
11
+ .benchmarks/
12
+ *.whl
13
+ *.tar.gz
14
+ .DS_Store
@@ -0,0 +1,30 @@
1
+ # Changelog — bitchat_protocol (Python)
2
+
3
+ All notable changes follow [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
4
+
5
+ ## [0.1.0] — 2026-03-22
6
+
7
+ Initial GA release.
8
+
9
+ ### Added
10
+ - `encode(packet, padding=False)` / `decode(data)` — binary packet encode/decode; `decode` never raises
11
+ - `BitchatPacket` dataclass: `version`, `type`, `ttl`, `timestamp`, `flags`, `sender_id`, `payload`
12
+ - Protocol v1 (14-byte header) and v2 (16-byte header) support
13
+ - Compression: raw deflate (wbits=-15) with 50,000:1 ratio safety cap; `IS_COMPRESSED` flag handling
14
+ - `MessageType` enum with all wire-defined message types
15
+ - TLV codec:
16
+ - `AnnouncementPacket(nickname, noise_public_key, signing_public_key)`
17
+ - `PrivateMessagePacket(message_id, content, recipient_id?, sender_id?, timestamp?)`
18
+ - `encode_announcement(pkt)` / `decode_announcement(data)` → `AnnouncementPacket | None`
19
+ - `encode_private_message(pkt)` / `decode_private_message(data)` → `PrivateMessagePacket | None`
20
+ - `peer_id_from_noise_key(noise_public_key)` — derive 8-byte peer ID from 32-byte key
21
+ - `peer_id_to_hex(peer_id)` / `peer_id_from_hex(hex_str)` — hex conversion helpers
22
+ - Cross-language compatibility: wire format matches `@bitchat-sdk/protocol-core` (JS) and `BitchatProtocol` (Swift)
23
+ - Comprehensive fuzz and stress test suite (38 tests)
24
+
25
+ ### Protocol Compatibility
26
+ Wire-format compatible with BitChat iOS (Swift), BitChat Android (Kotlin), `@bitchat-sdk/protocol-core`, and `BitchatProtocol`.
27
+
28
+ [0.1.0]: https://github.com/bitchat-sdk/protocol-core-py/releases/tag/v0.1.0
29
+
30
+ [Unreleased]: https://github.com/bitchat-sdk/protocol-core-py/compare/v0.1.0...HEAD
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as compiled
5
+ binaries, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all rights to the present and future
14
+ work under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <https://unlicense.org>
@@ -0,0 +1,162 @@
1
+ Metadata-Version: 2.4
2
+ Name: bitchat-protocol
3
+ Version: 0.1.0
4
+ Summary: BitChat binary protocol encode/decode — packet structs, TLV codec, peer ID utilities
5
+ Project-URL: Source Code, https://github.com/bitchat-sdk/protocol-core-py
6
+ Project-URL: Bug Tracker, https://github.com/bitchat-sdk/protocol-core-py/issues
7
+ Project-URL: Changelog, https://github.com/bitchat-sdk/protocol-core-py/blob/main/CHANGELOG.md
8
+ Author: bitchat-sdk contributors
9
+ License: Unlicense
10
+ License-File: LICENSE
11
+ Keywords: bitchat,ble,mesh,nostr,p2p,protocol
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: The Unlicense (Unlicense)
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Communications
20
+ Classifier: Topic :: Security :: Cryptography
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.10
23
+ Provides-Extra: dev
24
+ Requires-Dist: mypy>=1.9; extra == 'dev'
25
+ Requires-Dist: pytest>=8.0; extra == 'dev'
26
+ Description-Content-Type: text/markdown
27
+
28
+ # bitchat-protocol
29
+
30
+ BitChat binary protocol encode/decode for Python.
31
+
32
+ Implements the wire format from the BitChat mesh networking protocol:
33
+ binary packet encode/decode, TLV codec for announcement and private message
34
+ structures, and peer ID derivation utilities.
35
+
36
+ ## Installation
37
+
38
+ ```bash
39
+ pip install bitchat-protocol
40
+ ```
41
+
42
+ Requires Python 3.10+.
43
+
44
+ ## Quick Start
45
+
46
+ ```python
47
+ from bitchat_protocol import (
48
+ encode, decode,
49
+ BitchatPacket, MessageType,
50
+ encode_announcement, decode_announcement,
51
+ AnnouncementPacket,
52
+ peer_id_from_noise_key,
53
+ )
54
+
55
+ # Encode a broadcast message
56
+ import time
57
+ packet = BitchatPacket(
58
+ version=1,
59
+ type=int(MessageType.MESSAGE),
60
+ ttl=7,
61
+ timestamp=int(time.time() * 1000),
62
+ flags=0,
63
+ sender_id=bytes.fromhex('abcdef0123456789'),
64
+ payload='Hello, BitChat!'.encode(),
65
+ )
66
+ wire = encode(packet, padding=True) # padded for BLE transmission
67
+
68
+ # Decode from bytes received over BLE or Nostr relay
69
+ decoded = decode(wire)
70
+ if decoded:
71
+ print('type:', decoded.type)
72
+ print('payload:', decoded.payload.decode())
73
+ ```
74
+
75
+ ## API
76
+
77
+ ### Packet Encode/Decode
78
+
79
+ ```python
80
+ encode(packet: BitchatPacket, *, padding: bool = False) -> bytes
81
+ decode(data: bytes) -> BitchatPacket | None
82
+ ```
83
+
84
+ `decode()` returns `None` (never raises) on invalid or truncated input.
85
+
86
+ ### TLV: AnnouncementPacket
87
+
88
+ ```python
89
+ encode_announcement(packet: AnnouncementPacket) -> bytes
90
+ decode_announcement(data: bytes) -> AnnouncementPacket | None
91
+ ```
92
+
93
+ Decoder is **lenient**: unknown TLV tags are skipped (forward-compatible).
94
+
95
+ ### TLV: PrivateMessagePacket
96
+
97
+ ```python
98
+ encode_private_message(packet: PrivateMessagePacket) -> bytes
99
+ decode_private_message(data: bytes) -> PrivateMessagePacket | None
100
+ ```
101
+
102
+ Decoder is **strict**: returns `None` on any unknown TLV tag.
103
+
104
+ ### Peer ID Utilities
105
+
106
+ ```python
107
+ peer_id_from_noise_key(noise_public_key: bytes) -> str # 16-char hex
108
+ peer_id_to_bytes(peer_id: str) -> bytes # 8 bytes
109
+ peer_id_from_bytes(data: bytes) -> str # 16-char hex
110
+ nostr_geo_dm_peer_id(nostr_pubkey_hex: str) -> str # "nostr_" + prefix
111
+ nostr_geo_chat_peer_id(nostr_pubkey_hex: str) -> str # "nostr:" + prefix
112
+ ```
113
+
114
+ ### Utilities
115
+
116
+ ```python
117
+ hex_to_bytes(hex_str: str) -> bytes
118
+ bytes_to_hex(data: bytes) -> str
119
+ ```
120
+
121
+ ## Wire Format
122
+
123
+ ### v1 Header (14 bytes)
124
+ ```
125
+ [version:1][type:1][ttl:1][timestamp:8 BE uint64][flags:1][payloadLen:2 BE uint16]
126
+ [senderID:8]
127
+ [recipientID:8] — if flags & HAS_RECIPIENT
128
+ [payload:payloadLen]
129
+ [signature:64] — if flags & HAS_SIGNATURE
130
+ ```
131
+
132
+ ### v2 Header (16 bytes)
133
+ Same but `payloadLen` is 4 bytes (BE uint32) and source routing is supported.
134
+
135
+ ### Flags Byte
136
+ | Bit | Value | Name |
137
+ |-----|-------|------|
138
+ | 0 | 0x01 | HAS_RECIPIENT |
139
+ | 1 | 0x02 | HAS_SIGNATURE |
140
+ | 2 | 0x04 | IS_COMPRESSED |
141
+ | 3 | 0x08 | HAS_ROUTE (v2+ only) |
142
+ | 4 | 0x10 | IS_RSR |
143
+
144
+ ## Running Tests
145
+
146
+ ```bash
147
+ pip install -e ".[dev]"
148
+ pytest
149
+ ```
150
+
151
+ ## Compatibility
152
+
153
+ This package implements the same binary wire format as:
154
+ - `ios/bitchat/Protocols/BinaryProtocol.swift`
155
+ - `android/.../BinaryProtocol.kt`
156
+
157
+ Cross-language compatibility is verified by the golden fixture suite in
158
+ the [bitchat-sdk](https://github.com/bitchat-sdk) org.
159
+
160
+ ## License
161
+
162
+ Unlicense — public domain.
@@ -0,0 +1,135 @@
1
+ # bitchat-protocol
2
+
3
+ BitChat binary protocol encode/decode for Python.
4
+
5
+ Implements the wire format from the BitChat mesh networking protocol:
6
+ binary packet encode/decode, TLV codec for announcement and private message
7
+ structures, and peer ID derivation utilities.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ pip install bitchat-protocol
13
+ ```
14
+
15
+ Requires Python 3.10+.
16
+
17
+ ## Quick Start
18
+
19
+ ```python
20
+ from bitchat_protocol import (
21
+ encode, decode,
22
+ BitchatPacket, MessageType,
23
+ encode_announcement, decode_announcement,
24
+ AnnouncementPacket,
25
+ peer_id_from_noise_key,
26
+ )
27
+
28
+ # Encode a broadcast message
29
+ import time
30
+ packet = BitchatPacket(
31
+ version=1,
32
+ type=int(MessageType.MESSAGE),
33
+ ttl=7,
34
+ timestamp=int(time.time() * 1000),
35
+ flags=0,
36
+ sender_id=bytes.fromhex('abcdef0123456789'),
37
+ payload='Hello, BitChat!'.encode(),
38
+ )
39
+ wire = encode(packet, padding=True) # padded for BLE transmission
40
+
41
+ # Decode from bytes received over BLE or Nostr relay
42
+ decoded = decode(wire)
43
+ if decoded:
44
+ print('type:', decoded.type)
45
+ print('payload:', decoded.payload.decode())
46
+ ```
47
+
48
+ ## API
49
+
50
+ ### Packet Encode/Decode
51
+
52
+ ```python
53
+ encode(packet: BitchatPacket, *, padding: bool = False) -> bytes
54
+ decode(data: bytes) -> BitchatPacket | None
55
+ ```
56
+
57
+ `decode()` returns `None` (never raises) on invalid or truncated input.
58
+
59
+ ### TLV: AnnouncementPacket
60
+
61
+ ```python
62
+ encode_announcement(packet: AnnouncementPacket) -> bytes
63
+ decode_announcement(data: bytes) -> AnnouncementPacket | None
64
+ ```
65
+
66
+ Decoder is **lenient**: unknown TLV tags are skipped (forward-compatible).
67
+
68
+ ### TLV: PrivateMessagePacket
69
+
70
+ ```python
71
+ encode_private_message(packet: PrivateMessagePacket) -> bytes
72
+ decode_private_message(data: bytes) -> PrivateMessagePacket | None
73
+ ```
74
+
75
+ Decoder is **strict**: returns `None` on any unknown TLV tag.
76
+
77
+ ### Peer ID Utilities
78
+
79
+ ```python
80
+ peer_id_from_noise_key(noise_public_key: bytes) -> str # 16-char hex
81
+ peer_id_to_bytes(peer_id: str) -> bytes # 8 bytes
82
+ peer_id_from_bytes(data: bytes) -> str # 16-char hex
83
+ nostr_geo_dm_peer_id(nostr_pubkey_hex: str) -> str # "nostr_" + prefix
84
+ nostr_geo_chat_peer_id(nostr_pubkey_hex: str) -> str # "nostr:" + prefix
85
+ ```
86
+
87
+ ### Utilities
88
+
89
+ ```python
90
+ hex_to_bytes(hex_str: str) -> bytes
91
+ bytes_to_hex(data: bytes) -> str
92
+ ```
93
+
94
+ ## Wire Format
95
+
96
+ ### v1 Header (14 bytes)
97
+ ```
98
+ [version:1][type:1][ttl:1][timestamp:8 BE uint64][flags:1][payloadLen:2 BE uint16]
99
+ [senderID:8]
100
+ [recipientID:8] — if flags & HAS_RECIPIENT
101
+ [payload:payloadLen]
102
+ [signature:64] — if flags & HAS_SIGNATURE
103
+ ```
104
+
105
+ ### v2 Header (16 bytes)
106
+ Same but `payloadLen` is 4 bytes (BE uint32) and source routing is supported.
107
+
108
+ ### Flags Byte
109
+ | Bit | Value | Name |
110
+ |-----|-------|------|
111
+ | 0 | 0x01 | HAS_RECIPIENT |
112
+ | 1 | 0x02 | HAS_SIGNATURE |
113
+ | 2 | 0x04 | IS_COMPRESSED |
114
+ | 3 | 0x08 | HAS_ROUTE (v2+ only) |
115
+ | 4 | 0x10 | IS_RSR |
116
+
117
+ ## Running Tests
118
+
119
+ ```bash
120
+ pip install -e ".[dev]"
121
+ pytest
122
+ ```
123
+
124
+ ## Compatibility
125
+
126
+ This package implements the same binary wire format as:
127
+ - `ios/bitchat/Protocols/BinaryProtocol.swift`
128
+ - `android/.../BinaryProtocol.kt`
129
+
130
+ Cross-language compatibility is verified by the golden fixture suite in
131
+ the [bitchat-sdk](https://github.com/bitchat-sdk) org.
132
+
133
+ ## License
134
+
135
+ Unlicense — public domain.
@@ -0,0 +1,86 @@
1
+ """
2
+ bitchat_protocol — BitChat binary protocol encode/decode for Python.
3
+
4
+ Quickstart:
5
+
6
+ from bitchat_protocol import encode, decode, MessageType, AnnouncementPacket, BitchatPacket
7
+
8
+ packet = BitchatPacket(
9
+ version=1, type=int(MessageType.MESSAGE), ttl=7,
10
+ timestamp=0, flags=0,
11
+ sender_id=bytes.fromhex('abcdef0123456789'),
12
+ payload=b'Hello, BitChat!',
13
+ )
14
+ wire = encode(packet)
15
+ decoded = decode(wire)
16
+ """
17
+
18
+ from .types import (
19
+ MessageType,
20
+ NoisePayloadType,
21
+ PacketFlag,
22
+ BitchatPacket,
23
+ AnnouncementPacket,
24
+ PrivateMessagePacket,
25
+ )
26
+ from .errors import (
27
+ BitchatProtocolError,
28
+ PacketTooShortError,
29
+ UnsupportedVersionError,
30
+ TruncatedFieldError,
31
+ DecompressionError,
32
+ SuspiciousCompressionRatioError,
33
+ TLVDecodeError,
34
+ TLVEncodeError,
35
+ )
36
+ from .codec import encode, decode, hex_to_bytes, bytes_to_hex
37
+ from .tlv import (
38
+ encode_announcement,
39
+ decode_announcement,
40
+ encode_private_message,
41
+ decode_private_message,
42
+ )
43
+ from .peer import (
44
+ peer_id_from_noise_key,
45
+ peer_id_to_bytes,
46
+ peer_id_from_bytes,
47
+ nostr_geo_dm_peer_id,
48
+ nostr_geo_chat_peer_id,
49
+ )
50
+
51
+ __version__ = "0.1.0"
52
+
53
+ __all__ = [
54
+ # Types
55
+ "MessageType",
56
+ "NoisePayloadType",
57
+ "PacketFlag",
58
+ "BitchatPacket",
59
+ "AnnouncementPacket",
60
+ "PrivateMessagePacket",
61
+ # Errors
62
+ "BitchatProtocolError",
63
+ "PacketTooShortError",
64
+ "UnsupportedVersionError",
65
+ "TruncatedFieldError",
66
+ "DecompressionError",
67
+ "SuspiciousCompressionRatioError",
68
+ "TLVDecodeError",
69
+ "TLVEncodeError",
70
+ # Codec
71
+ "encode",
72
+ "decode",
73
+ "hex_to_bytes",
74
+ "bytes_to_hex",
75
+ # TLV
76
+ "encode_announcement",
77
+ "decode_announcement",
78
+ "encode_private_message",
79
+ "decode_private_message",
80
+ # Peer
81
+ "peer_id_from_noise_key",
82
+ "peer_id_to_bytes",
83
+ "peer_id_from_bytes",
84
+ "nostr_geo_dm_peer_id",
85
+ "nostr_geo_chat_peer_id",
86
+ ]