diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-10 17:30:22 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-10 17:30:22 +0200 |
| commit | 6cf21a019963468cb853e5c763ef0097115efa46 (patch) | |
| tree | ac0fd6261252b744ffdf15f0b100af7fd252d221 /packages/meshbay-common/tests | |
| parent | efc93c187dba9027292b51ff0e9caa29349c953e (diff) | |
| download | meshbay-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.py | 211 |
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 |