# Montana — Спецификация протокола **Версия:** 18.2.0 (2026-04-05 09:11 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. --- ## Три решённые проблемы ### 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). Чеканка открыта — нельзя напечатать из воздуха. Переводы закрыты — нельзя узнать кто кому сколько. Два слоя: публичная эмиссия + приватные опер��ции. ### Двойная трата Каждый аккаунт имеет одну цепочку. Две операции с одним 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 mɈ = 1 000 000 μɈ = 1 000 000 000 nɈ 60 секунд = 1 минута = 60 TimeCoin 3 600 секунд = 1 час = 3 600 TimeCoin 86 400 секунд = 1 день = 86 400 TimeCoin Одно окно τ₁ регистрирует 60 прошедших секунд = 60 TimeCoin. Точность: 9 знаков после запятой (наносекунда). Все расчёты эмиссии в nɈ (целочисленная арифметика, без плавающей точки). ### Issuance schedule Одна секунда протокольного времени порождает одну монету. С первого блока и навсегда. | Параметр | Значение | |----------|----------| | Генезис | 09.01.2026 00:00:00 UTC | | TIME_RECORD | 60 000 000 000 nɈ (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 связывает окна до генезиса ``` Шаги 1–3: миллисекунды. Шаг 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. --- ## Архитектура ``` ┌─────────────────────────────────┐ │ Wallet │ │ Кошелёк, баланс, переводы │ │ FN-DSA-512 keypair │ └──────────────┬──────────────────┘ │ ┌──────────────┴──────────────────┐ │ Montana │ │ Децентрализованные часы │ │ │ │ TimeChain ──→ NodeChain ──→ Account │ (часы) (присутствие) (состояние) │ │ │ Account Chain (Block Lattice) │ │ Account Table, Proposals │ │ SHA-256, FN-DSA-512 │ └─────────────────────────────────┘ ```