dm: прямой обмен сообщениями (DM) + soundtouch + архитектура звонков

- src/dm/: dm_core/dm_crypto/dm_mailbox — прямой обмен сообщениями (DM)
- lib/soundtouch-master/: vendored SoundTouch (изменение темпа/высоты аудио)
- doc/dm_arch.md, doc/chat_call_arch.md: архитектура DM и звонков
- tests: test_dm.c, test_dm_e2e.c
- chat: рефакторинг chat_* модулей, member_sync, invite_build
- chatgui/chatgui-android: синхронизация с новым API чата
- lib/u_async, debug_config, utun_instance: сопутствующие изменения
This commit is contained in:
evgeny committed 2026-09-15 21:09:17 +03:00
1 parent 761f64cf76
commit 73fe99b33f
123 files changed
+14095 -1270

No files matched your search

+50
View File
@@ -0,0 +1,50 @@
/*
* dm_crypto.h — криптография прямого чата (DM)
*
* Детерминированная идентичность и E2E-шифрование:
* - conv_id / content_key выводятся обеими сторонами из своих ключей и
* pubkey пира (известен из общей группы) — без переговоров.
* - шифрование AES-256-CCM с детерминированным nonce из (dir, seq).
*/
#ifndef DM_CRYPTO_H
#define DM_CRYPTO_H
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
#define DM_CONTENT_KEY_SIZE 32
#define DM_NONCE_SIZE 13 /* AES-CCM требует ровно 13 байт */
#define DM_TAG_SIZE 16
/* conv_id = SHA256("utun_dm_v1" || min(a,b) || max(a,b))[..8] & 0x7FFF...,
* 63-битное число, одинаковое на обеих сторонах (одна ветка на пару). */
uint64_t dm_derive_conv_id(uint64_t a, uint64_t b);
/* content_key = SHA256(X25519(my_priv, peer_pub) || "utun_dm_content").
* Возвращает 0 при успехе, <0 при ошибке. */
int dm_derive_content_key(const uint8_t my_priv[32], const uint8_t peer_pub[32],
uint8_t out[DM_CONTENT_KEY_SIZE]);
/* Детерминированный nonce, уникальный на каждое сообщение:
* SHA256(conv_id || author || seq)[..13]. Одинаков на обеих сторонах,
* не пересекается между направлениями (author различается). */
void dm_build_nonce(uint64_t conv_id, uint64_t author, uint64_t seq, uint8_t nonce[DM_NONCE_SIZE]);
/* AES-256-CCM. ciphertext = ciphertext(plain_len) || tag(DM_TAG_SIZE).
* out должен вмещать plain_len + DM_TAG_SIZE. 0=ок, <0=ошибка. */
int dm_encrypt(const uint8_t key[DM_CONTENT_KEY_SIZE], const uint8_t nonce[DM_NONCE_SIZE],
const uint8_t* plain, size_t plain_len, uint8_t* out, size_t* out_len);
/* Обратная операция. ct_len = plain_len + DM_TAG_SIZE. 0=ок, <0=ошибка. */
int dm_decrypt(const uint8_t key[DM_CONTENT_KEY_SIZE], const uint8_t nonce[DM_NONCE_SIZE],
const uint8_t* ct, size_t ct_len, uint8_t* out, size_t* out_len);
#ifdef __cplusplus
}
#endif
#endif /* DM_CRYPTO_H */