montana/Node/External-Audit/SINGLE-SOURCE-OF-TRUTH.md
2026-05-21 03:44:38 +03:00

7.4 KiB
Raw Blame History

Single Source of Truth — VPN-сеть Montana

Версия: 2026-05-19

Принцип

Вся канонически верифицируемая правда о состоянии VPN-сети живёт в одном append-only signed event log:

https://montana.quest/vpn/events.jsonl

Каждая строка — событие, индивидуально подписанное ed25519:

{"data":{...},"seq":N,"sig":"ed25519:...","ts":"2026-05-19T19:00:00Z","type":"node_register"}

Свойства:

  • Append-only: запись только в конец, прошлые события не переписываются.
  • Подписанные: каждое событие проверяется публичным ключом d9a8bf07871d35c8e85f7de4a9b62896c330ba0987732468515c7bda8bb4adde.
  • Монотонный seq: счётчик никогда не убывает, гэпы запрещены.
  • Pure-function state: state = replay(events).

Типы событий

type data когда
node_register {alias, ip, country, label} admin регистрирует узел через /vpn/node/register
node_deregister {alias, ip} узел остановлен (xray ExecStopPost)
node_online {alias, ip} orchestrator watchdog: probe OK после offline
node_offline {alias, ip} orchestrator watchdog: 2 probe fails подряд
unique_user {ip_hash} новый sha256(client_IP) в логе xray
metric произвольное периодические метрики (нагрузка, throughput)
checkpoint {seq_range, merkle} каждые 1000 событий (план)

Derived state

https://montana.quest/vpn/state.json — кешированный результат build_state(events). Любой может перепостроить и сравнить.

{
  "head_seq": 1502,
  "head_ts": "2026-05-19T19:25:30Z",
  "built_at": "...",
  "nodes": {
    "helsinki":  {"online": true, "ip": "91.132.142.42", "country": "FI", ...},
    "frankfurt": {"online": true, ...},
    "newyork":   {"online": true, ...}
  },
  "unique_users": 957,
  "unique_users_merkle": "...",
  "pubkey_hex": "d9a8bf07...",
  "event_log_url": "https://montana.quest/vpn/events.jsonl"
}

state.json rebuilds каждые 30 секунд через montana-state-builder.timer на Moscow.

Что НЕ публикуется

  • IP-адреса пользователей (это PII). В события unique_user идёт только sha256 IP — не обратимо без brute-force на 32-битное IPv4 пространство (~4 сек на rainbow tabe).
  • Чтобы усложнить brute-force, в roadmap — добавить secret salt с публикацией с задержкой 7 дней.

Архитектура emitters

                            ┌─────────────────────────┐
                            │  /opt/montana-vpn-stats │
                            │     /event_log.py       │
                            │    (sign + append)      │
                            └────────────┬────────────┘
                                         │
            ┌────────────────────────────┼────────────────────────────┐
            │                            │                            │
   orchestrator watchdog            xray-stats collector       admin /register
   (online/offline transitions)     (new unique IPs)            (manual events)
            │                            │                            │
            └────────────────────────────▼────────────────────────────┘
                                         │
                            /var/www/montana_quest/vpn/events.jsonl
                                         │
                                         ▼
                          montana-state-builder.timer (30s)
                                         │
                            /var/www/montana_quest/vpn/state.json
                                         │
                                         ▼
                  сайт + /vpn/sub + /vpn/node/uptime (читают state.json)

Гарантии

Гарантия Как доказывается
Число уникальных пользователей не подделано каждое событие unique_user подписано; state.json содержит merkle root; replay воспроизводит число
Узел не «фейково онлайн» переходы online↔offline — отдельные подписанные события с timestamp
История не переписана append-only; seq монотонный без гэпов; любой имеет полный лог
Нельзя backdate timestamp на каждом событии; запланировано daily anchoring через OpenTimestamps

Что НЕ гарантируется (пока)

  • Forced inclusion: мы можем замедлить добавление события в лог. Защита: автоматический rebuild каждые 30 секунд.
  • Privatekey compromise: если ключ утечёт, можно подделать события. Защита: privateKey 600 root на Moscow.
  • Tampering архивных событий: теоретически root доступом на Moscow можно переписать events.jsonl. Защита roadmap: ежедневный snapshot хеша всего лога в Bitcoin через OpenTimestamps — нельзя backdate.

Аудит

Любой может проверить single-source-of-truth:

bash Montana/Node/External-Audit/scripts/verify-state.sh

Этот скрипт:

  1. Скачивает events.jsonl и state.json.
  2. Проверяет ed25519-подпись каждого события.
  3. Проверяет монотонность seq без гэпов.
  4. Replay events до head_seq из state.json.
  5. Сравнивает результат replay со state.json: head_seq, unique_users, merkle root, nodes online/offline.

Если хотя бы один тест провалится — мы лжём.

Сейчас зелёные тесты

✓ все 1531 events подписаны валидно, seq непрерывен
✓ replay matches claimed state: head_seq=1502, nodes=3, unique_users=957
=== ВСЕ ПРОВЕРКИ ЗЕЛЁНЫЕ ===

Roadmap

  • P1: daily checkpoint в Bitcoin через OpenTimestamps. Дописать transparency.md.
  • P2: мульти-эмиттер — каждый узел независимо подписывает свои события + threshold-signature (2 of 3). Устраняет single trust на Moscow privateKey.
  • P3: GraphQL-like derivation API — клиенты запрашивают subset state через ?fields=....
  • P4: Public mirror лога на IPFS/GitHub raw — анти-цензура.