HMP / docs /dht_protocol.md
GitHub Action
Sync from GitHub with Git LFS
1c5b1af
# DHT Protocol Specification
## 1. Общие положения
* DHT-протокол предназначен для обмена информацией о пирах между агентами.
* Используется **DID** (Decentralized Identifier) как уникальный идентификатор агента.
* Для проверки подлинности применяется криптоподпись (публичный/приватный ключ).
* Для защиты от спама/флуда используется **Proof-of-Work (PoW)**.
* Каждый агент может иметь несколько сетевых интерфейсов (адресов).
* У агента может быть только **одна устойчивая пара DID + pubkey**.
---
## 2. Интерфейсы
Формат интерфейса:
```json
{
"addr": "tcp://1.2.3.4:4000",
"nonce": 123456,
"pow_hash": "abcd1234...",
"difficulty": 22,
"datetime": "2025-09-14T21:00:00Z",
"type": "internet"
}
```
### Поддерживаемые протоколы
* `tcp://`
* `udp://`
### Поле `type` (опционально)
* `localhost` — адреса локальной машины.
* `lan:[маска_подсети]` — локальная сеть, пример: `lan:192.168.10.0`.
(Один агент может иметь несколько сетевых интерфейсов и, соответственно, несколько LAN-сегментов.)
* `internet` — обычное TCP/UDP-подключение через глобальную сеть.
* `yggdrasil` — узел доступен через Yggdrasil overlay.
* `i2p` — узел доступен через I2P.
### Правила
* Если `port = 0` → интерфейс считается **отключённым**.
* Корректный интерфейс с более новой датой заменяет аналогичный старый (после проверки PoW).
* При обмене рекомендуется **не передавать локальные интерфейсы** в Интернет (исключение: Yggdrasil и I2P).
---
## 3. Proof-of-Work (PoW)
* Каждый интерфейс сопровождается PoW.
* Сложность PoW должна быть выбрана так, чтобы генерация занимала **несколько минут** (операция нечастая).
* Поля:
* `nonce` — число, подобранное агентом.
* `pow_hash` — хэш значения (`DID + addr + datetime + nonce`).
* `difficulty` — число ведущих нулей (или иное условие).
---
## 3.1 Формализация PoW и подписи
### Канонический вход для PoW
```
pow_input_string = DID + " -- " + addr + " -- " + datetime + " -- " + nonce_string
```
* Все строки кодируются в UTF-8.
* Хеш: `pow_hash = sha256(pow_input_string_bytes)`, hex lower-case (64 символа).
* `difficulty` = число ведущих нулевых hex-символов.
### Подпись сообщения
* Подписывается всё сообщение (JSON), кроме поля `signature`.
* Сериализация: JSON с отсортированными ключами, без пробелов:
```python
serialized = json.dumps(obj, separators=(",", ":"), sort_keys=True, ensure_ascii=False).encode("utf-8")
```
* Алгоритм: **Ed25519** (рекомендуется).
* Подпись хранится в поле:
```json
"signature": "BASE64URL(...)",
"sig_algo": "ed25519"
```
### Верификация
1. Проверить подпись сообщения по `pubkey`.
2. Для каждого `address` вычислить PoW и проверить `difficulty`.
3. Некорректные адреса игнорировать, сообщение в целом может оставаться валидным.
---
## 4. Сообщения
### 4.1 DISCOVERY
Используется для объявления себя в локальной сети.
```json
{
"type": "DISCOVERY",
"id": "did:example:123",
"name": "Agent_X",
"pubkey": "base58...",
"addresses": [
{
"addr": "tcp://1.2.3.4:4000",
"nonce": 123456,
"pow_hash": "0000abf39d...",
"difficulty": 22,
"datetime": "2025-09-14T21:00:00Z",
"type": "internet"
}
],
"signature": "BASE64URL(...)",
"sig_algo": "ed25519"
}
````
---
### 4.2 PEER\_EXCHANGE\_REQUEST / RESPONSE
Запрос известных пиров:
```json
{
"type": "PEER_EXCHANGE_REQUEST",
"id": "did:example:123",
"name": "Agent_X",
"addresses": [
{
"addr": "udp://1.2.3.4:4010",
"nonce": 987654,
"pow_hash": "0000123def...",
"difficulty": 22,
"datetime": "2025-09-14T21:05:00Z",
"type": "lan:192.168.1.0"
}
],
"signature": "BASE64URL(...)",
"sig_algo": "ed25519"
}
```
Ответ содержит список пиров (каждый с DID, pubkey и адресами, у которых тоже должен быть валидный PoW):
```json
[
{
"id": "did:example:456",
"name": "Agent_Y",
"pubkey": "base58...",
"addresses": [
{
"addr": "tcp://5.6.7.8:4020",
"nonce": 22222,
"pow_hash": "0000a1b2c3...",
"difficulty": 22,
"datetime": "2025-09-14T21:10:00Z",
"type": "internet"
}
],
"signature": "BASE64URL(...)",
"sig_algo": "ed25519"
}
]
```
---
## 5. Правила валидации адресов и пиров
* Каждый `address` в DISCOVERY и PEER_EXCHANGE должен содержать валидный PoW:
* `pow_hash = sha256(DID + " -- " + addr + " -- " + datetime + " -- " + nonce_string)`
* `difficulty` соответствует локальной политике (например, 22 ведущих нуля).
* Если PoW некорректен → адрес игнорируется.
* `datetime` фиксируется при генерации PoW и не должен изменяться.
* Если приходит новый адрес с той же парой `(DID + addr)` и более свежим `datetime` → он заменяет старый.
* **Разные pubkey для одного DID** → принимается **первый**, остальные игнорируются.
* **Адрес подписан чужим ключом** → запись отклоняется.
* **Несколько интерфейсов** → сохраняются все, кроме явных дубликатов.
> Примечание: строка `DID + " -- " + addr + " -- " + datetime + " -- " + nonce_string` всегда кодируется в UTF-8,
> а `nonce_string` преобразуется к десятичной строке перед конкатенацией.
---
## 6. Безопасность
* Для всех сообщений требуется **подпись отправителя** (в будущем: обязательная проверка).
* Сообщения без подписи или с невалидным PoW могут игнорироваться.
* В перспективе можно добавить шифрование трафика (например, на уровне TCP/TLS или QUIC).