Autorka: Lukrecja Pleskaczyńska
Dane formalne: Paweł Pleskaczyński
Promotor: dr inż. Rafał Brodziak
WSB Merito Poznań
Wydział Finansów i Bankowości
Kierunek: Informatyka
Poznań 2026
Stworzenie bezpiecznego komunikatora P2P w języku Rust, umożliwiającego wysyłanie wiadomości do użytkowników nieaktywnych w sieci.
sledRealizacja zgodna z wymaganiami pracy projektowej.
| System | Architektura | Dostarczanie do nieaktywnych | Szyfrowanie |
|---|---|---|---|
| Signal | Scentralizowana | Tak (serwer) | Double Ratchet |
| Matrix | Federacyjna | Tak (serwery) | Olm / Megolm |
| Briar | P2P + Tor | Częściowo (Bluetooth) | Własne E2E |
| Tox | P2P (DHT) | Nie | NaCl box |
| PROJEKT | P2P (libp2p) | Tak (mailbox) | Noise + schemat inspirowany HPKE |
libp2p, mDNS, Kademliasled// network/behaviour.rs
#[derive(NetworkBehaviour)]
pub struct P2PBehaviour {
pub chat: ChatBehaviour, // wiadomości bezpośrednie
pub mailbox: MailboxBehaviour, // magazyn offline
pub discovery: DiscoveryBehaviour, // discovery = mDNS + Kademlia
pub ping: ping::Behaviour, // utrzymanie połączeń
}
Zachowanie sieciowe łączy czat, mailbox i odkrywanie.
1. Węzeł mailbox ogłasza usługę:
start_providing(klucz_usługi_mailbox)
2. Nadawca pyta DHT:
get_providers(klucz_usługi_mailbox)
→ [peer_1, peer_2, ...]
3. Trasowanie Kademlii (metryka XOR):
Nadawca → węzły coraz bliższe kluczowi → dostawcy
4. Nadawca wybiera 2+ najlepsze węzły
(lokalny ranking) i wysyła zaszyfrowaną
wiadomość + identyfikator odbiorcy
(hash klucza publicznego)
DHT zapewnia odkrywanie usług bez centralnego rejestru.
// network/handlers/mailbox.rs
MailboxRequest::Put { recipient, message } => {
match storage.store_message(recipient, message).await {
Ok(()) => {
self.start_providing_for_recipient(recipient)?;
MailboxResponse::PutResult { success: true }
}
Err(_) => MailboxResponse::PutResult { success: false },
}
}
Po zapisie węzeł ogłasza usługę w DHT.
// sync/retry.rs
pub fn exponential_backoff_with_jitter(&self, attempt: u32) -> Duration {
let base = self.exponential_backoff(attempt);
let jitter = rand::random::<u64>() % (base.as_millis() as u64 / 4 + 1);
Duration::from_millis(base.as_millis() as u64 + jitter)
}
Wygładza skoki obciążenia sieci.
// net/discovery.rs
pub fn new(local_peer_id: PeerId) -> Result<Self> {
let mdns = mdns::tokio::Behaviour::new(mdns::Config::default(), local_peer_id)?;
let store = kad::store::MemoryStore::new(local_peer_id);
let mut kademlia = kad::Behaviour::new(local_peer_id, store);
kademlia.set_mode(Some(kad::Mode::Server));
Ok(Self { mdns, kademlia })
}
Automatyczne wykrywanie w LAN + DHT.
// web/api.rs
let encrypted = node.identity.encrypt_for(&friend.e2e_public_key, req.content.as_bytes())?;
let message = Message { id: Uuid::new_v4(), sender: node.identity.peer_id, recipient: peer_id, ... };
node.history.store_message(message.clone()).await?;
node.outbox.add_pending(message.clone()).await?;
tokio::spawn(async move { network.send_message(peer_id, message).await; });
Walidacja, szyfrowanie, zapis i wysyłka.
// sync/engine/discovery/ranking.rs
let mut providers: Vec<_> = candidates
.into_iter()
.filter(|peer| self.backoff_manager.can_attempt(peer))
.collect();
providers.sort_by(|a, b| {
let sa = self.calculate_mailbox_score(*a);
let sb = self.calculate_mailbox_score(*b);
sb.partial_cmp(&sa).unwrap_or(Ordering::Equal)
});
Preferuje węzły niezawodne i szybkie.
// sync/engine/mailbox/ack.rs
let retry = RetryPolicy::fast_mailbox();
let ack_result = retry.retry_with_jitter(|| async {
network.mailbox_ack(peer_id, recipient_hash, msg_ids.clone()).await
}).await;
Zamyka cykl życia wiadomości.
// crypto/storage.rs
let mut key = [0u8; 32];
argon2.hash_password_into(password.as_bytes(), salt, &mut key)?;
let cipher = ChaCha20Poly1305::new(Key::from_slice(&key));
let nonce = ChaCha20Poly1305::generate_nonce(&mut OsRng);
let ciphertext = cipher.encrypt(&nonce, data)?;
Opcjonalne szyfrowanie danych w bazie.
// storage/history.rs
let conversation_id = Self::get_conversation_id(&msg.sender, &msg.recipient);
let key = Self::make_composite_key(&conversation_id, msg.timestamp, msg.nonce);
let value = self.serialize_message(&msg)?;
self.tree.insert(key, value)?;
self.tree.flush_async().await?;
Klucze kompozytowe = szybkie zapytania.
Zaszyfrowany ruch w analizie pakietów
Zabezpiecza kanał TCP między węzłami.
// crypto/hpke.rs (schemat inspirowany)
let shared = sk.diffie_hellman(&pk); // X25519
let key = sha256(shared); // KDF
let nonce = random_nonce(); // losowy nonce
let ct = aead.encrypt(&nonce, msg); // ChaCha20-Poly1305
Zabezpiecza treść wiadomości niezależnie od transportu.
Materiał pokazuje działanie systemu w praktyce.
Mediana opóźnienia: 2,1 → 4,6 ms (5 → 25 węzłów)
Przepustowość: 161 → 132 msg/s
Pamięć: 34–43 MB (średnio), do ok. 131 MB
Skuteczność dostarczeń: 100% przy churn 5–70%