montana/Монтана-Протокол/Архив/Montana v19.0.0.md

1519 lines
98 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Montana — Спецификация протокола
**Версия:** 19.0.0 (2026-04-06 06:47 UTC)
## Определение
Montana — цифровой стандарт времени. Сеть независимых VDF-осцилляторов, поддерживающих единую верифицируемую временную шкалу с криптографическим доказательством каждого момента. Каждая зарегистрированная секунда = 1 TimeCoin (Ɉ).
NTP говорит «сейчас 14:32» — и ты доверяешь серверу. Montana говорит «сейчас 14:32, вот криптографическое доказательство, и вот что произошло в этот момент» — и ты проверяешь сам.
Основная функция — хронометраж. Вторичная — передача ценности.
Консенсус: **Proof of Time (PoT)** — три цепочки. TimeChain: глобальные часы (D последовательных SHA-256 = одно окно). NodeChain: персональная цепочка узла (доказательство присутствия при каждом тике). Account: состояние счёта. Влияние узла = длина его NodeChain. Протокол не использует время для консенсуса — протокол и есть ход времени, оцифрованный и криптографически верифицируемый.
Генезис: 09.01.2026 00:00:00 UTC.
Генезис-фраза: `«Кто контролирует прошлое, контролирует будущее. Кто контролирует настоящее, контролирует прошлое.» — Оруэлл, 1984`
---
## Три решённые проблемы
### 1. Децентрализованный хронометраж
**Проблема.** Существующие системы измерения времени (NTP, GPS, PTP) зависят от доверенной инфраструктуры. Компрометация сервера NTP или отключение спутника GPS нарушает временную шкалу для всех зависимых систем.
**Решение.** Децентрализованные часы — сеть независимых VDF-осцилляторов, в которой каждый узел вычисляет ход времени автономно через последовательное SHA-256 хэширование. Результат детерминирован и верифицируем любым участником без доверия к третьей стороне.
**Свойства.** Montana Time обладает четырьмя свойствами одновременно:
| Свойство | Определение | NTP | GPS | PTP | Montana |
|----------|------------|-----|-----|-----|---------|
| Монотонность | Время не идёт назад | нет | да | да | да |
| Консистентность | Все честные узлы согласны на одну шкалу | слабая | да | да | да |
| Верифицируемость | Любой может доказать прохождение интервала | нет | нет | нет | да |
| Независимость | Отсутствие серверов, спутников, доверенной инфраструктуры | нет | нет | нет | да |
Ни одна существующая система измерения времени не обеспечивает все четыре свойства.
### 2. Неплутократический консенсус
**Проблема.** В Proof of Work влияние пропорционально вычислительному бюджету. В Proof of Stake — капиталу. В обоих случаях безопасность сети является функцией концентрации ресурсов, приобретаемых на рынке.
**Решение.** Proof of Time — механизм консенсуса, в котором влияние узла определяется исключительно длительностью его непрерывного присутствия в сети, измеренной в подписанных временных окнах. Вес узла = длина его NodeChain (количество окон, в которых узел криптографически доказал своё присутствие).
**Свойства.**
- Время — единственный ресурс, который нельзя приобрести, передать, делегировать или сконцентрировать
- Два участника, запустившие узлы одновременно, имеют равный вес независимо от капитала
- Стоимость атаки на консенсус выражается не в валюте, а во времени, и растёт линейно с возрастом сети
### 3. Хронометрическая эмиссия
**Проблема.** Денежная политика фиатных валют определяется решениями комитетов и непредсказуема. Денежная политика Bitcoin предсказуема, но дефляционна — фиксированный потолок supply создаёт ожидание роста цены и подавляет использование как средства обмена.
**Решение.** Хронометрическая эмиссия — денежная политика, в которой скорость создания новых единиц привязана к физической константе — секунде — и неизменна на всём горизонте существования протокола. Одна секунда протокольного времени порождает одну монету.
**Свойства.**
- Supply в момент T = количество секунд, прошедших с генезиса
- Годовая инфляция монотонно убывает и асимптотически стремится к нулю как следствие арифметики, не изменения правил
- Эмиссия не контролируется ни одним участником, комитетом или голосованием
- Денежная политика полностью определена единственной константой и не может быть изменена после генезиса
### Следствие: цифровой стандарт времени
Три решённые проблемы порождают уникальную возможность. Любой документ, событие, состояние может быть записано в Montana с математически доказуемой привязкой к моменту верифицируемого времени. Anchor — 32 байта, навсегда. Ни одна существующая система не предоставляет timestamp, который одновременно децентрализован, неплутократичен и привязан к детерминированной денежной политике. Montana — не блокчейн с функцией timestamping. Montana — цифровой стандарт времени с функцией передачи ценности.
---
## Montana Time
VDF — цифровой аналог физического осциллятора. 9 192 631 770 колебаний цезия-133 = одна секунда SI. D последовательных SHA-256 = одно окно τ₁ Montana. Калибровка D каждые τ₂ — синхронизация цифрового осциллятора с физическим временем.
TimeChain — глобальные цифровые часы, поддерживаемые сетью узлов. Каждый узел тикает независимо через последовательное хэширование. Результат детерминирован — одни входные данные дают одну временную шкалу.
Токен — не награда за работу. Токен — тик часов, записанный в цепочку. Протокол не генерирует монеты — протокол регистрирует прошедшие секунды. Запись называется монетой.
### Четыре свойства
| Свойство | NTP | GPS | PTP | Montana |
|----------|-----|-----|-----|---------|
| Монотонность | нет | да | да | да |
| Консистентность | слабая | да | да | да |
| Верифицируемость | нет | нет | нет | да |
| Независимость | нет | нет | нет | да |
**Монотонность.** Время никогда не идёт назад. VDF последователен — каждый хэш зависит от предыдущего.
**Консистентность.** Все честные узлы согласны на одну временную шкалу. TimeChain детерминирован.
**Верифицируемость.** Любой может пересчитать VDF и доказать что заявленное время прошло.
**Независимость.** Каждый узел тикает сам. Нет серверов, спутников, доверенной инфраструктуры.
Montana — не эталон точности. Montana — эталон независимости.
### Точность
Гранулярность осциллятора: одно SHA-256 хэширование (зависит от аппаратуры: наносекунды — десятки наносекунд). Дрифт между калибровками (τ₂): единицы секунд за 14 дней. Калибровка D возвращает окно к целевым 60 секундам. Протокол самокорректируется.
### Time Oracle
TimeChain value в каждом proposal — верифицируемая временная метка. Внешние системы используют Montana Time:
- **Timestamping.** H(document) привязанный к TimeChain value = криптографическое доказательство существования в момент T.
- **Ordering.** Два события привязанные к разным TimeChain values имеют доказуемый порядок.
- **Anchoring.** Внешний протокол якорится в Montana Time для независимой верификации порядка событий.
### Протокольная дата
```
protocol_date(height) = genesis_timestamp + height × 60
```
Genesis: 09.01.2026 00:00:00 UTC (Unix: 1736380800). Proposal height 525 600 = ровно один год после генезиса. Калибровка D корректирует дрифт — протокольная дата отклоняется от UTC на единицы секунд за τ₂. Формула точна для любого height.
TimeChain хранится навсегда. Временные метки верифицируемы любым узлом в любой момент.
---
## Криптография
Четыре примитива с разделёнными ролями:
- **SHA-256** — консенсус (TimeChain, NodeChain), адреса, Merkle-деревья, хэширование
- **FN-DSA-512** (selected NIST candidate, forthcoming FIPS 206) — подписи операций аккаунтов
- **Pedersen commitments** (Ristretto group) — скрытие балансов и сумм
- **Bulletproofs** (Bünz et al. 2018) — range proofs и balance proofs без trusted setup
SHA-256 обеспечивает квантовую устойчивость консенсуса: алгоритм Гровера сокращает безопасность с 256 до 128 бит. FN-DSA-512 обеспечивает математическую постквантовую устойчивость подписей на основе NTRU-решёток. Pedersen commitments и Bulletproofs обеспечивают приватность транзакций — балансы, суммы и получатели скрыты, корректность верифицируема без раскрытия значений.
### Подписи — FN-DSA-512
Подпись на NTRU-решётках (Falcon-512). Stateless, многоразовая. Публичный ключ закрепляется за аккаунтом при создании и используется для всех последующих операций.
| Компонент | Размер |
|-----------|--------|
| Приватный ключ | 1 281B |
| Публичный ключ | 897B |
| Подпись (padded) | 666B |
Поле suite_id в формате блока обеспечивает миграцию подписи без изменения модели состояния. Активация новой схемы требует protocol upgrade. Активная схема на момент запуска: FN-DSA-512.
### Адреса
Формат: `mt` + Base58(account_id + checksum).
Account_id = SHA-256("mt-account" || suite_id || pubkey). Стабильный идентификатор аккаунта. Смена ключа или схемы подписи выполняется через ChangeKey без изменения account_id — для этого account_id привязан к первому pubkey, а текущий ключ хранится в состоянии аккаунта.
---
## Account Chain (Block Lattice)
Каждый аккаунт имеет собственную цепочку операций. Перевод — одна операция в цепочке отправителя. Зачисление получателю — детерминированно после финализации. Цепочки аккаунтов полностью независимы.
### Типы операций
**OpenAccount** — создание аккаунта (один раз):
```
type 1B
suite_id 2B
account_id 32B
pubkey 897B <- FN-DSA-512, публикуется единожды
signature 666B
Итого: ~1 598B
```
Аккаунт создаётся автоматически при первом входящем переводе. Отправитель указывает pubkey получателя в поле link, при финализации в Account Table создаётся запись с balance = link_amount. Приглашений не требуется. Как Bitcoin: адрес существует математически, в блокчейне появляется при первом зачислении.
**Transfer** — приватный перевод:
```
prev_hash 32B <- хэш предыдущей операции в цепочке аккаунта
sender_commitment 33B <- Pedersen commitment на account_id отправителя
link_commitment 33B <- Pedersen commitment на account_id получателя
amount_commitment 33B <- Pedersen commitment на сумму перевода
balance_commitment 33B <- Pedersen commitment на баланс после операции
ephemeral_pubkey 33B <- одноразовый ключ для stealth address получателя
encrypted_data 96B <- зашифровано для получателя: сумма, sender, blinding factors
flags 1B
signature 666B <- FN-DSA-512
range_proof 672B <- Bulletproof: amount >= 0, balance >= 0
balance_proof 64B <- proof: prev_commitment == balance + amount
Итого: ~1 696B
```
Скрыто: отправитель, получатель, сумма, баланс. Balance proof доказывает что prev_commitment == balance_commitment + amount_commitment без раскрытия скрытых значений.
**ChangeKey** — смена ключа или схемы подписи:
```
prev_hash 32B
account_id 32B
new_suite_id 2B
new_pubkey 897B <- новый публичный ключ
signature 666B <- подписано старым ключом
Итого: ~1 629B
```
**Anchor** — криптографический якорь (привязка данных ко времени):
```
prev_hash 32B <- хэш предыдущей операции в цепочке аккаунта
account_id 32B
app_id 32B <- SHA-256("mt-app" || app_name), пространство имён приложения
data_hash 32B <- хэш произвольных данных (Merkle root, H(document), ...)
signature 666B <- FN-DSA-512
Итого: ~796B
```
Anchor не перемещает средства и не требует комиссии. Единственная операция — запись data_hash в цепочку аккаунта с привязкой к timechain_value окна финализации.
### Верификация баланса
Балансы и суммы скрыты через Pedersen commitments. Верификация без знания значений:
```
balance_proof: prev_balance_commitment == new_balance_commitment + amount_commitment
range_proof: new_balance >= 0, amount > 0
```
Каждый узел проверяет Bulletproofs: commitments балансируются, все значения неотрицательны. Значения не раскрываются. Без trusted setup.
### Anti-inflation
Чеканка монет из воздуха невозможна. Два механизма:
**1. Commitment arithmetic.** Pedersen commitments гомоморфны: `C(a) + C(b) = C(a+b)`. Сумма всех balance_commitments в системе = commitment на общий supply. Каждый узел верифицирует: сумма всех commitments == commitment на supply(height). Если кто-то создал монеты — сумма не сходится.
**2. Supply audit.** `supply(height) = 60_000_000_000 × (height + 1) nɈ`. TimeCoin — единственный источник новых монет. TimeCoin публичен (в proposal header). Supply детерминирован по height. Расхождение = невалидный state.
### Перевод
Перевод на несуществующий account_id создаёт аккаунт получателя автоматически при финализации. Запись в Account Table: account_id, balance = link_amount, pubkey из OpenAccount (если есть) или из первого входящего перевода.
### TimeCoin (публичный слой)
Единственный публичный объект в системе переводов. Победитель τ₁ записывает прошедшее время: 60 Ɉ (60 зарегистрированных секунд).
TimeCoin **открыт**: сумма эмиссии, winner_node_id, height — публичные поля proposal header. Это чеканка новых монет — она должна быть верифицируема каждым узлом без криптографических proofs.
```
Публичное (верифицируемо всеми):
TimeCoin: 60 Ɉ за окно (константа)
Supply audit: supply(height) = 60_000_000_000 × (height + 1) nɈ
Winner: winner_node_id в proposal header
VDF: TimeChain values, NodeChain endpoints, подписи
Приватное (только участники):
Кто отправил перевод (sender_commitment)
Кому отправлен (link_commitment)
Сколько (amount_commitment)
Какой баланс (balance_commitment)
```
Supply audit: сумма всех TimeCoin от генезиса = supply(height). Чеканка открыта — нельзя напечатать из воздуха. Переводы закрыты — нельзя узнать кто кому сколько. Два слоя: публичная эмиссия + приватные опер<D0B5><D180>ции.
### Двойная трата
Каждый аккаунт имеет одну цепочку. Две операции с одним prev_hash = equivocation.
**Без конфликта:** операция → узлы валидируют → публикуют confirmation → quorum → финализирована. Cemented — необратимо.
**При конфликте (equivocation):**
1. Узел получает операцию X с prev_hash = H. Узел уже видел операцию Y с prev_hash = H, Y ≠ X. Форк обнаружен. Обе операции помечаются как equivocated.
2. Если одна операция уже cemented (quorum до обнаружения конфликта) — cemented необратимо. Вторая отклоняется.
3. Если ни одна не cemented — узлы продолжают собирать confirmations для обеих. Если одна набирает quorum → cemented, вторая отклоняется.
4. Если через 10 окон ни одна не набрала quorum → обе отклоняются окончательно. Аккаунт продолжает с последней cemented операции. Владелец отправляет новую операцию.
Equivocation создаётся только владельцем аккаунта (требуется подпись). Третья сторона не может создать equivocation для чужого аккаунта. Стимул: двойная трата = потеря обеих операций.
### Антиспам
Ноль комиссий — антиспам через время. Право на операцию = доказанное время существования аккаунта.
#### Приоритет операции
```
account_age = current_window - creation_window
priority(op) = account_age × windows_since_last_op
```
`account_age` — возраст аккаунта в окнах. Растёт линейно. Некупуемый. `windows_since_last_op` — окна с последней операции аккаунта. Сбрасывается при каждой операции. Спамер обнуляет приоритет с каждой операцией — самонаказание.
При переполнении ёмкости сети — операции с наименьшим приоритетом ожидают следующего окна.
#### Бакеты по account_age
Изоляция спама. Round-robin по бакетам при формировании набора операций: одна операция из бакета 0, одна из бакета 1, ..., по кругу. Спам в бакете 0 не вытесняет операции из бакетов 1-3.
```
Бакет 0: account_age < 4τ₂ 1 операция за τ₁
Бакет 1: account_age 4τ₂ — 16τ₂ 4 операции за τ₁
Бакет 2: account_age 16τ₂ — 64τ₂ 16 операций за τ₁
Бакет 3: account_age 64τ₂+ 64 операции за τ₁
```
Границы бакетов = 4^N × τ₂. Квота = 4^N операций за τ₁. Одна формула.
Новый аккаунт — бакет 0 с момента создания. 1 операция в минуту. Вход без ожидания: получил перевод → сразу можешь отправить.
#### Квота
Жёсткий потолок операций аккаунта за одно окно τ₁. Превышение квоты → операция невалидна → не ретранслируется. Не приоритизация — запрет.
Спамер с 1000 новых аккаунтов: 1000 операций за τ₁ в бакете 0. Бакет 0 получает 1/4 от round-robin. Изолирован. Аккаунты в бакетах 1-3 не замечают.
---
## Состояние сети
Глобальное состояние = Account Table + Node Table.
```
Account Table (запись на аккаунт):
account_id 32B
balance_commitment 33B <- Pedersen commitment на баланс (значение скрыто)
frontier_hash 32B <- хэш последней операции в цепочке
op_height 4B <- количество операций в цепочке
suite_id 2B
current_pubkey 897B
phone_hash 32B <- SHA-256("mt-phone" || phone), 0x00 если не привязан
creation_window 4B <- окно создания аккаунта (первый входящий перевод)
last_op_window 4B <- окно последней операции (для приоритета)
Node Table (запись на узел):
node_id 32B <- SHA-256("mt-node" || node_pubkey), верифицируемо
node_pubkey 897B
suite_id 2B
start_window 4B <- окно регистрации (первое окно NodeChain)
pending_invite 32B <- node_id приглашённого узла (0x00..00 если нет)
invite_window 4B <- окно финализации NodeInvitation (0 если нет)
invite_expires 4B <- invite_window + 21 160 (0 если нет)
```
### State Root
Merkle-дерево глобального состояния. Два подкорня с разным ритмом обновления:
```
state_root = SHA-256("mt-merkle-node" || account_root || node_root)
node_root: Merkle root Node Table, обновляется каждый τ₁ (control_set + expiry)
account_root: Merkle root Account Table, обновляется на границе τ₂ (checkpoint)
Account Table Root: листья по account_id (лексикографически)
Node Table Root: листья по node_id (лексикографически)
Каждый узел в Node Table — участник сети. Узел существует в таблице = участвует.
```
Все sort keys фиксированной длины. Побайтовое лексикографическое сравнение. Две реализации с одинаковыми данными строят одинаковое дерево и получают одинаковый State Root.
State Root коммитится в заголовке каждого финализированного proposal τ₁. Между τ₂ — `node_root` пересчитывается каждый τ₁, `account_root` frozen (одинаков во всех proposals τ₂-периода).
#### τ₂ Account Root Checkpoint
На границе τ₂ (первый proposal нового τ₂-периода) `account_root` пересчитывается:
```
account_root_cutoff = τ₂_boundary_window - 100
account_root = MerkleRoot(Account Table по состоянию на account_root_cutoff)
```
Cutoff = 100 окон до boundary (~100 минут). За 100 минут любая операция гарантированно cemented у всех узлов. Все узлы вычисляют одинаковый account_root из одинакового набора cemented операций. Детерминирован.
#### Pruning
На τ₂ boundary вместе с пересчётом account_root:
```
Удалить все записи Account Table где:
balance_commitment == C(0) <- нулевой баланс (каноничное значение)
AND last_op_window + 4τ₂ <= current_window <- нет активности 4τ₂ (56 дней)
```
Пустой аккаунт без активности 56 дней — удаляется. Воссоздание: новый входящий Transfer → аккаунт создаётся заново. При нулевом балансе balance_commitment устанавливается в каноничное C(0) с r=0. Pruning детерминирован, автоматичен, каноничен.
---
## Двигатели
Три цепочки с односторонним потоком зависимостей: TimeChain → NodeChain → Account.
### TimeChain VDF — осциллятор
Первичный продукт протокола. Непрерывная последовательная SHA-256 цепочка — цифровой осциллятор Montana Time:
```
T_r = SHA-256^D(T_{r-1})
```
D — количество последовательных хэшей за одно окно τ₁. Каждый хэш — один тик осциллятора. D хэшей — одно колебание. TimeChain продвигается по расписанию окон. Для фиксированного индекса r значение T_r совпадает у всех честных узлов. Каждый узел вычисляет TimeChain независимо — результат детерминирован.
TimeChain не зависит от состояния, транзакций и поведения отдельных узлов. Даже при отказе всего Account слоя часы продолжают тикать.
### NodeChain — персональная цепочка узла
Криптографическое доказательство присутствия конкретного node_id при каждом тике часов. Якорится в TimeChain каждое окно:
```
S_{i,s,0} = SHA-256(S_{i,s-1,m} || T_s || node_id_i)
S_{i,s,j+1} = SHA-256(S_{i,s,j}) для j = 0..m-1
```
Три компонента seed: предыдущий endpoint (непрерывность цепочки), значение TimeChain (протокольное время), node_id (идентичность). m последовательных хэшей за окно — одно звено NodeChain.
Инициализация: для первого окна нового узла предыдущий endpoint отсутствует. NodeChain init привязан к каноническим данным proposal в котором NodeInvitation финализирован:
```
S_{i,0,0} = SHA-256("mt-nodechain-init" || control_root || timechain_value || node_id_i)
```
control_root и timechain_value из proposal header окна финализации Invitation. Оба канонические (не зависят от субъективного user_set). Предвычисление VDF невозможно — timechain_value неизвестен до закрытия окна. Grinding surface = ноль. Верифицируем любым узлом.
NodeChain зависит от TimeChain. TimeChain не зависит от NodeChain.
### VDF Reveal и лотерея
После закрытия окна τ₁ каждый узел вычисляет свой ticket:
```
ticket_i = -ln(endpoint_i / 2^256)
```
Если ticket < target узел является кандидатом и публикует reveal. Остальные узлы молчат.
```
VDF_Reveal:
node_id 32B
window_index 4B <- индекс τ₁
endpoint 32B <- S_{i,s,m}
start_window 4B <- окно начала NodeChain (для верификации)
signature 666B <- FN-DSA-512, подписано node_pubkey
Итого: ~738B
```
Target калиброван на ~12 кандидатов за окно. Из кандидатов побеждает lowest ticket. Калибровка target на τ:
```
target_new = target_old × (12 / actual_candidates_per_window)
actual_candidates_per_window = total_candidates_за_τ₂ / 20 160
```
Reveal публикуется только кандидатами. Трафик за окно: ~12 reveals × 738B 8.9 KB. При любом количестве узлов.
Валидация reveal при получении:
1. Подпись FN-DSA-512 соответствует node_pubkey из Node Table
2. window_index = только что закрытый τ
3. node_id существует в Node Table
4. ticket < target
5. endpoint верифицируем: пересчёт NodeChain VDF от предыдущего endpoint
### Account — содержимое блока
Приём, верификация объектов и формирование набора. Два класса объектов:
**UserObjects** пользовательские операции:
| Тип | Описание | Валидация |
|-----|----------|-----------|
| Transfer | Приватный перевод | FN-DSA-512 подпись, Bulletproofs валидны, prev_hash. Если получатель не существует создаётся автоматически |
| OpenAccount | Публикация ключа | FN-DSA-512 подпись, account_id существует в Account Table (создан входящим переводом) |
| ChangeKey | Смена ключа | FN-DSA-512 подпись старым ключом, new_pubkey |
| Anchor | Якорь данных ко времени | FN-DSA-512 подпись, prev_hash, app_id = 32B, data_hash = 32B |
| PhoneLink | Привязка телефона | FN-DSA-512 подпись, phone_hash = 32B |
**ControlObjects** объекты управляющие составом сети:
| Тип | Описание | Валидация |
|-----|----------|-----------|
| NodeInvitation | Приглашение нового узла | FN-DSA-512 подпись пригласившего, pending_invite = 0 |
| NodeRegistration | Регистрация узла | FN-DSA-512 подпись, node_id уникален, proof_endpoint верифицируем через VDF, приглашение существует |
Каждый узел валидирует объекты обоих классов локально при получении. Валидные объекты ретранслируются по P2P.
UserObjects финализируются непрерывно через подтверждения (67% online chain_length). ControlObjects включаются в proposal победителем τ (каноничен).
#### Proposal
Proposal содержит только **control_set** и метаданные окна. UserObjects финализируются непрерывно через подтверждения, не через proposal.
**control_set** = все валидные ControlObjects полученные по P2P до control_cutoff, не финализированные ранее и не истёкшие. Каноничен все ControlObjects включены ровно один раз. Пропуск или добавление лишнего ControlObject = невалидный proposal = fallback.
Порядок внутри control_set: H(object) лексикографически (каноничен, не зависит от победителя).
Форки аккаунтов (две операции с одним prev_hash) разрешаются голосованием узлов весом chain_length. 67% online chain_length за одну операцию побеждает (см. раздел «Двойная трата»).
#### Дедлайн в окне
```
|-------- τ₁ (60 сек) --------|--- R (12 сек) ---|
^
reveal_cutoff = control_cutoff
(R сек после закрытия)
```
- **reveal_cutoff** = control_cutoff = R секунд после закрытия окна. VDF_Reveal и ControlObjects принимаются до этого момента.
R, F калибруются в τ (см. раздел «Калибровка R, F»). Генезис: R = 12s, F = 12s.
После reveal_cutoff: определяется победитель лотереи, победитель собирает proposal.
#### Proposer
Победитель собирает proposal:
- **control_set**: все ControlObjects до control_cutoff (каноничен, свобода = ноль)
- **State Root snapshot**: состояние после применения всех финализированных операций за окно
Свобода proposer: ноль. Control_set каноничен. State Root детерминирован каждый узел применяет одни и те же финализированные операции и получает один и тот же результат.
Proposal с невалидным ControlObject, пропущенным ControlObject или неверным state_root отклоняется, переход ко второму месту.
#### Финальность proposal
Финальность proposal = подпись победителя на proposal header + независимая верифицируемость.
1. Победитель публикует подписанный proposal header + control_set
2. Каждый узел проверяет ControlObjects по правилам валидации
3. Каждый узел применяет control_set + TimeCoin детерминированно
4. Каждый узел сравнивает вычисленный state_root с заявленным в proposal
5. Совпадает proposal принят
6. Не совпадает proposal отклонён, fallback на второе место
Финальность операций аккаунтов отдельный процесс через подтверждения (67% online chain_length), не через proposal.
Proposal header:
```
Proposal header:
prev_proposal_hash 32B
control_root 32B <- Merkle root control_set (каноничен)
node_root 32B <- Merkle root Node Table (обновляется каждый τ₁)
account_root 32B <- Merkle root Account Table (frozen между τ₂, обновляется на τ₂ boundary)
new_state_root 32B <- SHA-256(node_root || account_root)
timechain_value 32B
winner_endpoint 32B <- NodeChain endpoint победителя
timecoin_hash 32B
winner_node_id 32B
target 8B <- текущий target лотереи
wall_clock 8B <- секунды с генезиса (локальное измерение победителя)
fallback_depth 1B <- 1 = первое место, 2+ = fallback
signature 666B <- FN-DSA-512, подписано node_pubkey победителя
```
Fallback: если proposal победителя (lowest ticket) не получен в пределах timeout (F секунд после reveal_cutoff) или отклонён proposal формирует следующий кандидат по ticket. Молчание победителя = потерянный TimeCoin за это окно. F калибруется в τ (см. раздел «Калибровка R, F»).
#### Непрерывность VDF
VDF следующего окна вычисляется непрерывно, не ожидая завершения финализации предыдущего. TimeChain для окна N+1 детерминирован каждый узел вычисляет его независимо. NodeChain для окна N+1 стартует сразу после закрытия окна N, используя собственный endpoint текущего окна и новое значение TimeChain. Reveal phase и финализация происходят параллельно с началом VDF следующего окна.
#### Confirmations (финализация операций)
При получении валидной операции аккаунта узел публикует confirmation:
```
Confirmation:
node_id 32B
op_hash 32B <- хэш операции
signature 666B
```
Операция финализирована когда подтверждения от узлов с суммарным chain_length > quorum. Cemented — необратимо. Типичное время: ~0.3 секунды (P2P propagation + сбор подтверждений).
```
quorum = max(67% × online_chain_length, 50% × total_chain_length)
online_chain_length = сумма chain_length узлов, опубликовавших
хотя бы одно подтверждение за последние 10 окон
total_chain_length = Σ(current_window - start_window) для всех узлов в Node Table
```
67% online — нормальный режим. 50% total — абсолютный минимум (детерминирован, вычисляется из канонических данных Node Table). При online < 50% total операции не финализируются (сеть приостановлена by design).
#### State transition
Два параллельных процесса обновления состояния:
**Непрерывная финализация операций:** при достижении 67% online chain_length операция применяется к Account Table немедленно:
```
Transfer: обновить balance_commitment отправителя и получателя.
Если получатель не существует — создать запись в Account Table.
OpenAccount: записать pubkey в Account Table.
ChangeKey: обновить pubkey и suite_id в Account Table.
Anchor: записать data_hash в цепочку аккаунта.
PhoneLink: записать phone_hash в Account Table.
```
**State transition в proposal:** при финализации proposal применяется атомарно:
```
apply_proposal(state, proposal) -> state':
Шаг 1: применить control_set в порядке H(object) лексикографически.
NodeInvitation: записать pending_invite, invite_window и invite_expires в Node Table пригласившего.
NodeRegistration: проверить приглашение, создать запись в Node Table. Очистить pending_invite пригласившего.
Шаг 2: применить TimeCoin победителя.
Шаг 3: обработать expiry.
Приглашения узлов: все записи Node Table где invite_expires <= current_window
и invite_expires > 0 -> очистить pending_invite, invite_window и invite_expires.
Шаг 4: вычислить node_root (после control_set + TimeCoin + expiry).
account_root = frozen (из предыдущего τ₂ checkpoint, или пересчитан если τ₂ boundary).
new_state_root = SHA-256(node_root || account_root).
```
Порядок детерминирован. Каждый узел применяет одни и те же шаги и получает один и тот же new_state_root.
Account зависит от TimeChain и NodeChain. Обратных зависимостей нет.
С ростом TPS сети дополнительные ядра подключаются для верификации операций. Минимум для валидатора: 3 логических ядра (TimeChain + NodeChain + Account). Один узел = 3 ядра. 50 ядер = 16 узлов. Верификация операций аккаунтов полностью параллелизуется цепочки аккаунтов независимы.
### Приглашение и регистрация
Два уровня входа в сеть. Узлы участвуют в консенсусе приглашение + 14 дней VDF. Аккаунты держат и переводят средства создаются автоматически при первом входящем переводе.
Генезис: 12 узлов в разных локациях (hardcoded, аналог bootstrap nodes в Bitcoin).
#### Приглашение узла (NodeInvitation)
Вход узла в консенсус. Приглашение + 14 дней VDF + регистрация. Одновременно одно приглашение узла на пригласившего.
```
NodeInvitation:
inviter_node_id 32B
invited_pubkey 897B <- публичный ключ приглашённого узла
signature 666B <- подписано inviter node_pubkey
Итого: ~1 595B
```
NodeInvitation ControlObject. Не содержит start_window определяется при финализации.
Валидация:
1. Подпись валидна для inviter node_pubkey из Node Table
2. inviter существует в Node Table
3. inviter pending_invite = 0x00..00 (нет активного приглашения узла)
4. invited node_id = SHA-256("mt-node" || invited_pubkey) не существует в Node Table
При финализации в proposal P окна W:
- inviter pending_invite = invited node_id
- inviter invite_window = W
- inviter invite_expires = W + 21 160 (20 160 окон + 1 000 окон запас)
#### Привязка NodeChain к моменту приглашения
Первое звено NodeChain приглашённого узла привязано к каноническим полям proposal в котором NodeInvitation финализирован:
```
nodechain_init = SHA-256("mt-nodechain-init" || control_root || timechain_value || node_id)
```
control_root и timechain_value канонические поля из proposal header окна финализации. Не зависят от субъективного user_set победителя. Предвычисление VDF невозможно: timechain_value неизвестен до закрытия окна.
Приглашённый узел узнаёт control_root и timechain_value только увидев финализированный proposal вычисляет nodechain_init начинает NodeChain с окна W+1.
#### Регистрация узла
Приглашённый узел после финализации NodeInvitation:
1. Наблюдает proposal с NodeInvitation получает control_root и timechain_value
2. Вычисляет nodechain_init = SHA-256("mt-nodechain-init" || control_root || timechain_value || node_id)
3. Непрерывно строит NodeChain: 20 160 окон подряд (от W+1 до W+20 160), каждое звено якорится в соответствующий TimeChain
4. Через ~14 дней получает proof_endpoint = S_{i,20159,m}
5. Публикует NodeRegistration
```
NodeRegistration:
type 1B
suite_id 2B
node_pubkey 897B <- FN-DSA-512 ключ узла
inviter_node_id 32B <- кто пригласил
proof_endpoint 32B <- S_{i,20159,m} (endpoint после 20 160 окон VDF)
signature 666B <- подписано node_pubkey
Итого: ~1 630B
```
NodeRegistration ControlObject.
Валидация NodeRegistration:
1. Подпись FN-DSA-512 валидна для node_pubkey
2. node_id уникален (не существует в Node Table)
3. inviter_node_id существует в Node Table, pending_invite = node_id
4. invite_window + 20 160 < текущее окно (VDF завершён)
5. Восстановить control_root и timechain_value из proposal окна invite_window
6. Вычислить nodechain_init = SHA-256("mt-nodechain-init" || control_root || timechain_value || node_id) из proposal окна invite_window
7. proof_endpoint верифицируем: пересчёт VDF от nodechain_init через 20 160 окон с якорением в TimeChain значения от invite_window+1
Верификация: 20 160 сегментов VDF проверяются параллельно. На C ядрах: ~(20 160/C) × t_segment.
При финализации: создать запись в Node Table (start_window = текущее окно). Очистить pending_invite, invite_window и invite_expires у пригласившего.
#### Истечение приглашения узла
Если NodeRegistration не финализирован до invite_expires (invite_window + 21 160) приглашённый не завершил VDF. При обработке state transition: pending_invite, invite_window, invite_expires пригласившего очищаются автоматически. Узел может приглашать снова.
#### Создание аккаунта
Аккаунт не требует приглашений. Пользователь генерирует FN-DSA-512 keypair вычисляет account_id = SHA-256("mt-account" || suite_id || pubkey) получает адрес. Аккаунт появляется в Account Table при первом входящем переводе. Как Bitcoin: адрес существует математически, в блокчейне при первом зачислении.
Sybil-барьер для аккаунтов: account_age (возраст аккаунта) определяет квоту операций. Новый аккаунт бакет 0, максимум 1 операция за τ₁. Рост квоты = время. Пустые аккаунты бесполезны без баланса ничего не делают.
#### Скорость роста сети
Узлы: каждый узел производит максимум одно приглашение узла за ~14 дней. Рост ограничен текущим размером сети:
```
Генезис: 12 узлов
14 дней: 24
28 дней: 48
1 год: до 12 × 2^26 (~800M, теоретический максимум)
```
Аккаунты: без ограничений. Любой владелец TimeCoin может создать аккаунт любому, переведя средства на новый адрес. Рост пользовательской базы не ограничен протоколом.
Аппаратный бюджет сверх количества приглашений узлов бесполезен. 1000 узлов = максимум 1000 новых узлов за 14 дней, независимо от количества ядер.
---
## Потоковая модель
Операции аккаунтов текут непрерывно. Узел получает операцию проверяет подпись FN-DSA-512 и баланс публикует confirmation передаёт в P2P gossip.
Операция финализируется при получении подтверждений от узлов с суммарным chain_length > 67% online chain_length. Типичное время: ~0.3 секунды. Cemented — необратимо.
Два параллельных процесса:
- **Операции** финализируются непрерывно через подтверждения (не ждут окна)
- **Часы** тикают по расписанию окон τ₁ (TimeChain, NodeChain, лотерея, TimeCoin)
Кошелёк получателя отображает входящий перевод после финализации (~0.3 секунды). Одно состояние: «финализирован».
Цепочки аккаунтов полностью независимы. Операции разных аккаунтов обрабатываются параллельно без конфликтов.
---
## Временные слои (τ)
```
τ₁ (60с) → τ₂ (20 160 × τ₁ ≈ 14 дней)
```
Одно окно — τ₁. Всё остальное — производные.
### τ₁ — Окно (60 секунд)
Единственная единица протокольного времени. Регистрация времени и эмиссия.
- TimeChain продвигается на D хэшей
- NodeChain продвигается на m хэшей с якорем в текущем T_s
- Операции аккаунтов финализируются непрерывно через подтверждения (параллельно с окном)
- control_set: все валидные ControlObjects до control_cutoff (каноничен)
- Кандидаты (~12) раскрывают NodeChain endpoint (reveal phase, R = 12 секунд)
- Лотерея: `ticket_i = -ln(endpoint_i / 2^256)`, победитель = lowest ticket среди кандидатов
- Победитель публикует подписанный proposal
- Финальность proposal: подпись победителя на proposal header. Каждый валидатор применяет control_set + TimeCoin детерминированно и проверяет new_state_root
- TimeCoin: запись прошедшего времени (60 Ɉ = 60 секунд) → победителю
- Supply audit: суммарная эмиссия TimeCoin от генезиса сверяется с supply(height) из issuance schedule
- Разрешение форков: приоритет ветки с наибольшим суммарным TimeChain-доказательством
TimeChain safety: компрометация значения TimeChain требует нарушения свойства последовательности SHA-256 VDF.
TimeChain liveness: задержка продвижения TimeChain невозможна — TimeChain вычисляется каждым узлом независимо.
### τ₂ — Адаптация (20 160 × τ₁ ≈ 14 дней)
- Калибровка D и m (см. ниже)
- Калибровка R, F (см. ниже)
- Account Root checkpoint: пересчёт account_root в первом proposal нового τ₂. Cutoff = boundary - 100 окон. Детерминирован
- Pruning: удаление пустых аккаунтов без активности 4τ₂ (56 дней)
- Supply audit: сумма всех balance_commitments == commitment на supply(height)
- Криптографическая амнезия: подписанные proposals сохраняются навсегда — верифицируемая цепочка state commitments. Proposals доказывают что конкретное состояние было закоммичено победителем; восстановление содержимого состояния требует snapshot или архива
- Пересчёт параметров размера окна τ₁
#### Калибровка D и m
Каждый proposal содержит `wall_clock` — секунды с генезиса по локальным часам победителя. Одно измерение субъективно. Медиана 20 160 измерений за τ₂ — распределённый эталон.
Валидация wall_clock при получении proposal:
```
wall_clock > prev_proposal.wall_clock (монотонность)
wall_clock < prev_proposal.wall_clock + 2 × 60 (не более 2× target вперёд)
```
Формула пересчёта D на границе τ₂:
```
intervals[i] = proposal[i].wall_clock - proposal[i-1].wall_clock
для i = 1..20 159
actual_interval = median(intervals)
target_interval = 60
D_new = D_old × target_interval / actual_interval
D_new = clamp(D_new, D_old × 0.5, D_old × 1.5)
```
Формула точная — D корректируется ровно пропорционально отклонению. Страховочный clamp ±50% защищает от чёрного лебедя (массовый выход узлов, аппаратная революция). При нормальной работе отклонение медианы от 60 секунд — единицы секунд, коррекция D — единицы процентов.
Медиана > 60 → окна медленнее цели → D слишком велик → уменьшить. Медиана < 60 окна быстрее D увеличить.
m калибруется пропорционально: `m_new = m_old × (D_new / D_old)`.
Генезис: D и m калибруются при запуске для целевых 60 секунд. Абсолютный якорь: 09.01.2026 00:00:00 UTC. Медиана 20 159 интервалов для сдвига необходим контроль >50% proposals (>50% веса сети).
#### Калибровка R, F
Входные данные — из proposals за τ₂ (канонические, детерминированно вычисляются всеми узлами):
```
fallback_ratio = count(fallback_depth > 1) / 20160
```
Формула пересчёта:
```
R_new = clamp(R_old × fallback_ratio / fallback_target, R_old × 0.8, R_old × 1.2)
R_new = clamp(R_new, R_min, R_max)
F_new = clamp(F_old × fallback_ratio / fallback_target, F_old × 0.8, F_old × 1.2)
F_new = clamp(F_new, F_min, F_max)
```
Протокольные константы:
```
fallback_target = 5%
R_min = 4s, R_max = 30s
F_min = 4s, F_max = 30s
```
Генезис: R₀ = 12s, F₀ = 12s.
---
## Консенсус — Proof of Time (PoT)
### Три цепочки
**TimeChain** — глобальные часы. Чистая VDF-цепочка `T_r = SHA-256^D(T_{r-1})`. Первичный продукт протокола. Источник времени и случайности. Продвигается по расписанию окон.
**NodeChain** — персональная цепочка узла. VDF-цепочка конкретного node_id, якорится в TimeChain каждое окно. Доказывает непрерывную работу узла.
**Account** — состояние счёта. Операции финализируются непрерывно через подтверждения (67% online chain_length). ControlObjects включаются в proposal (каноничен).
Зависимости односторонние: TimeChain → NodeChain → Account. Отказ в Account не останавливает часы. Отказ конкретного узла в NodeChain не заражает общий ритм.
### Лотерея
Каждый узел = равный шанс за одно окно. После закрытия окна τ₁ каждый узел вычисляет ticket из своего NodeChain endpoint:
```
ticket_i = -ln(endpoint_i / 2^256)
```
Если ticket < target узел является кандидатом. Target калиброван на ~12 кандидатов за окно. Из кандидатов побеждает lowest ticket.
Стимул работать непрерывно: каждое окно = одна попытка. Узел онлайн 365 дней = 525 600 попыток. Узел онлайн 1 день = 1 440 попыток. Больше попыток = больше побед = больше TimeCoin.
### Победитель τ₁
Победитель определяется после закрытия окна τ₁. Кандидаты (~12 из всей сети) публикуют reveal. Lowest ticket = победитель.
Победитель:
- Записывает TimeChain value
- Получает 60 Ɉ TimeCoin (единственный доход)
- Коммитит State Root (snapshot финализированных операций за окно)
- Включает ControlObjects в proposal (каноничен)
Победитель публикует подписанный proposal: control_set + State Root snapshot + TimeCoin. Валидация: control_set полон, все объекты валидны, state_root корректен. Финальность proposal подпись победителя на proposal header. Верификация независимый пересчёт state_root.
### Верификация
Победитель публикует: `{node_id, NodeChain endpoint, proposal}`.
Верификация NodeChain за одно окно: пересчёт m хэшей. Параллелизация по сегментам время верификации обратно пропорционально числу ядер.
Верификация proposal: независимое применение control_set + TimeCoin и сравнение state_root.
### Устойчивость
- **Остановка часов** исключена: каждый узел тикает независимо
- **Искажение часов** исключено: VDF последователен, результат детерминирован
- **Proposer grinding** исключён: control_set каноничен, state transition детерминирован, операции финализируются независимо от победителя
- **Front-running** исключён: операции финализируются через подтверждения (~0.3s), не через proposal победителя
- **Предвычисление** исключено: seed содержит текущее значение TimeChain
- **Replay** исключён: TimeChain уникален для каждого τ
- **Аппаратное преимущество** ограничено: последовательное хэширование масштабируется тактовой частотой, не количеством ядер
- **Sybil-барьер**: приглашение (1 инвайт на узел, 1 одновременно) + 14 дней VDF + 3 ядра на узел
- **Цензура операций** исключена: операции финализируются через подтверждения узлов, не через победителя
- **Цензура ControlObjects** исключена: control_set каноничен, пропуск = fallback
- **Liveness halt операций** исключён: финализация через 67% online chain_length, не зависит от победителя
- **Liveness halt proposals** исключён: fallback на следующего кандидата
- **Масштабирование**: трафик лотереи ~8.9 KB за окно при любом количестве узлов
### Разрешение конфликтов
**Двойная операция аккаунта** (две операции с одним prev_hash): equivocation. Cemented до обнаружения необратимо, вторая отклоняется. Не cemented ожидание quorum 10 окон, затем обе отклоняются. См. раздел «Двойная трата».
**Невалидный proposal**: валидаторы отклоняют, fallback на следующего кандидата. Победитель теряет TimeCoin за это окно.
**Два proposal от одного победителя**: оба отклоняются, fallback. Победитель теряет TimeCoin.
---
## Адреса и переводы
### Полный флоу перевода
```
1. Боб: кошелёк генерирует keypair -> account_id (постоянный адрес, существует математически)
2. Боб -> Алисе: "отправь на mt4ZGfe..." (account_id)
3. Алиса формирует Transfer в своей цепочке:
prev_hash: хэш её предыдущей операции
link: account_id Боба
link_amount: 50 Ɉ
balance: 50 Ɉ (100 - 50)
4. Алиса подписывает FN-DSA-512
5. Алиса рассылает операцию узлам сети
6. Каждый узел проверяет:
FN-DSA-512 подпись валидна для pubkey Алисы
prev_hash совпадает с frontier Алисы
balance >= 0
link_amount > 0
7. Узлы публикуют confirmations, операция распространяется через P2P gossip
8. 67% online chain_length подтвердили → финализирована (~0.3 секунды)
Баланс Алисы: 50 Ɉ
Если Боб новый — создать запись в Account Table (balance = 50 Ɉ)
Если Боб существует — баланс увеличен на 50 Ɉ (детерминированно)
Кошелёк Боба: «финализирован»
```
### Баланс
Баланс аккаунта одно число в таблице аккаунтов. Обновляется при финализации операции: исходящие переводы (из Transfer отправителя) и входящие зачисления (детерминированно по финализированным операциям).
Бэкап = seed (для деривации приватного ключа FN-DSA-512).
---
## Эмиссия
### Единица
Монета: **TimeCoin** (тикер: $TimeCoin, символ: Ɉ).
1 секунда = 1 TimeCoin = 1 Ɉ = 1 000 = 1 000 000 μɈ = 1 000 000 000
60 секунд = 1 минута = 60 TimeCoin
3 600 секунд = 1 час = 3 600 TimeCoin
86 400 секунд = 1 день = 86 400 TimeCoin
Одно окно τ регистрирует 60 прошедших секунд = 60 TimeCoin.
Точность: 9 знаков после запятой (наносекунда). Все расчёты эмиссии в (целочисленная арифметика, без плавающей точки).
### Issuance schedule
Одна секунда протокольного времени порождает одну монету. С первого блока и навсегда.
| Параметр | Значение |
|----------|----------|
| Генезис | 09.01.2026 00:00:00 UTC |
| TIME_RECORD | 60 000 000 000 (60 Ɉ) |
### Регистрация времени
```
time_record(height) = 60_000_000_000 nɈ
```
Каждое окно τ регистрирует 60 прошедших секунд = 60 Ɉ. Без халвингов, без фаз, без исключений. Одна константа на весь горизонт существования протокола.
### Supply audit
```
supply(height) = 60_000_000_000 × (height + 1) nɈ
```
Одно умножение. Проверяемо каждым узлом в каждом τ₁. O(1).
### Инфляция
Supply растёт линейно. Инфляция снижается асимптотически к нулю константная эмиссия делится на растущий supply:
```
Год 1: 100%
Год 2: 50%
Год 5: 20%
Год 10: 10%
Год 50: 2%
Год 100: 1%
Год 1000: 0.1%
```
### Раннее участие
Эмиссия постоянна: 60 TimeCoin за каждое окно, с первого блока и навсегда. Вероятность победы пропорциональна весу. Узел, работающий дольше, побеждает чаще. Два узла запустившиеся одновременно имеют равные шансы независимо от капитала. Узел запустившийся раньше имеет преимущество он доказал больше времени.
Стимул для ранних участников встроен в арифметику: не бонусы, не множители просто больший вес.
### Распределение
Победитель τ записывает прошедшее время и получает 60 Ɉ TimeCoin в своей цепочке. Одно правило. Неизменно с генезиса.
Базовый бюджет: 60 Ɉ/τ (запись 60 секунд). Реальный бюджет безопасности в покупательной способности зависит от рынка.
1 TimeCoin = 1 секунда описывает скорость хода часов. Не ценовой peg, не гарантия покупательной способности.
---
## Пропускная способность
Размер Transfer: ~1 696B (приватный перевод с Bulletproofs).
| Канал узла | TPS |
|-----------|-----|
| 10 Mbps | ~1 620 |
| 100 Mbps | ~16 200 |
| 1 Gbps | ~162 000 |
### Адаптивный размер окна
Пересчёт в τ:
- Заполненность > 80% → увеличение размера окна
- Заполненность < 20% уменьшение размера окна
- Шаг: ±20% за τ
- Диапазон: 1 MB 100 MB
---
## Хранение
### Модель: глобальное состояние + локальная история
Узлы хранят глобальное состояние (Account Table, Node Table, proposals). Тела операций аккаунтов хранятся у владельцев. После финализации state transition применён commitment в таблице обновлён, тело операции сети больше не нужно.
### Три уровня участников
**Узел (валидатор)** десктоп или сервер, 24/7, минимум 3 ядра (1 узел = 3 ядра, 50 ядер = 16 узлов):
```
Хранит:
Account Table (commitments, frontier_hash, pubkey, phone_hash)
Node Table (node_id, pubkey, start_window, invites)
Proposals (навсегда)
Blob Buffer (зашифрованные сообщения для владельца, TTL = τ₂)
Делает:
TimeChain VDF (1 ядро, 24/7)
NodeChain VDF (1 ядро, 24/7)
Валидация операций (1+ ядро)
P2P gossip (операции, confirmations, reveals, proposals)
Почтовый ящик (хранит сообщения для своего владельца пока тот офлайн)
```
**Кошелёк (клиент)** телефон, онлайн когда используется:
```
Хранит:
Своя цепочка операций (история переводов)
Свои ключи (seed → keypairs)
Свои контакты (адресная книга: имя → mt-адрес)
Blinding factors (для расшифровки commitments)
Сообщения (локальная история переписки)
Делает:
Отправка/получение переводов
Мессенджер (P2P напрямую через libp2p)
Discovery (phone_hash → account_id → pubkey, локально)
Запрос pubkey и proposals у узлов сети
```
**Доверенный узел** узел друга, семьи, сообщества:
```
Делает:
Всё что узел + хранит Blob Buffer для привязанных аккаунтов
Владелец аккаунта привязывает свой account_id к доверенному узлу
Узел хранит зашифрованные сообщения (содержимое скрыто)
Владелец забирает сообщения когда появляется онлайн
```
### Размеры
| Участник | Данные | Размер |
|----------|--------|--------|
| Узел (1M аккаунтов) | Account Table + Node Table + Proposals | ~2 GB |
| Узел (10M аккаунтов) | Account Table + Node Table + Proposals | ~11 GB |
| Узел (100M аккаунтов) | Account Table + Node Table + Proposals | ~101 GB |
| Кошелёк (обычный) | 100 операций/год + контакты + сообщения | ~1 MB |
| Кошелёк (активный) | 10 000 операций/год | ~16 MB |
| Корпорация | 1M Anchor/год | ~0.8 GB |
### Потеря данных клиента
Потеря устройства: balance_commitment в Account Table цел, seed восстанавливает ключи, баланс доступен. История переводов и сообщений утрачена как потерять выписку, не деньги. Если есть доверенный узел зашифрованные сообщения можно восстановить.
### Fast Sync (новый узел)
1. Цепочка proposals от генезиса проверка TimeChain-цепочки и подписей победителей (мегабайты)
2. State Root из последнего τ boundary proposal (account_root + node_root)
3. Global State snapshot от пиров: каноническая сериализация всех листьев Merkle-дерева состояния (Account Table + Node Table). Верификация: пересчёт Merkle root из полученных листьев, сравнение с account_root и node_root из proposal
4. Catch-up cemented операций после τ checkpoint:
- Запросить cemented операции от пиров
- Для каждой: проверить подпись FN-DSA-512 + Bulletproofs + prev_hash
- Запросить confirmations, проверить quorum (chain_length > quorum)
- Применить к локальному Account Table
5. Узел синхронизирован и готов к участию
Proposals доказывают цепочку state commitments. Checkpoint восстанавливает каноничное состояние. Catch-up добирает cemented операции после checkpoint через самоверифицируемые операции + confirmations. Тела операций не нужны сети — состояние самодостаточно.
---
## Application Layer
Montana — цифровой стандарт времени. Приложения управляют своим состоянием самостоятельно (серверы, базы данных, P2P). Montana хранит только криптографические отпечатки с привязкой ко времени — 32 байта на запись.
### Anchor
Одна операция, данные навсегда привязаны к timechain_value конкретного окна.
```
Anchor:
prev_hash 32B
account_id 32B
app_id 32B <- SHA-256("mt-app" || app_name)
data_hash 32B <- Merkle root, H(document), произвольный хэш
signature 666B
Итого: ~796B
```
app_id — детерминированный идентификатор пространства имён. Вычисляется из имени приложения, регистрация не требуется. Позволяет фильтровать, индексировать, строить лёгкие клиенты для конкретного приложения.
### Timestamp Proof
Стандартный формат доказательства: документ D существовал до момента T.
```
Доказательство:
1. H(D) <- хэш документа
2. Anchor с data_hash <- содержит MerkleRoot включающий H(D)
3. Merkle proof: H(D) → data_hash <- H(D) является листом дерева
4. Proposal header окна <- содержит Anchor, timechain_value = T
5. VDF-цепочка от генезиса <- доказывает T
Верификация:
1. Пересчитать Merkle proof: H(D) → data_hash
2. Убедиться что Anchor включён в proposal (user_root)
3. Убедиться что proposal содержит валидный timechain_value
4. Любой участник с доступом к цепочке proposals верифицирует
```
Proposals хранятся навсегда. Timestamp proof верифицируем в любой момент.
### Примеры
**Мессенджер.** Каждое сообщение хэшируется, цепочка хэшей формирует Merkle root, Merkle root записывается в Anchor раз в минуту или час. Montana хранит 32 байта — доказательство что набор сообщений существовал в конкретный момент. Подделать историю переписки невозможно — хэш не совпадёт.
**Архив документов.** Компания ежедневно записывает Merkle root документов. Через 10 лет регулятор спрашивает «существовал ли документ X на дату Y». Компания предоставляет документ, Merkle proof и ссылку на proposal. Верификация математическая.
**Социальная сеть.** Каждый пост привязан к Montana Time через Anchor. Порядок публикаций доказуем. Редактирование не скрывает оригинал — хэш оригинала уже в цепочке.
### Экономика
Anchor бесплатен. Тысячи приложений записывающих якоря — утилитарное использование Montana Time. Спрос на токен привязан к утилитарной функции: перевод ценности и запись времени, не спекуляция.
Не нужны смарт-контракты. Не нужен Turing-complete язык. Не нужен газ. Не нужны комиссии.
### Phone Discovery
Привязка номера телефона к аккаунту. Опционально — пользователь решает сам.
```
phone_hash = SHA-256("mt-phone" || phone_number)
```
Пользователь записывает phone_hash в Account Table через PhoneLink (UserObject). Любой знающий номер вычисляет phone_hash локально → находит account_id в своей копии Account Table → получает pubkey. Ноль запросов к серверу. Ноль загрузки контактов.
```
PhoneLink:
prev_hash 32B
account_id 32B
phone_hash 32B <- SHA-256("mt-phone" || phone_number)
signature 666B
Итого: ~762B
```
Алиса открывает адресную книгу → вычисляет phone_hash каждого контакта локально → сверяет с Account Table на своём узле → мгновенно видит кто в Montana. Как WhatsApp, но без сервера.
### Messenger
Мессенджер поверх Montana. Протокол отвечает за identity и время. Доставка — P2P между устройствами. Montana не хранит, не буферизирует, не маршрутизирует сообщения.
**Что даёт Montana мессенджеру:**
- **Discovery:** phone_hash → account_id → pubkey (локально, из Account Table)
- **Шифрование:** pubkey получателя из Account Table → E2E encryption
- **Timestamping:** Anchor с хэшем переписки → доказуемый момент
**Что Montana НЕ делает:**
- Не хранит сообщения
- Не маршрутизирует
- Не буферизирует
```
Отправка:
1. Алиса знает phone_hash Боба → account_id → pubkey (локально)
2. Шифрует сообщение pubkey Боба
3. Отправляет прямо устройству Боба через P2P (libp2p)
4. Опционально: Anchor с H(conversation_root) → привязка ко времени
Получение (онлайн):
1. Боб получает сообщение по P2P напрямую
2. Расшифровывает своим приватным ключом
Получение (офлайн):
1. Боб офлайн → Алиса хранит сообщение на своём устройстве
2. Боб появился → устройство Алисы доставляет
3. Если у Боба есть узел (валидатор) — узел работает 24/7,
принимает и хранит сообщения для своего владельца
```
**Три уровня доставки:**
```
Уровень 1 — оба онлайн:
Телефон Алисы ←→ libp2p ←→ Телефон Боба
Прямое P2P соединение. Мгновенно.
Уровень 2 — Боб офлайн, у Боба есть узел:
Телефон Алисы → libp2p → Узел Боба (24/7)
Узел хранит зашифрованное сообщение в Blob Buffer (TTL = τ₂)
Боб появился → телефон забирает сообщения с узла
Уровень 3 — Боб офлайн, у Боба есть доверенный узел:
Телефон Алисы → libp2p → Доверенный узел Боба
Зашифровано pubkey Боба — доверенный узел не видит содержимое
Боб появился → забирает сообщения
Fallback — оба офлайн, нет узла:
Алиса хранит сообщение на своём устройстве
Доставляет при следующей встрече онлайн
```
Сообщения хранятся у участников, не в сети. Montana хранит только хэши (32B) с привязкой ко времени. Подделать историю переписки невозможно — хэш в proposal навсегда.
### Integration
Три операции для подключения внешних систем к Montana.
#### Write — запись
Внешняя система формирует Anchor и отправляет в P2P-сеть.
```
Вход: app_id (32B) + data_hash (32B) + подпись FN-DSA-512
Выход: Anchor включён в proposal окна W с timechain_value T_W
```
data_hash — произвольный хэш: Merkle root документов, хэш batch'а Rollup, fingerprint состояния. Montana не интерпретирует содержимое — хранит 32 байта с привязкой ко времени.
#### Read — чтение
Внешняя система запрашивает доказательство по height или data_hash.
```
Вход: proposal height или data_hash + app_id
Выход: proposal header + Merkle path от data_hash до user_root
```
Proposal header содержит timechain_value = доказуемый момент. Merkle path доказывает что data_hash включён в этот proposal.
#### Verify — верификация
Внешняя система проверяет proof автономно, без доверия к Montana-узлу.
```
1. Пересчитать Merkle path: data_hash → user_root
2. Сравнить user_root с полем в proposal header
3. Проверить подпись победителя на proposal header
4. Проверить timechain_value: пересчёт D хэшей от T_{W-1} до T_W
5. Проверить цепочку proposals: prev_proposal_hash связывает окна до генезиса
```
Шаги 13: миллисекунды. Шаг 4: ~60 секунд на одном ядре (один сегмент VDF). Шаг 5: проверка подписей и хэшей — линейна по количеству proposals, параллелизуема.
Полная верификация от генезиса: H сегментов VDF, каждый проверяется независимо. На C ядрах: ~(H/C) × 60 секунд. TimeChain хранит все промежуточные T_r в proposals — параллелизация полная.
---
## Ключи
```
seed
├── Аккаунт: FN-DSA-512 keypair → account_id = SHA-256("mt-account" || suite_id || account_pubkey)
└── Узел: FN-DSA-512 keypair → node_id = SHA-256("mt-node" || node_pubkey)
```
Один seed порождает два FN-DSA-512 keypair: для аккаунта (подпись операций) и для узла (подпись proposals и NodeChain endpoints). account_id и node_id выводятся из публичных ключей, верифицируемы без знания seed. Бэкап = seed.
---
## Криптографическая реализация
### Primitive layer
Собственная реализация криптографических примитивов запрещена. Только audited библиотеки с constant-time гарантиями и опубликованными test vectors.
| Примитив | Стандарт | Роль |
|----------|----------|------|
| SHA-256 | FIPS 180-4 | TimeChain, NodeChain, адреса, Merkle-деревья |
| FN-DSA-512 | Selected NIST candidate, forthcoming FIPS 206 | Подписи блоков аккаунтов и proposals |
| Pedersen commitments | Ristretto group | Скрытие балансов и сумм |
| Bulletproofs | Bünz et al. 2018 | Range proofs, balance proofs. Без trusted setup |
### Consensus encoding layer
Консенсусно-критическая поверхность: каноническая сериализация, Merkle layout и domain separation. Разная сериализация одного объекта = разный хэш = форк. Требования:
- Fixed binary encoding для каждого консенсусного объекта
- Length-prefix кодирование полей, фиксированный endianness (little-endian)
- Domain separation для всех хэшей:
| Домен | Контекст |
|-------|----------|
| `mt-op` | Хэширование операций аккаунтов |
| `mt-header` | Хэширование proposal headers |
| `mt-account` | Деривация account_id |
| `mt-invitation` | Хэширование приглашений |
| `mt-merkle-leaf` | Листья Merkle-деревьев |
| `mt-merkle-node` | Внутренние узлы Merkle-деревьев |
| `mt-timechain` | TimeChain VDF seed |
| `mt-nodechain-init` | NodeChain init seed |
| `mt-equivocation` | Хэширование equivocation proofs |
| `mt-confirmation` | Хэширование async confirmations |
| `mt-app` | Деривация app_id для Application Layer |
| `mt-node` | Деривация node_id |
| `mt-phone` | Деривация phone_hash для Phone Discovery |
- Альтернативные сериализации запрещены
- Test vectors для каждого консенсусного объекта
- Cross-implementation conformance tests перед запуском mainnet
### Protocol layer
Собственная реализация поверх криптографического ядра:
| Компонент | Назначение |
|-----------|------------|
| Merkle-деревья | State Root (из SHA-256 вызовов) |
| VDF scheduling | Управление TimeChain и NodeChain цепочками |
| State machine | Account Table, Node Table, state transitions |
| P2P gossip | Распространение операций, confirmations и proposals |
### Инфраструктура
| Библиотека | Назначение |
|------------|------------|
| RocksDB | Хранение Account Table и операций |
| libp2p | P2P транспорт |
Production: Rust.
---
## Сетевой уровень
### Transport Obfuscation
Весь P2P-трафик Montana неотличим от обычного HTTPS. Внешний наблюдатель (ISP, DPI, государственный фаервол) не может определить что соединение принадлежит Montana.
**Требования:**
1. Все P2P-соединения инкапсулированы в TLS 1.3 на порт 443
2. Noise framework (встроен в libp2p) для шифрования внутри TLS
3. Padding: каждый пакет дополняется до фиксированного размера из набора {1 KB, 2 KB, 4 KB}. Ближайший больший размер
4. Timing jitter: интервал между пакетами рандомизирован в пределах ±20% от базового
**Что скрывается:**
| Наблюдатель | Видит | Не видит |
|-------------|-------|----------|
| ISP / DPI | TLS 1.3 соединение на порт 443 | Протокол, содержимое, тип сообщения |
| Сетевой аналитик | Поток пакетов фиксированного размера | Паттерн VDF reveal / confirmation / proposal |
| Государственный фаервол | HTTPS-трафик | Факт участия в Montana |
**Реализация:**
```
libp2p transport stack:
TCP → TLS 1.3 (порт 443) → Noise → Montana protocol
Padding:
msg_padded = msg || random_bytes(next_bucket_size - len(msg))
bucket_sizes = [1024, 2048, 4096]
Timing jitter:
send_delay = base_interval × (1 + uniform(-0.2, 0.2))
```
Блокировка Montana = блокировка TLS 1.3 на порт 443 = блокировка HTTPS = блокировка интернета.
Transport obfuscation ортогонален консенсусу. TimeChain, NodeChain, state machine работают поверх любого транспорта без изменений.
### Censorship-Resistant Discovery
Генезис: 12 hardcoded bootstrap nodes. Если все 12 IP заблокированы на уровне страны — новый узел не может войти в сеть. Четыре независимых канала обнаружения. Достаточно одного из четырёх.
**1. Domain fronting.** Bootstrap через CDN (Cloudflare, AWS CloudFront). Узел отправляет HTTPS-запрос на CDN-домен, внутри TLS — запрос к Montana bootstrap. Внешний наблюдатель видит соединение с CDN. Блокировка = блокировка CDN = блокировка половины интернета.
**2. Peer exchange.** Каждый узел хранит и передаёт список активных пиров новичкам. Достаточно знать IP одного узла — друг, QR-код, мессенджер. Один живой контакт = вход в сеть.
**3. DHT.** Kademlia DHT поверх libp2p. Узлы находят друг друга без центральной точки. Идентификаторы рандомизированы — DHT не раскрывает node_id до установления Montana-соединения.
**4. Bridge nodes.** Узлы за пределами цензурируемой юрисдикции, опубликованные через внеполосные каналы (социальные сети, мессенджеры, печатные QR-коды). IP bridge node неизвестен фаерволу до использования.
Избыточность = устойчивость. Четыре канала независимы. Блокировка одного не влияет на остальные.
### Dandelion++ (анонимность отправителя)
P2P gossip Montana ретранслирует операции через все узлы. Без защиты первый пир знает IP отправителя. Dandelion++ (Fanti et al. 2018) устраняет связь IP → операция модификацией существующего gossip.
**Две фазы:**
```
Stem (стебель):
Операция проходит по цепочке через 2-3 случайных узла.
Каждый узел видит только предыдущий hop, не автора.
На каждом hop с вероятностью p = 0.1 переход в fluff.
Fluff (пух):
Последний stem-узел запускает обычный gossip.
Для всей сети операция «появилась» из случайной точки.
```
**Применение по типу объекта:**
| Объект | Режим | Причина |
|--------|-------|---------|
| UserObject (Transfer, Anchor, OpenAccount, ChangeKey, PhoneLink) | Stem → fluff | Скрыть IP отправителя |
| ControlObject (NodeInvitation, NodeRegistration) | Stem → fluff | Скрыть IP пригласившего/регистрирующегося |
| VDF Reveal | Прямой gossip (без stem) | node_id публичен в reveal, анонимность невозможна |
| Confirmation | Stem → fluff | Скрыть какой узел подтвердил первым |
VDF Reveal — единственное исключение. Reveal содержит node_id по определению. Связь IP → node_id для внешнего наблюдателя закрыта слоем Transport Obfuscation (TLS 1.3 на порт 443).
**Свойства:**
| Угроза | Защита |
|--------|--------|
| Пир видит IP отправителя | Stem: пир видит только предыдущий hop |
| Глобальный наблюдатель (ISP) | TLS 1.3 + timing jitter (Transport Obfuscation) |
| Анализ графа gossip | Операция входит в gossip из случайной точки |
| Контроль k узлов | Деанонимизация требует контроля O(√n) узлов |
**Реализация:**
```
stem_peer = random_choice(connected_peers)
on_receive_stem(msg, from_peer):
if random() < 0.1:
gossip_broadcast(msg) // fluff
else:
next_peer = random_choice(connected_peers, exclude=from_peer)
send_stem(msg, next_peer) // продолжить stem
timeout:
если stem-сообщение не ушло в fluff за 30 секунд → принудительный fluff
```
Dandelion++ не требует внешней инфраструктуры. Каждый Montana-узел уже является relay — gossip существует, stem добавляет 2-3 hop перед ним. Latency overhead: миллисекунды.
### Три слоя — одна конструкция
```
Слой 1: Transport Obfuscation ISP не знает что ты в Montana
Слой 2: Censorship-Resistant Discovery фаервол не может отрезать от сети
Слой 3: Dandelion++ пиры не знают кто автор операции
```
Каждый слой закрывает свой вектор. Ни один не требует внешней инфраструктуры. Всё построено поверх libp2p и существующего gossip. Сетевой уровень ортогонален консенсусу — ни один state transition не затронут.
---
## Архитектура
```
┌─────────────────────────────────┐
│ Wallet │
│ Кошелёк, баланс, переводы │
│ FN-DSA-512 keypair │
└──────────────┬──────────────────┘
┌──────────────┴──────────────────┐
│ Montana │
│ Децентрализованные часы │
│ │
│ TimeChain ──→ NodeChain ──→ Account
│ (часы) (присутствие) (состояние)
│ │
│ Account Chain (Block Lattice) │
│ Account Table, Proposals │
│ SHA-256, FN-DSA-512 │
└─────────────────────────────────┘
```