aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-common/tests
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-10 17:30:22 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-10 17:30:22 +0200
commit6cf21a019963468cb853e5c763ef0097115efa46 (patch)
treeac0fd6261252b744ffdf15f0b100af7fd252d221 /packages/meshbay-common/tests
parentefc93c187dba9027292b51ff0e9caa29349c953e (diff)
downloadmeshbay-6cf21a019963468cb853e5c763ef0097115efa46.tar.gz
refactor(common): delete the sender-key implementation nothing uses
`senderkeys.py` and its 13 tests implemented Signal-style sender keys, and production has never called them: chat is a key per group, per epoch, per device, derived by name. The reasoning that ruled the ratchet out stays where it belongs — in `chatbox.py`, at the top of the module that replaced it — because the argument is the useful part, and it now stands on its own instead of pointing at a file to compare against. Kept code that nothing calls is worse than absent code: it reads as an alternative somebody may reach for, and it has to be maintained past every refactor to stay compiling, which is maintenance spent on a decision already made. The three comments naming `GroupSenderKeyStore` are rewritten to say the thing they were illustrating. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AsoWC3GmhNdwVFomW3QjH3
Diffstat (limited to 'packages/meshbay-common/tests')
-rw-r--r--packages/meshbay-common/tests/test_senderkeys.py211
1 files changed, 0 insertions, 211 deletions
diff --git a/packages/meshbay-common/tests/test_senderkeys.py b/packages/meshbay-common/tests/test_senderkeys.py
deleted file mode 100644
index a1181e1..0000000
--- a/packages/meshbay-common/tests/test_senderkeys.py
+++ /dev/null
@@ -1,211 +0,0 @@
-"""
-Tests for the Sender Keys group messaging protocol.
-
-Covers: key creation, distribution, encrypt/decrypt, multi-member groups,
-out-of-order delivery, serialization, and key rotation on member removal.
-"""
-
-import pytest
-
-from meshbay_common.senderkeys import (
- SenderKeyRecord,
- SenderKeyDistribution,
- SenderKeyMessage,
- GroupSenderKeyStore,
- encrypt_message,
- decrypt_message,
-)
-
-
-def test_basic_encrypt_decrypt():
- """Alice encrypts, Bob decrypts using Alice's distributed sender key."""
- alice_rec = SenderKeyRecord.create("alice")
- alice_dist = alice_rec.distribution()
-
- bob_store = GroupSenderKeyStore("group-1")
- bob_store.add_sender(alice_dist)
-
- msg, alice_rec = encrypt_message(alice_rec, b"hello group")
- plaintext = decrypt_message(bob_store, msg)
- assert plaintext == b"hello group"
-
-
-def test_multiple_messages_sequential():
- """Multiple messages from the same sender decrypt in order."""
- alice_rec = SenderKeyRecord.create("alice")
- store = GroupSenderKeyStore("group-1")
- store.add_sender(alice_rec.distribution())
-
- for i in range(5):
- msg, alice_rec = encrypt_message(alice_rec, f"message {i}".encode())
- pt = decrypt_message(store, msg)
- assert pt == f"message {i}".encode()
-
-
-def test_multi_member_group():
- """Three members: Alice sends, Bob and Carol both decrypt."""
- alice_rec = SenderKeyRecord.create("alice")
- alice_dist = alice_rec.distribution()
-
- bob_store = GroupSenderKeyStore("group-1")
- bob_store.add_sender(alice_dist)
-
- carol_store = GroupSenderKeyStore("group-1")
- carol_store.add_sender(alice_dist)
-
- msg, alice_rec = encrypt_message(alice_rec, b"broadcast")
-
- assert decrypt_message(bob_store, msg) == b"broadcast"
- assert decrypt_message(carol_store, msg) == b"broadcast"
-
-
-def test_bidirectional_chat():
- """Alice and Bob both send and receive."""
- alice_rec = SenderKeyRecord.create("alice")
- bob_rec = SenderKeyRecord.create("bob")
-
- alice_store = GroupSenderKeyStore("group-1")
- alice_store.add_sender(bob_rec.distribution())
-
- bob_store = GroupSenderKeyStore("group-1")
- bob_store.add_sender(alice_rec.distribution())
-
- msg1, alice_rec = encrypt_message(alice_rec, b"hi bob")
- assert decrypt_message(bob_store, msg1) == b"hi bob"
-
- msg2, bob_rec = encrypt_message(bob_rec, b"hi alice")
- assert decrypt_message(alice_store, msg2) == b"hi alice"
-
-
-def test_out_of_order_delivery():
- """Messages delivered out of order are decrypted correctly (up to MAX_SKIP)."""
- alice_rec = SenderKeyRecord.create("alice")
- store = GroupSenderKeyStore("group-1")
- store.add_sender(alice_rec.distribution())
-
- msg0, alice_rec = encrypt_message(alice_rec, b"msg 0")
- msg1, alice_rec = encrypt_message(alice_rec, b"msg 1")
- msg2, alice_rec = encrypt_message(alice_rec, b"msg 2")
-
- # Deliver out of order: 2, 0, 1
- assert decrypt_message(store, msg2) == b"msg 2"
- assert decrypt_message(store, msg0) == b"msg 0"
- assert decrypt_message(store, msg1) == b"msg 1"
-
-
-def test_replay_rejected():
- """A message decrypted twice raises an error (replay protection)."""
- alice_rec = SenderKeyRecord.create("alice")
- store = GroupSenderKeyStore("group-1")
- store.add_sender(alice_rec.distribution())
-
- msg, alice_rec = encrypt_message(alice_rec, b"once only")
- decrypt_message(store, msg)
-
- with pytest.raises(ValueError, match="already consumed"):
- decrypt_message(store, msg)
-
-
-def test_unknown_sender_rejected():
- """Message from an unknown sender raises ValueError."""
- alice_rec = SenderKeyRecord.create("alice")
- store = GroupSenderKeyStore("group-1")
-
- msg, _ = encrypt_message(alice_rec, b"who am i")
- with pytest.raises(ValueError, match="Unknown sender"):
- decrypt_message(store, msg)
-
-
-def test_non_member_cannot_decrypt():
- """Eve (not in group) cannot decrypt Alice's messages."""
- alice_rec = SenderKeyRecord.create("alice")
- eve_store = GroupSenderKeyStore("group-1")
-
- msg, _ = encrypt_message(alice_rec, b"secret")
- with pytest.raises(ValueError, match="Unknown sender"):
- decrypt_message(eve_store, msg)
-
-
-def test_key_rotation_on_member_removal():
- """After rotation, old chain keys cannot decrypt new messages."""
- alice_rec = SenderKeyRecord.create("alice")
- old_dist = alice_rec.distribution()
-
- # Eve had Alice's old key
- eve_store = GroupSenderKeyStore("group-1")
- eve_store.add_sender(old_dist)
-
- # Alice rotates (member removed from group)
- alice_rec = alice_rec.rotate()
- new_dist = alice_rec.distribution()
-
- # Bob gets the new distribution
- bob_store = GroupSenderKeyStore("group-1")
- bob_store.add_sender(new_dist)
-
- msg, alice_rec = encrypt_message(alice_rec, b"post-rotation")
- assert decrypt_message(bob_store, msg) == b"post-rotation"
-
- # Eve cannot decrypt with old key
- with pytest.raises(Exception):
- decrypt_message(eve_store, msg)
-
-
-def test_distribution_serialization():
- """SenderKeyDistribution round-trips through serialize/deserialize."""
- rec = SenderKeyRecord.create("alice")
- dist = rec.distribution()
- data = dist.serialize()
- recovered = SenderKeyDistribution.deserialize(data)
-
- assert recovered.sender_id == dist.sender_id
- assert recovered.chain_key == dist.chain_key
- assert recovered.iteration == dist.iteration
- assert recovered.signing_pk == dist.signing_pk
-
-
-def test_message_serialization():
- """SenderKeyMessage round-trips through serialize/deserialize."""
- rec = SenderKeyRecord.create("alice")
- store = GroupSenderKeyStore("group-1")
- store.add_sender(rec.distribution())
-
- msg, _ = encrypt_message(rec, b"serialize me")
- data = msg.serialize()
- recovered = SenderKeyMessage.deserialize(data)
-
- assert recovered.sender_id == msg.sender_id
- assert recovered.iteration == msg.iteration
- assert recovered.ciphertext == msg.ciphertext
- assert recovered.nonce == msg.nonce
- assert recovered.signature == msg.signature
-
- # Deserialized message still decrypts
- pt = decrypt_message(store, recovered)
- assert pt == b"serialize me"
-
-
-def test_tampered_ciphertext_rejected():
- """Modifying the ciphertext makes signature verification fail."""
- alice_rec = SenderKeyRecord.create("alice")
- store = GroupSenderKeyStore("group-1")
- store.add_sender(alice_rec.distribution())
-
- msg, _ = encrypt_message(alice_rec, b"authentic")
- msg.ciphertext = bytes([b ^ 0xff for b in msg.ciphertext])
-
- with pytest.raises(Exception):
- decrypt_message(store, msg)
-
-
-def test_store_sender_count():
- """GroupSenderKeyStore tracks sender count correctly."""
- store = GroupSenderKeyStore("group-1")
- assert store.sender_count == 0
-
- store.add_sender(SenderKeyRecord.create("alice").distribution())
- store.add_sender(SenderKeyRecord.create("bob").distribution())
- assert store.sender_count == 2
-
- store.remove_sender("alice")
- assert store.sender_count == 1