Zenth – Schémas d’Architecture (Mermaid)
Ces schémas Mermaid sont importés depuis le site Zenth et décrivent l’architecture réseau, le système d’ajout d’amis et les flux d’authentification (login / register).
Architecture réseau
graph TB
subgraph "CLIENT A (Alice)"
CA[Application Zenth]
CA_DB[(UserDb chiffré)]
CA_Keys[Clés privées
Dilithium, Kyber, X25519] CA --> CA_DB CA --> CA_Keys end subgraph "DARKNET LAYER 1 (Tor/I2P)" DN1A[Circuit Tor 1
3 relays anonymes] DN1A_Exit[Exit Node] end subgraph "RELAY SERVER 1 (Notre Relay)" R1[Relay Node 1
Onion Service] R1_Route[Table de Routage
Chiffrée] R1_NoLog[NO LOGS
NO METADATA] R1 --> R1_Route R1 --> R1_NoLog end subgraph "DARKNET LAYER 2 (Tor/I2P)" DN2[Circuit Tor 2
3 nouveaux relays] DN2_Exit[Exit Node 2] end subgraph "RELAY SERVER 2 (Notre Relay)" R2[Relay Node 2
Onion Service] R2_Route[Table de Routage
Chiffrée] R2_NoLog[NO LOGS
NO METADATA] R2 --> R2_Route R2 --> R2_NoLog end subgraph "DARKNET LAYER 3 (Tor/I2P)" DN3[Circuit Tor 3
3 nouveaux relays] DN3_Exit[Exit Node 3] end subgraph "CLIENT B (Bob)" CB[Application Zenth] CB_DB[(UserDb chiffré)] CB_Keys[Clés privées
Dilithium, Kyber, X25519] CB --> CB_DB CB --> CB_Keys end subgraph "DHT SERVER (Serveur Central)" DHT[DHT Node
HTTPS TLS 1.3] DHT_DB[(Base de données)] DHT_Data[Données stockées:
• username_hash
• PreKeyBundles publics
• Demandes d'amis
• Challenges
• Sessions
PAS de secrets] DHT --> DHT_DB DHT_DB --> DHT_Data end %% MESSAGING FLOW (Client to Client) CA -->|1. Message chiffré E2E
Kyber1024 + X25519| DN1A DN1A -->|2. Circuit Tor anonyme| DN1A_Exit DN1A_Exit -->|3. Onion routing| R1 R1 -->|4. Re-chiffrement
Nouveau circuit| DN2 DN2 -->|5. Circuit Tor anonyme| DN2_Exit DN2_Exit -->|6. Onion routing| R2 R2 -->|7. Re-chiffrement
Nouveau circuit| DN3 DN3 -->|8. Circuit Tor anonyme| DN3_Exit DN3_Exit -->|9. Livraison| CB %% AUTHENTICATION/REGISTRATION FLOW CA -.->|Register/Login
HTTPS TLS 1.3| DN1A DN1A -.->|Circuit Tor| DN1A_Exit DN1A_Exit -.->|Onion routing| R1 R1 -.->|Forward to DHT| DN2 DN2 -.->|Circuit Tor| DN2_Exit DN2_Exit -.->|Connexion directe| DHT %% STYLING style CA fill:#87CEEB,stroke:#104E8B,stroke-width:3px,color:#000 style CB fill:#87CEEB,stroke:#104E8B,stroke-width:3px,color:#000 style DN1A fill:#9370DB,stroke:#4B0082,stroke-width:2px,color:#fff style DN2 fill:#9370DB,stroke:#4B0082,stroke-width:2px,color:#fff style DN3 fill:#9370DB,stroke:#4B0082,stroke-width:2px,color:#fff style R1 fill:#FFD700,stroke:#8B6914,stroke-width:3px,color:#000 style R2 fill:#FFD700,stroke:#8B6914,stroke-width:3px,color:#000 style DHT fill:#FF6347,stroke:#8B0000,stroke-width:3px,color:#fff style CA_DB fill:#98FB98,stroke:#228B22,stroke-width:2px,color:#000 style CB_DB fill:#98FB98,stroke:#228B22,stroke-width:2px,color:#000 style DHT_DB fill:#FFB6C1,stroke:#8B0000,stroke-width:2px,color:#000 style R1_NoLog fill:#90EE90,stroke:#2d5016,stroke-width:2px,color:#000 style R2_NoLog fill:#90EE90,stroke:#2d5016,stroke-width:2px,color:#000 style DHT_Data fill:#FFA500,stroke:#FF8C00,stroke-width:2px,color:#000
Dilithium, Kyber, X25519] CA --> CA_DB CA --> CA_Keys end subgraph "DARKNET LAYER 1 (Tor/I2P)" DN1A[Circuit Tor 1
3 relays anonymes] DN1A_Exit[Exit Node] end subgraph "RELAY SERVER 1 (Notre Relay)" R1[Relay Node 1
Onion Service] R1_Route[Table de Routage
Chiffrée] R1_NoLog[NO LOGS
NO METADATA] R1 --> R1_Route R1 --> R1_NoLog end subgraph "DARKNET LAYER 2 (Tor/I2P)" DN2[Circuit Tor 2
3 nouveaux relays] DN2_Exit[Exit Node 2] end subgraph "RELAY SERVER 2 (Notre Relay)" R2[Relay Node 2
Onion Service] R2_Route[Table de Routage
Chiffrée] R2_NoLog[NO LOGS
NO METADATA] R2 --> R2_Route R2 --> R2_NoLog end subgraph "DARKNET LAYER 3 (Tor/I2P)" DN3[Circuit Tor 3
3 nouveaux relays] DN3_Exit[Exit Node 3] end subgraph "CLIENT B (Bob)" CB[Application Zenth] CB_DB[(UserDb chiffré)] CB_Keys[Clés privées
Dilithium, Kyber, X25519] CB --> CB_DB CB --> CB_Keys end subgraph "DHT SERVER (Serveur Central)" DHT[DHT Node
HTTPS TLS 1.3] DHT_DB[(Base de données)] DHT_Data[Données stockées:
• username_hash
• PreKeyBundles publics
• Demandes d'amis
• Challenges
• Sessions
PAS de secrets] DHT --> DHT_DB DHT_DB --> DHT_Data end %% MESSAGING FLOW (Client to Client) CA -->|1. Message chiffré E2E
Kyber1024 + X25519| DN1A DN1A -->|2. Circuit Tor anonyme| DN1A_Exit DN1A_Exit -->|3. Onion routing| R1 R1 -->|4. Re-chiffrement
Nouveau circuit| DN2 DN2 -->|5. Circuit Tor anonyme| DN2_Exit DN2_Exit -->|6. Onion routing| R2 R2 -->|7. Re-chiffrement
Nouveau circuit| DN3 DN3 -->|8. Circuit Tor anonyme| DN3_Exit DN3_Exit -->|9. Livraison| CB %% AUTHENTICATION/REGISTRATION FLOW CA -.->|Register/Login
HTTPS TLS 1.3| DN1A DN1A -.->|Circuit Tor| DN1A_Exit DN1A_Exit -.->|Onion routing| R1 R1 -.->|Forward to DHT| DN2 DN2 -.->|Circuit Tor| DN2_Exit DN2_Exit -.->|Connexion directe| DHT %% STYLING style CA fill:#87CEEB,stroke:#104E8B,stroke-width:3px,color:#000 style CB fill:#87CEEB,stroke:#104E8B,stroke-width:3px,color:#000 style DN1A fill:#9370DB,stroke:#4B0082,stroke-width:2px,color:#fff style DN2 fill:#9370DB,stroke:#4B0082,stroke-width:2px,color:#fff style DN3 fill:#9370DB,stroke:#4B0082,stroke-width:2px,color:#fff style R1 fill:#FFD700,stroke:#8B6914,stroke-width:3px,color:#000 style R2 fill:#FFD700,stroke:#8B6914,stroke-width:3px,color:#000 style DHT fill:#FF6347,stroke:#8B0000,stroke-width:3px,color:#fff style CA_DB fill:#98FB98,stroke:#228B22,stroke-width:2px,color:#000 style CB_DB fill:#98FB98,stroke:#228B22,stroke-width:2px,color:#000 style DHT_DB fill:#FFB6C1,stroke:#8B0000,stroke-width:2px,color:#000 style R1_NoLog fill:#90EE90,stroke:#2d5016,stroke-width:2px,color:#000 style R2_NoLog fill:#90EE90,stroke:#2d5016,stroke-width:2px,color:#000 style DHT_Data fill:#FFA500,stroke:#FF8C00,stroke-width:2px,color:#000
Système d’ajout d’amis
graph TD
Start([Interface utilisateur])
Start --> SearchUser[search_user]
Start --> SendRequest[send_friend_request]
Start --> SyncRequests[sync_friend_requests]
Start --> ListPending[list_pending_requests]
Start --> AcceptRequest[accept_friend_request]
Start --> RejectRequest[reject_friend_request]
Start --> SyncResponses[sync_friend_responses]
Start --> ListFriends[list_friends]
Start --> RemoveFriend[remove_friend]
Start --> GetMyKey[get_my_public_key]
%% SEARCH USER FLOW
SearchUser --> SU1[Ouvrir UserDb
Authentification] SU1 --> SU2[Valider format hash
64 caractères hex] SU2 --> SU3{Hash valide?} SU3 -->|Non| SU_Err[Erreur format invalide] SU3 -->|Oui| SU4[Retour UserPublicInfoResponse
• username_hash
• status pending] %% SEND FRIEND REQUEST FLOW SendRequest --> SR1[Ouvrir UserDb] SR1 --> SR2{Vérifications:
• Pas déjà ami?
• Pas demande en cours?} SR2 -->|Échec| SR_Err[Erreur validation] SR2 -->|OK| SR3[Récupérer user_info] SR3 --> SR4[Déchiffrer clés privées
AES-256-GCM] SR4 --> SR5[Extraire dilithium_secret] SR5 --> SR6[Créer PreKeyBundle
• username_hash
• registration_id
• identity_key
• kyber_public_key
• x25519_public_key] SR6 --> SR7[Créer timestamp Unix] SR7 --> SR8[Signer avec Dilithium2
Message: target_hash + bundle + timestamp] SR8 --> SR9[Construire FriendRequest
• requester_hash_id
• target_hash_id
• pre_key_bundle
• dilithium_signature
• encrypted_message
• timestamp] SR9 --> SR10[Envoyer au serveur DHT
via send_friend_request_to_server] SR10 --> SR11[Créer DhtRequest
METHOD_CONTACT = 6] SR11 --> SR12[POST HTTPS
Content-Type: application/x-protobuf] SR12 --> SR13{Serveur
répond?} SR13 -->|Erreur| SR14[Log erreur
continuer quand même] SR13 -->|OK| SR15[Vérifier DhtResponse.success] SR14 --> SR16[Sauvegarder localement
create_outgoing_request] SR15 --> SR16 SR16 --> SR17[Succès
Demande envoyée/sauvegardée] %% SYNC FRIEND REQUESTS FLOW SyncRequests --> SFR1[Ouvrir UserDb] SFR1 --> SFR2[Déchiffrer dilithium_secret] SFR2 --> SFR3[fetch_incoming_requests_from_server] SFR3 --> SFR4[Créer timestamp + signer
Message: user_hash + since + timestamp] SFR4 --> SFR5[Construire FetchFriendRequestsRequest
• user_hash
• since_timestamp 0
• dilithium_signature] SFR5 --> SFR6[Créer DhtRequest
METHOD_FETCH_FRIEND_REQUESTS = 10] SFR6 --> SFR7[POST HTTPS vers DHT] SFR7 --> SFR8{Serveur OK?} SFR8 -->|Erreur| SFR_Err[Log erreur + continuer] SFR8 -->|OK| SFR9[Décoder FetchFriendRequestsResponse] SFR9 --> SFR10[Pour chaque FriendRequest reçue] SFR10 --> SFR11{Filtres:
• Pas notre demande?
• Pas déjà ami?
• Pas déjà reçue?} SFR11 -->|Skip| SFR10 SFR11 -->|OK| SFR12[Décoder PreKeyBundle
Extraire clés publiques] SFR12 --> SFR13[create_incoming_request
Sauvegarder dans DB] SFR13 --> SFR14[Incrémenter new_incoming] SFR14 --> SFR10 SFR10 --> SFR15[Nettoyer demandes expirées
cleanup_expired_requests] SFR15 --> SFR16[Retour SyncResult
• new_incoming
• errors] %% LIST PENDING REQUESTS ListPending --> LP1[Ouvrir UserDb] LP1 --> LP2[Nettoyer demandes expirées] LP2 --> LP3[list_pending_requests depuis DB] LP3 --> LP4[Retour Vec PendingRequestInfo] %% ACCEPT FRIEND REQUEST AcceptRequest --> AR1[Ouvrir UserDb] AR1 --> AR2[Déchiffrer dilithium_secret] AR2 --> AR3[Créer signature d'amitié
Message: FRIENDSHIP: + our_hash + remote_hash] AR3 --> AR4[Signer avec Dilithium2
friendship_signature] AR4 --> AR5[db_accept_friend_request
Créer ami avec signature] AR5 --> AR6[Créer notre PreKeyBundle] AR6 --> AR7[Construire FriendResponse
• responder_hash_id
• requester_hash_id
• accepted = true
• pre_key_bundle
• dilithium_signature
• timestamp] AR7 --> AR8[send_friend_response_to_server] AR8 --> AR9[Créer DhtRequest
METHOD_RESPOND_FRIEND_REQUEST = 11] AR9 --> AR10[POST HTTPS vers DHT] AR10 --> AR11{Serveur OK?} AR11 -->|Erreur| AR12[Log warning
acceptation locale OK] AR11 -->|OK| AR13[Succès complet] AR12 --> AR13 %% REJECT FRIEND REQUEST RejectRequest --> RR1[Ouvrir UserDb] RR1 --> RR2[Déchiffrer dilithium_secret] RR2 --> RR3[db_reject_friend_request
Supprimer de pending] RR3 --> RR4[Créer message à signer
requester_hash + 0 + timestamp] RR4 --> RR5[Signer avec Dilithium2] RR5 --> RR6[Construire FriendResponse
• accepted = false
• pre_key_bundle vide
• dilithium_signature] RR6 --> RR7[send_friend_response_to_server
METHOD_RESPOND_FRIEND_REQUEST = 11] RR7 --> RR8[POST HTTPS vers DHT] RR8 --> RR9{Serveur OK?} RR9 -->|Erreur| RR10[Log warning
rejet local OK] RR9 -->|OK| RR11[Succès complet] RR10 --> RR11 %% SYNC FRIEND RESPONSES SyncResponses --> SFRes1[Ouvrir UserDb] SFRes1 --> SFRes2[Déchiffrer dilithium_secret] SFRes2 --> SFRes3[fetch_friend_responses_from_server] SFRes3 --> SFRes4[Créer timestamp + signer] SFRes4 --> SFRes5[Construire FetchFriendResponsesRequest] SFRes5 --> SFRes6[Créer DhtRequest
METHOD_FETCH_FRIEND_RESPONSES = 14] SFRes6 --> SFRes7[POST HTTPS vers DHT] SFRes7 --> SFRes8{Serveur OK?} SFRes8 -->|Erreur| SFRes_Err[Log erreur] SFRes8 -->|OK| SFRes9[Décoder FetchFriendResponsesResponse] SFRes9 --> SFRes10[Pour chaque FriendResponse] SFRes10 --> SFRes11{Demande sortante
existe?} SFRes11 -->|Non| SFRes10 SFRes11 -->|Oui| SFRes12{accepted?} SFRes12 -->|true| SFRes13[Décoder PreKeyBundle
Extraire clés] SFRes13 --> SFRes14[add_friend_from_accepted_request
• remote_signature stockée] SFRes14 --> SFRes15[Incrémenter new_accepted] SFRes15 --> SFRes10 SFRes12 -->|false| SFRes16[Supprimer pending_request] SFRes16 --> SFRes10 SFRes10 --> SFRes17[Retour SyncResult
• new_accepted
• errors] %% LIST FRIENDS ListFriends --> LF1[Ouvrir UserDb] LF1 --> LF2[list_friends depuis DB] LF2 --> LF3[Retour Vec FriendInfo] %% REMOVE FRIEND RemoveFriend --> RF1[Ouvrir UserDb] RF1 --> RF2[remove_friend friend_id] RF2 --> RF3[Succès suppression] %% GET MY PUBLIC KEY GetMyKey --> GMK1[Ouvrir UserDb] GMK1 --> GMK2[get_user_info] GMK2 --> GMK3[Retour username_hash] style SearchUser fill:#87CEEB,stroke:#104E8B,stroke-width:2px,color:#000 style SendRequest fill:#FFD700,stroke:#8B6914,stroke-width:2px,color:#000 style SyncRequests fill:#98FB98,stroke:#228B22,stroke-width:2px,color:#000 style ListPending fill:#DDA0DD,stroke:#68228B,stroke-width:2px,color:#000 style AcceptRequest fill:#90EE90,stroke:#2d5016,stroke-width:2px,color:#000 style RejectRequest fill:#FFB6C1,stroke:#8B0000,stroke-width:2px,color:#000 style SyncResponses fill:#98FB98,stroke:#228B22,stroke-width:2px,color:#000 style ListFriends fill:#87CEEB,stroke:#104E8B,stroke-width:2px,color:#000 style RemoveFriend fill:#FFB6C1,stroke:#8B0000,stroke-width:2px,color:#000 style GetMyKey fill:#DDA0DD,stroke:#68228B,stroke-width:2px,color:#000
Authentification] SU1 --> SU2[Valider format hash
64 caractères hex] SU2 --> SU3{Hash valide?} SU3 -->|Non| SU_Err[Erreur format invalide] SU3 -->|Oui| SU4[Retour UserPublicInfoResponse
• username_hash
• status pending] %% SEND FRIEND REQUEST FLOW SendRequest --> SR1[Ouvrir UserDb] SR1 --> SR2{Vérifications:
• Pas déjà ami?
• Pas demande en cours?} SR2 -->|Échec| SR_Err[Erreur validation] SR2 -->|OK| SR3[Récupérer user_info] SR3 --> SR4[Déchiffrer clés privées
AES-256-GCM] SR4 --> SR5[Extraire dilithium_secret] SR5 --> SR6[Créer PreKeyBundle
• username_hash
• registration_id
• identity_key
• kyber_public_key
• x25519_public_key] SR6 --> SR7[Créer timestamp Unix] SR7 --> SR8[Signer avec Dilithium2
Message: target_hash + bundle + timestamp] SR8 --> SR9[Construire FriendRequest
• requester_hash_id
• target_hash_id
• pre_key_bundle
• dilithium_signature
• encrypted_message
• timestamp] SR9 --> SR10[Envoyer au serveur DHT
via send_friend_request_to_server] SR10 --> SR11[Créer DhtRequest
METHOD_CONTACT = 6] SR11 --> SR12[POST HTTPS
Content-Type: application/x-protobuf] SR12 --> SR13{Serveur
répond?} SR13 -->|Erreur| SR14[Log erreur
continuer quand même] SR13 -->|OK| SR15[Vérifier DhtResponse.success] SR14 --> SR16[Sauvegarder localement
create_outgoing_request] SR15 --> SR16 SR16 --> SR17[Succès
Demande envoyée/sauvegardée] %% SYNC FRIEND REQUESTS FLOW SyncRequests --> SFR1[Ouvrir UserDb] SFR1 --> SFR2[Déchiffrer dilithium_secret] SFR2 --> SFR3[fetch_incoming_requests_from_server] SFR3 --> SFR4[Créer timestamp + signer
Message: user_hash + since + timestamp] SFR4 --> SFR5[Construire FetchFriendRequestsRequest
• user_hash
• since_timestamp 0
• dilithium_signature] SFR5 --> SFR6[Créer DhtRequest
METHOD_FETCH_FRIEND_REQUESTS = 10] SFR6 --> SFR7[POST HTTPS vers DHT] SFR7 --> SFR8{Serveur OK?} SFR8 -->|Erreur| SFR_Err[Log erreur + continuer] SFR8 -->|OK| SFR9[Décoder FetchFriendRequestsResponse] SFR9 --> SFR10[Pour chaque FriendRequest reçue] SFR10 --> SFR11{Filtres:
• Pas notre demande?
• Pas déjà ami?
• Pas déjà reçue?} SFR11 -->|Skip| SFR10 SFR11 -->|OK| SFR12[Décoder PreKeyBundle
Extraire clés publiques] SFR12 --> SFR13[create_incoming_request
Sauvegarder dans DB] SFR13 --> SFR14[Incrémenter new_incoming] SFR14 --> SFR10 SFR10 --> SFR15[Nettoyer demandes expirées
cleanup_expired_requests] SFR15 --> SFR16[Retour SyncResult
• new_incoming
• errors] %% LIST PENDING REQUESTS ListPending --> LP1[Ouvrir UserDb] LP1 --> LP2[Nettoyer demandes expirées] LP2 --> LP3[list_pending_requests depuis DB] LP3 --> LP4[Retour Vec PendingRequestInfo] %% ACCEPT FRIEND REQUEST AcceptRequest --> AR1[Ouvrir UserDb] AR1 --> AR2[Déchiffrer dilithium_secret] AR2 --> AR3[Créer signature d'amitié
Message: FRIENDSHIP: + our_hash + remote_hash] AR3 --> AR4[Signer avec Dilithium2
friendship_signature] AR4 --> AR5[db_accept_friend_request
Créer ami avec signature] AR5 --> AR6[Créer notre PreKeyBundle] AR6 --> AR7[Construire FriendResponse
• responder_hash_id
• requester_hash_id
• accepted = true
• pre_key_bundle
• dilithium_signature
• timestamp] AR7 --> AR8[send_friend_response_to_server] AR8 --> AR9[Créer DhtRequest
METHOD_RESPOND_FRIEND_REQUEST = 11] AR9 --> AR10[POST HTTPS vers DHT] AR10 --> AR11{Serveur OK?} AR11 -->|Erreur| AR12[Log warning
acceptation locale OK] AR11 -->|OK| AR13[Succès complet] AR12 --> AR13 %% REJECT FRIEND REQUEST RejectRequest --> RR1[Ouvrir UserDb] RR1 --> RR2[Déchiffrer dilithium_secret] RR2 --> RR3[db_reject_friend_request
Supprimer de pending] RR3 --> RR4[Créer message à signer
requester_hash + 0 + timestamp] RR4 --> RR5[Signer avec Dilithium2] RR5 --> RR6[Construire FriendResponse
• accepted = false
• pre_key_bundle vide
• dilithium_signature] RR6 --> RR7[send_friend_response_to_server
METHOD_RESPOND_FRIEND_REQUEST = 11] RR7 --> RR8[POST HTTPS vers DHT] RR8 --> RR9{Serveur OK?} RR9 -->|Erreur| RR10[Log warning
rejet local OK] RR9 -->|OK| RR11[Succès complet] RR10 --> RR11 %% SYNC FRIEND RESPONSES SyncResponses --> SFRes1[Ouvrir UserDb] SFRes1 --> SFRes2[Déchiffrer dilithium_secret] SFRes2 --> SFRes3[fetch_friend_responses_from_server] SFRes3 --> SFRes4[Créer timestamp + signer] SFRes4 --> SFRes5[Construire FetchFriendResponsesRequest] SFRes5 --> SFRes6[Créer DhtRequest
METHOD_FETCH_FRIEND_RESPONSES = 14] SFRes6 --> SFRes7[POST HTTPS vers DHT] SFRes7 --> SFRes8{Serveur OK?} SFRes8 -->|Erreur| SFRes_Err[Log erreur] SFRes8 -->|OK| SFRes9[Décoder FetchFriendResponsesResponse] SFRes9 --> SFRes10[Pour chaque FriendResponse] SFRes10 --> SFRes11{Demande sortante
existe?} SFRes11 -->|Non| SFRes10 SFRes11 -->|Oui| SFRes12{accepted?} SFRes12 -->|true| SFRes13[Décoder PreKeyBundle
Extraire clés] SFRes13 --> SFRes14[add_friend_from_accepted_request
• remote_signature stockée] SFRes14 --> SFRes15[Incrémenter new_accepted] SFRes15 --> SFRes10 SFRes12 -->|false| SFRes16[Supprimer pending_request] SFRes16 --> SFRes10 SFRes10 --> SFRes17[Retour SyncResult
• new_accepted
• errors] %% LIST FRIENDS ListFriends --> LF1[Ouvrir UserDb] LF1 --> LF2[list_friends depuis DB] LF2 --> LF3[Retour Vec FriendInfo] %% REMOVE FRIEND RemoveFriend --> RF1[Ouvrir UserDb] RF1 --> RF2[remove_friend friend_id] RF2 --> RF3[Succès suppression] %% GET MY PUBLIC KEY GetMyKey --> GMK1[Ouvrir UserDb] GMK1 --> GMK2[get_user_info] GMK2 --> GMK3[Retour username_hash] style SearchUser fill:#87CEEB,stroke:#104E8B,stroke-width:2px,color:#000 style SendRequest fill:#FFD700,stroke:#8B6914,stroke-width:2px,color:#000 style SyncRequests fill:#98FB98,stroke:#228B22,stroke-width:2px,color:#000 style ListPending fill:#DDA0DD,stroke:#68228B,stroke-width:2px,color:#000 style AcceptRequest fill:#90EE90,stroke:#2d5016,stroke-width:2px,color:#000 style RejectRequest fill:#FFB6C1,stroke:#8B0000,stroke-width:2px,color:#000 style SyncResponses fill:#98FB98,stroke:#228B22,stroke-width:2px,color:#000 style ListFriends fill:#87CEEB,stroke:#104E8B,stroke-width:2px,color:#000 style RemoveFriend fill:#FFB6C1,stroke:#8B0000,stroke-width:2px,color:#000 style GetMyKey fill:#DDA0DD,stroke:#68228B,stroke-width:2px,color:#000
Flux de connexion (login)
graph TD
Start([Utilisateur saisit username + password]) --> Hash[Génération username_hash
SHA3-512] Hash --> OpenDB[Ouvrir UserDb
UserDb::open username, password] OpenDB --> DBCheck{Base de données
ouverte?} DBCheck -->|Échec| DBErr[Erreur:
Mot de passe incorrect
ou DB corrompue] DBCheck -->|Succès| GetInfo[Récupérer user_info
user_db.get_user_info] GetInfo --> OpenMaster[Ouvrir MasterDb
Récupérer salt stocké] OpenMaster --> DeriveSalt[Dérivation hash_password
Argon2id avec MÊME salt
que lors du register] DeriveSalt --> Decrypt[Déchiffrer clés privées
AES-256-GCM] Decrypt --> DecryptData[decrypt_key_with_password
• encrypted_identity_keys
• hash_password
• username AAD] DecryptData --> ParseJSON[Parser JSON déchiffré
Extraire clés] ParseJSON --> ExtractDil[Récupérer dilithium_secret
hex::decode] ExtractDil --> CreateClient[Créer LoginApiClient
Config: URL, timeout, retries] CreateClient --> RequestChallenge[Demander challenge au serveur
client.request_challenge] RequestChallenge --> ChallengeReq[Envoyer username_hash
au serveur DHT] ChallengeReq --> ServerCheck{Serveur
répond?} ServerCheck -->|Erreur| ServerErr[Erreur réseau
ou serveur indisponible] ServerCheck -->|OK| RecvChallenge[Recevoir Challenge
• challenge_id
• nonce aléatoire
• required_proof_type] RecvChallenge --> CreateTimestamp[Créer timestamp Unix
SystemTime::now] CreateTimestamp --> PrepareSign[Préparer message à signer
nonce + username_hash + timestamp] PrepareSign --> SignChallenge[Signer avec Dilithium2
sign_with_dilithium] SignChallenge --> SignData[dilithium2::detached_sign
• message
• dilithium_secret] SignData --> CreateProof[Construire AuthProof
• challenge_id
• user_hash_id
• proof_type
• signature
• timestamp] CreateProof --> SubmitProof[Soumettre preuve au serveur
client.submit_proof] SubmitProof --> ProofReq[Envoyer AuthProof
au serveur DHT] ProofReq --> ServerVerify{Serveur vérifie
la signature?} ServerVerify -->|Signature invalide| AuthErr[Authentification échouée
Signature incorrecte] ServerVerify -->|Challenge expiré| ChallengeErr[Challenge expiré
Redemander un nouveau] ServerVerify -->|OK| RecvResponse[Recevoir LoginResponse
• success = true
• session_token
• session_expiry] RecvResponse --> CheckSuccess{success?} CheckSuccess -->|Non| LoginErr[Login échoué
error_message du serveur] CheckSuccess -->|Oui| Success[LOGIN SUCCESS
Session token reçu
Session expiry timestamp] Success --> End([Retour message succès]) DBErr --> End ServerErr --> End AuthErr --> End ChallengeErr --> End LoginErr --> End style Start fill:#87CEEB,stroke:#104E8B,stroke-width:3px,color:#000 style Success fill:#90EE90,stroke:#2d5016,stroke-width:3px,color:#000 style DBErr fill:#FFB6C1,stroke:#8B0000,stroke-width:3px,color:#000 style ServerErr fill:#FFB6C1,stroke:#8B0000,stroke-width:3px,color:#000 style AuthErr fill:#FFB6C1,stroke:#8B0000,stroke-width:3px,color:#000 style ChallengeErr fill:#FFB6C1,stroke:#8B0000,stroke-width:3px,color:#000 style LoginErr fill:#FFB6C1,stroke:#8B0000,stroke-width:3px,color:#000 style OpenDB fill:#98FB98,stroke:#228B22,stroke-width:2px,color:#000 style Decrypt fill:#FF69B4,stroke:#8B1A55,stroke-width:2px,color:#000 style SignChallenge fill:#FFD700,stroke:#8B6914,stroke-width:2px,color:#000 style RequestChallenge fill:#FFA500,stroke:#FF8C00,stroke-width:2px,color:#000 style SubmitProof fill:#FFA500,stroke:#FF8C00,stroke-width:2px,color:#000
SHA3-512] Hash --> OpenDB[Ouvrir UserDb
UserDb::open username, password] OpenDB --> DBCheck{Base de données
ouverte?} DBCheck -->|Échec| DBErr[Erreur:
Mot de passe incorrect
ou DB corrompue] DBCheck -->|Succès| GetInfo[Récupérer user_info
user_db.get_user_info] GetInfo --> OpenMaster[Ouvrir MasterDb
Récupérer salt stocké] OpenMaster --> DeriveSalt[Dérivation hash_password
Argon2id avec MÊME salt
que lors du register] DeriveSalt --> Decrypt[Déchiffrer clés privées
AES-256-GCM] Decrypt --> DecryptData[decrypt_key_with_password
• encrypted_identity_keys
• hash_password
• username AAD] DecryptData --> ParseJSON[Parser JSON déchiffré
Extraire clés] ParseJSON --> ExtractDil[Récupérer dilithium_secret
hex::decode] ExtractDil --> CreateClient[Créer LoginApiClient
Config: URL, timeout, retries] CreateClient --> RequestChallenge[Demander challenge au serveur
client.request_challenge] RequestChallenge --> ChallengeReq[Envoyer username_hash
au serveur DHT] ChallengeReq --> ServerCheck{Serveur
répond?} ServerCheck -->|Erreur| ServerErr[Erreur réseau
ou serveur indisponible] ServerCheck -->|OK| RecvChallenge[Recevoir Challenge
• challenge_id
• nonce aléatoire
• required_proof_type] RecvChallenge --> CreateTimestamp[Créer timestamp Unix
SystemTime::now] CreateTimestamp --> PrepareSign[Préparer message à signer
nonce + username_hash + timestamp] PrepareSign --> SignChallenge[Signer avec Dilithium2
sign_with_dilithium] SignChallenge --> SignData[dilithium2::detached_sign
• message
• dilithium_secret] SignData --> CreateProof[Construire AuthProof
• challenge_id
• user_hash_id
• proof_type
• signature
• timestamp] CreateProof --> SubmitProof[Soumettre preuve au serveur
client.submit_proof] SubmitProof --> ProofReq[Envoyer AuthProof
au serveur DHT] ProofReq --> ServerVerify{Serveur vérifie
la signature?} ServerVerify -->|Signature invalide| AuthErr[Authentification échouée
Signature incorrecte] ServerVerify -->|Challenge expiré| ChallengeErr[Challenge expiré
Redemander un nouveau] ServerVerify -->|OK| RecvResponse[Recevoir LoginResponse
• success = true
• session_token
• session_expiry] RecvResponse --> CheckSuccess{success?} CheckSuccess -->|Non| LoginErr[Login échoué
error_message du serveur] CheckSuccess -->|Oui| Success[LOGIN SUCCESS
Session token reçu
Session expiry timestamp] Success --> End([Retour message succès]) DBErr --> End ServerErr --> End AuthErr --> End ChallengeErr --> End LoginErr --> End style Start fill:#87CEEB,stroke:#104E8B,stroke-width:3px,color:#000 style Success fill:#90EE90,stroke:#2d5016,stroke-width:3px,color:#000 style DBErr fill:#FFB6C1,stroke:#8B0000,stroke-width:3px,color:#000 style ServerErr fill:#FFB6C1,stroke:#8B0000,stroke-width:3px,color:#000 style AuthErr fill:#FFB6C1,stroke:#8B0000,stroke-width:3px,color:#000 style ChallengeErr fill:#FFB6C1,stroke:#8B0000,stroke-width:3px,color:#000 style LoginErr fill:#FFB6C1,stroke:#8B0000,stroke-width:3px,color:#000 style OpenDB fill:#98FB98,stroke:#228B22,stroke-width:2px,color:#000 style Decrypt fill:#FF69B4,stroke:#8B1A55,stroke-width:2px,color:#000 style SignChallenge fill:#FFD700,stroke:#8B6914,stroke-width:2px,color:#000 style RequestChallenge fill:#FFA500,stroke:#FF8C00,stroke-width:2px,color:#000 style SubmitProof fill:#FFA500,stroke:#FF8C00,stroke-width:2px,color:#000
Flux d’inscription (register)
graph TD
Start([Utilisateur saisit username + password + key]) --> Validation[Validation des paramètres
SecurityPassword::check_register_params] Validation --> Hash1[Génération username_hash
SHA3-512] Hash1 --> CreateDB[Création UserDb chiffrée
UserDb::create] CreateDB --> StoreInMaster[Stockage dans MasterDb
• username
• salt généré
• db_path] StoreInMaster --> GetSalt[Récupération du salt
depuis MasterDb] GetSalt --> DeriveKey[Dérivation hash_password
Argon2id avec MÊME salt] DeriveKey --> CryptoGen[Génération des clés cryptographiques] CryptoGen --> Dilithium[Clés Dilithium
Signature quantique-résistante] CryptoGen --> Kyber[Clés Kyber1024
KEM quantique-résistant] CryptoGen --> X25519[Clés X25519
ECDH classique] Dilithium --> DilKeys[• dilithium_public
• dilithium_secret
• identity_key_dilithium
• identity_key_dilithium_secret] Kyber --> KyberKeys[• kyber_public_bytes
• kyber_secret_bytes] X25519 --> PreKeys[Génération PreKeys X25519] PreKeys --> PreKey1[• pre_key_secret
• pre_key_public] PreKeys --> PreKey2[• signed_pre_key_secret
• signed_pre_key_public] Kyber --> PQKeys[Génération PreKeys Kyber] PQKeys --> PQKey1[• pq_pre_key_public
• pq_pre_key_secret] PQKeys --> PQKey2[• pq_last_resort_public
• pq_last_resort_secret] DilKeys --> IDs[Génération IDs aléatoires
OsRng] KyberKeys --> IDs PreKey1 --> IDs PreKey2 --> IDs PQKey1 --> IDs PQKey2 --> IDs IDs --> IDList[• registration_id
• pre_key_id
• signed_pre_key_id
• pq_pre_key_id
• pq_last_resort_key_id] IDList --> Sign1[Signature de signed_pre_key_public
avec dilithium_secret] Sign1 --> Bundle[Construction PreKeyBundle] Bundle --> BundleContent[PreKeyBundle contient:
• username_hash
• registration_id
• identity_key Dilithium
• pre_keys X25519
• pq_pre_keys Kyber1024
• signatures] BundleContent --> Timestamp[Génération timestamp Unix] Timestamp --> Commitment[Création password_commitment
SHA3-512 hash_password + username_hash] Commitment --> ZKP[Génération preuve ZK-STARK] ZKP --> ZKPData[• zkp_proof
• zkp_public_input] ZKPData --> Sign2[Signature d'identité] Sign2 --> SignData[Données signées:
• username_hash
• password_commitment
• zkp_public_input] SignData --> Sign3[Signature avec dilithium_secret] Sign3 --> Serialize[Sérialisation PreKeyBundle
Protobuf encoding] Serialize --> Request[Construction RegistrationRequest] Request --> ReqContent[Contient:
• username_hash
• pre_key_bundle sérialisé
• proof_type STARK
• password_commitment
• initial_proof
• identity_key_dilithium
• identity_signature
• timestamp] ReqContent --> APIClient[Création RegisterApiClient
Config: base_url, timeout, retries] APIClient --> SendHTTPS[Envoi HTTPS TLS 1.3
vers DHT serveur] SendHTTPS --> ServerCheck{Serveur
accessible?} ServerCheck -->|Erreur TLS| TLSError[Erreur certificat SSL
Suggestion: ZENTH_ACCEPT_INVALID_CERTS=1] ServerCheck -->|Connection refused| ConnError[Serveur non joignable
Vérifier zenth_dht running] ServerCheck -->|Succès| Response{Réponse serveur
success?} Response -->|Non| ServerError[Retour error_message du serveur] Response -->|Oui| Store[Préparation stockage sécurisé] Store --> KeysJSON[Création objet JSON des clés privées] KeysJSON --> KeysList[Clés stockées:
• dilithium_secret
• kyber_secret
• pre_key_secret
• signed_pre_key_secret
• pq_pre_key_secret
• pq_last_resort_secret
• registration_id
• zkp_public_input] KeysList --> Encrypt[Chiffrement des clés
AES-256-GCM avec hash_password] Encrypt --> UserInfo[Construction NewUserInfo] UserInfo --> UserInfoData[Données stockées:
• pseudo username
• username_hash hex
• encrypted_network_key
• encrypted_identity_keys
• identity_key_public
• kyber_public_key
• x25519_public_key
• registration_id
• created_at timestamp] UserInfoData --> SaveDB[Sauvegarde dans UserDb
user_db.save_user_info] SaveDB --> Success([Registration successful
User database created]) TLSError --> End([Fin - Échec]) ConnError --> End ServerError --> End Success --> End([Fin]) style Start fill:#90EE90,stroke:#2d5016,stroke-width:3px,color:#000 style Success fill:#90EE90,stroke:#2d5016,stroke-width:3px,color:#000 style TLSError fill:#FFB6C1,stroke:#8B0000,stroke-width:3px,color:#000 style ConnError fill:#FFB6C1,stroke:#8B0000,stroke-width:3px,color:#000 style ServerError fill:#FFB6C1,stroke:#8B0000,stroke-width:3px,color:#000 style Dilithium fill:#FFD700,stroke:#8B6914,stroke-width:2px,color:#000 style Kyber fill:#FFD700,stroke:#8B6914,stroke-width:2px,color:#000 style X25519 fill:#87CEEB,stroke:#104E8B,stroke-width:2px,color:#000 style ZKP fill:#DDA0DD,stroke:#68228B,stroke-width:2px,color:#000 style Encrypt fill:#FF69B4,stroke:#8B1A55,stroke-width:2px,color:#000 style CreateDB fill:#98FB98,stroke:#228B22,stroke-width:2px,color:#000 style SaveDB fill:#98FB98,stroke:#228B22,stroke-width:2px,color:#000 style SendHTTPS fill:#FFA500,stroke:#FF8C00,stroke-width:2px,color:#000
SecurityPassword::check_register_params] Validation --> Hash1[Génération username_hash
SHA3-512] Hash1 --> CreateDB[Création UserDb chiffrée
UserDb::create] CreateDB --> StoreInMaster[Stockage dans MasterDb
• username
• salt généré
• db_path] StoreInMaster --> GetSalt[Récupération du salt
depuis MasterDb] GetSalt --> DeriveKey[Dérivation hash_password
Argon2id avec MÊME salt] DeriveKey --> CryptoGen[Génération des clés cryptographiques] CryptoGen --> Dilithium[Clés Dilithium
Signature quantique-résistante] CryptoGen --> Kyber[Clés Kyber1024
KEM quantique-résistant] CryptoGen --> X25519[Clés X25519
ECDH classique] Dilithium --> DilKeys[• dilithium_public
• dilithium_secret
• identity_key_dilithium
• identity_key_dilithium_secret] Kyber --> KyberKeys[• kyber_public_bytes
• kyber_secret_bytes] X25519 --> PreKeys[Génération PreKeys X25519] PreKeys --> PreKey1[• pre_key_secret
• pre_key_public] PreKeys --> PreKey2[• signed_pre_key_secret
• signed_pre_key_public] Kyber --> PQKeys[Génération PreKeys Kyber] PQKeys --> PQKey1[• pq_pre_key_public
• pq_pre_key_secret] PQKeys --> PQKey2[• pq_last_resort_public
• pq_last_resort_secret] DilKeys --> IDs[Génération IDs aléatoires
OsRng] KyberKeys --> IDs PreKey1 --> IDs PreKey2 --> IDs PQKey1 --> IDs PQKey2 --> IDs IDs --> IDList[• registration_id
• pre_key_id
• signed_pre_key_id
• pq_pre_key_id
• pq_last_resort_key_id] IDList --> Sign1[Signature de signed_pre_key_public
avec dilithium_secret] Sign1 --> Bundle[Construction PreKeyBundle] Bundle --> BundleContent[PreKeyBundle contient:
• username_hash
• registration_id
• identity_key Dilithium
• pre_keys X25519
• pq_pre_keys Kyber1024
• signatures] BundleContent --> Timestamp[Génération timestamp Unix] Timestamp --> Commitment[Création password_commitment
SHA3-512 hash_password + username_hash] Commitment --> ZKP[Génération preuve ZK-STARK] ZKP --> ZKPData[• zkp_proof
• zkp_public_input] ZKPData --> Sign2[Signature d'identité] Sign2 --> SignData[Données signées:
• username_hash
• password_commitment
• zkp_public_input] SignData --> Sign3[Signature avec dilithium_secret] Sign3 --> Serialize[Sérialisation PreKeyBundle
Protobuf encoding] Serialize --> Request[Construction RegistrationRequest] Request --> ReqContent[Contient:
• username_hash
• pre_key_bundle sérialisé
• proof_type STARK
• password_commitment
• initial_proof
• identity_key_dilithium
• identity_signature
• timestamp] ReqContent --> APIClient[Création RegisterApiClient
Config: base_url, timeout, retries] APIClient --> SendHTTPS[Envoi HTTPS TLS 1.3
vers DHT serveur] SendHTTPS --> ServerCheck{Serveur
accessible?} ServerCheck -->|Erreur TLS| TLSError[Erreur certificat SSL
Suggestion: ZENTH_ACCEPT_INVALID_CERTS=1] ServerCheck -->|Connection refused| ConnError[Serveur non joignable
Vérifier zenth_dht running] ServerCheck -->|Succès| Response{Réponse serveur
success?} Response -->|Non| ServerError[Retour error_message du serveur] Response -->|Oui| Store[Préparation stockage sécurisé] Store --> KeysJSON[Création objet JSON des clés privées] KeysJSON --> KeysList[Clés stockées:
• dilithium_secret
• kyber_secret
• pre_key_secret
• signed_pre_key_secret
• pq_pre_key_secret
• pq_last_resort_secret
• registration_id
• zkp_public_input] KeysList --> Encrypt[Chiffrement des clés
AES-256-GCM avec hash_password] Encrypt --> UserInfo[Construction NewUserInfo] UserInfo --> UserInfoData[Données stockées:
• pseudo username
• username_hash hex
• encrypted_network_key
• encrypted_identity_keys
• identity_key_public
• kyber_public_key
• x25519_public_key
• registration_id
• created_at timestamp] UserInfoData --> SaveDB[Sauvegarde dans UserDb
user_db.save_user_info] SaveDB --> Success([Registration successful
User database created]) TLSError --> End([Fin - Échec]) ConnError --> End ServerError --> End Success --> End([Fin]) style Start fill:#90EE90,stroke:#2d5016,stroke-width:3px,color:#000 style Success fill:#90EE90,stroke:#2d5016,stroke-width:3px,color:#000 style TLSError fill:#FFB6C1,stroke:#8B0000,stroke-width:3px,color:#000 style ConnError fill:#FFB6C1,stroke:#8B0000,stroke-width:3px,color:#000 style ServerError fill:#FFB6C1,stroke:#8B0000,stroke-width:3px,color:#000 style Dilithium fill:#FFD700,stroke:#8B6914,stroke-width:2px,color:#000 style Kyber fill:#FFD700,stroke:#8B6914,stroke-width:2px,color:#000 style X25519 fill:#87CEEB,stroke:#104E8B,stroke-width:2px,color:#000 style ZKP fill:#DDA0DD,stroke:#68228B,stroke-width:2px,color:#000 style Encrypt fill:#FF69B4,stroke:#8B1A55,stroke-width:2px,color:#000 style CreateDB fill:#98FB98,stroke:#228B22,stroke-width:2px,color:#000 style SaveDB fill:#98FB98,stroke:#228B22,stroke-width:2px,color:#000 style SendHTTPS fill:#FFA500,stroke:#FF8C00,stroke-width:2px,color:#000