sorrydave
Should be production-quality Python library for the DAVE (Discord Audio/Video End-to-End Encryption) protocol. Currently it passes the tests i made but i have problem using it. I mean the library it uses(rfc9420) passes official vectors. It implements the protocol as a pure data-transformation and state-management layer on top of rfc9420 (PyMLS), with no I/O or networking: you pass in bytes (Voice Gateway opcodes, encoded media frames) and get back bytes (opcode payloads, encrypted/decrypted frames).
Features
- MLS integration: Key packages, external sender handling, proposals, commit/welcome (opcodes 25–30), exporter-based sender keys
- Sender key ratchet: Per-sender, per-epoch keys via MLS-Exporter + HKDF; cache for out-of-order decryption
- Frame transform: Codec-aware encrypt/decrypt (OPUS, VP9, VP8, H264, H265, AV1), ULEB128, truncated AES128-GCM, DAVE footer (
0xFAFA) - Identity: Pairwise fingerprint (scrypt) and displayable codes (45-digit / 30-digit)
- Voice Gateway helpers: Parse-and-apply wrappers that return explicit
applied/media_readyresults without sending frames
Install
pip install -e .
Requires Python 3.9+, rfc9420, cryptography, and pycryptodome.
Minimal lifecycle
- Create a session:
DaveSession(local_user_id=123456789, channel_id=voice_channel_id). The MLS group ID is the channel snowflake as 8 big-endian bytes; Discord will silently drop commits that use any other group ID. For Go Live, passchannel_id=mls_channel_id_from_stream_server_id(rtc_server_id). - On select_protocol_ack (or prepare_epoch with
epoch=1), callsession.prepare_epoch(1)and send the returned bytes as opcode 26 (Key Package). - On opcode 11 / 13, call
sync_clients_connect/sync_client_disconnect(or the sessionadd_expected_members/remove_expected_membermethods). If opcode 11 listed other users before this session existed, callconfigure_occupied_join(...)so you wait for opcode 30 instead of committing a local group. - On opcode 25, call
handle_external_sender_wire(session, package_bytes). - On opcode 27, call
apply_proposals_message(session, proposal_bytes). After a short quiet period, sendsession.take_commit_welcome()as opcode 28 if it returns bytes. Batching and the send itself stay in the caller. - On opcode 29 / 30, call
handle_announce_commit_wire/handle_welcome_wire. Ifappliedis True and media is ready, send opcode 23 withbuild_ready_for_transition_dict(transition_id). Do not execute the transition here. - On opcode 22, parse with
parse_execute_transition(orhandle_execute_transition_message) and then switch send ratchets. Senders must keep the previous epoch until this opcode, per protocol.md. - Media:
session.encrypt_frame(frame, codec="OPUS")andsession.decrypt_frame(protocol_frame, sender_id). Silence packets (SILENCE_PACKET) and frames that failprotocol_frame_checkpass through.
Error recovery: On InvalidCommitError, call recover_invalid_commit(session, transition_id) and send the returned opcode 31 JSON, then the opcode 26 key package. Do not send opcode 23 or execute opcode 22 for the rejected transition.
Caller-owned: Voice Gateway WebSocket I/O, proposal coalescing timers, opcode 23 sends, opcode 22 execution policy (including the documented transition_id=0 init path), recovery retry caps, and join watchdogs.
API overview
DaveSession:handle_external_sender_package,prepare_epoch,apply_proposals,take_commit_welcome,handle_commit,handle_welcome,execute_transition,configure_occupied_join,leave_group,encrypt_frame,decrypt_frame,receive_ratchet_user_idssorrydave.voice_gateway:sync_clients_connect,handle_external_sender_wire,apply_proposals_message,handle_announce_commit_wire,handle_welcome_wire,recover_invalid_commitFrameEncryptor.encrypt(encoded_frame, codec)/FrameDecryptor.decrypt(protocol_frame)generate_fingerprint(local_id, local_pub, remote_id, remote_pub)→ 45-digit stringdisplayable_code(data, total_digits, group_size)for epoch authenticator (e.g. 30 digits, group 5)
Scope
- In scope: MLS state, ratchet, OPUS/VP9/VP8/H264/H265/AV1 codec handling, frame encrypt/decrypt, identity fingerprint, opcode parse/build, and transport-free Voice Gateway helpers.
- Out of scope: Voice Gateway WebSocket I/O, proposal debounce timers, SFU silence-packet generation, WebRTC depacketizer patches.
License
MIT.
Release files for sorrydave 0.10.7
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sorrydave-0.10.7.tar.gz | 193.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sorrydave-0.10.7-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 350.4 kB
Release files / sorrydave-0.10.7.tar.gz
| Download URL | sorrydave-0.10.7.tar.gz |
|---|---|
| Size | 193.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
625d0f2c9b1cdc2a15bbd7c0c678c01db9a1384869c9ff9077ecf469325b7ce2
|
|
BLAKE2b-256 checksum How to use checksums |
1b077a304b4d143f42a7399f1fce149000064254922bd06b605e3f947e1301a1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.5
|
Release files / sorrydave-0.10.7-py3-none-any.whl
| Download URL | sorrydave-0.10.7-py3-none-any.whl |
|---|---|
| Size | 157.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7171305345607a98a3db5e729d8470cfb938dac41106b45894323d6319161cb5
|
|
BLAKE2b-256 checksum How to use checksums |
28c0e374886ae014bf78fafe56d057b2e835595ea31d8b5695d9a20796e0dd45
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.5
|