Эксплорер TimeChain
Откройте любой перевод монет Montana по его идентификатору или ссылке подтверждения и проверьте его сами. Запись читается с узлов; её хеш, постквантовая подпись и баланс её ключа — свёрнутый из всей цепи ключа — проверяются здесь, в вашем браузере.
Контрольная точка сети
Последние переводы
Новейшие записи на каждом узле. Каждая строка проверяется здесь, как только показана: её хеш, подпись и место в цепи её ключа.
Как проверить самостоятельно
Перевод — одна запись, подписанная сидом отправителя и положенная в цепь его ключа на узле, который выбирает ключ; журнал только дописывается: запись никогда не заменяется и не удаляется. Целые числа записаны от младшего байта (little-endian).
Ниже — раскладка записи, её подпись, идентификатор и адрес отправителя в записи Python (срез [a:b] берёт байты с a по b − 1).
Запись — 5443 байт
Запись несёт свой вид и поля, которыми этот вид пользуется; поле, которым вид не пользуется, нулевое. SEND: pair — метка пары, to = SHA-256(mt-coin-to ‖ from получателя ‖ blind), где blind = HMAC-SHA-256 под секретом пары над mt-coin-blind ‖ nonce, а t0 — часть суммы, объявленная, а не отчеканенная. RECV: to несёт blind, ref — принимаемый SEND, t0 — ту же объявленную часть. REFUND: ref называет собственный SEND отправителя. MINT: t0 и t1 ограничивают отчеканенные секунды. GENESIS: баланс, который кошелёк ключа объявил при открытии цепи.
| Смещение | Байт | Поле | Содержимое |
|---|---|---|---|
| 0 | 4 | magic | ASCII MTTX |
| 4 | 1 | version | 0x03 |
| 5 | 1 | kind | 1 SEND, 2 RECV, 3 MINT, 4 REFUND, 5 GENESIS |
| 6 | 8 | amount | u64, монеты, не меньше 1 |
| 14 | 8 | birth | u64, миллисекунды с 1970-01-01 UTC, по часам отправителя |
| 22 | 16 | nonce | случайные байты |
| 38 | 32 | prev | идентификатор предыдущей записи ключа в его цепи; 32 нулевых байта у первой |
| 70 | 32 | pair | HMAC-SHA-256 на секрете пары от ASCII mt-coin-pair-v1 |
| 102 | 32 | to | SEND: обязательство получателя; RECV: blind, который его раскрывает |
| 134 | 32 | ref | RECV, REFUND: идентификатор SEND, судьбу которого они решают |
| 166 | 8 | t0 | MINT: первая отчеканенная секунда (секунды узла с 1970); SEND, RECV: объявленная часть суммы |
| 174 | 8 | t1 | MINT: секунда после последней отчеканенной |
| 182 | 1952 | pubkey | открытый ключ ML-DSA-65 отправителя |
| 2134 | 3309 | sig | подпись ML-DSA-65 |
msg = b"mt-coin-tx-v3" + record[0:2134]
pk = record[182:2134]
sig = record[2134:5443]
valid = ML-DSA-65.Verify(pk, msg, sig, ctx=b"") # FIPS 204
id = SHA-256(record).hex()
from = SHA-256(pk).hex()
prev = record[38:70].hex() # 64 zeros: the key's first record
chain = ["montana.quest", "montana.xxx"][SHA-256(pk)[0] % 2] # the node whose word countsЦепь ключа живёт на одном узле неизменной таблицы узлов цепей протокола, упорядоченной по имени (формула выше): на том, что стоит под номером from[0] mod n, где from[0] — первый байт адреса отправителя. Этот узел принимает запись только поверх головы ключа, поэтому из двух записей на одной предшественнице стоит только одна. Идя по prev от записи к записи, можно пройти цепь ключа назад до её первой записи; эта страница связывает каждую запись с предыдущей.
Баланс ключа — свёртка его цепи от первой записи: MINT прибавляет не больше 2 × min(13, max(1, bit_length(s) − 1)) монет за s-ю секунду от первой записи ключа, за отрезок не короче 60 секунд, начинающийся там, где кончился прошлый; SEND вычитает — сначала отчеканенное — и не может увести ниже нуля; RECV прибавляет SEND, чей to раскрывается на этот ключ его blind; REFUND возвращает собственный SEND ключа через сутки, если его никто не принял. SEND, положенный, пока ключ получателя ещё не был известен, получателя не называет: он вычитает так же, а кошелёк получателя вносит монеты в свою цепь чеканкой в пределах своего времени. Узел цепи SEND решает судьбу каждого SEND один раз: принят или возвращён, но не то и другое.
Подпись — ML-DSA-65 по FIPS 204 с пустым контекстом, поэтому её проверит любая реализация стандарта. Эта страница проверяет её ядром Montana, собранным в WebAssembly, — тем же модулем, что работает в веб-приложении Montana, — а SHA-256 считает Web Crypto вашего браузера.
Метку пары знают только два конца разговора: любой видит, что адрес заплатил паре, но не видит, кто эта пара.
Каждый узел проверяет подпись ядром Montana прежде, чем принять запись, и каждый читатель проверяет её снова прежде, чем поверить, — кошелёк перед зачислением, эта страница перед словом «верна». Прочитайте запись сами с любого узла; команда печатает длину записи, её идентификатор и адрес отправителя:
curl -s -H 'Content-Type: application/json' -d '{"id":"{id}"}' https://montana.xxx/pushwake/tx-get | python3 -c 'import sys,json,base64,hashlib; r=base64.b64decode(json.load(sys.stdin)["rec"]); k={1:(69,2021),2:(101,2053),3:(182,2134)}[r[4]]; print(len(r), hashlib.sha256(r).hexdigest(), hashlib.sha256(r[k[0]:k[1]]).hexdigest())'
curl -s -H 'Content-Type: application/json' -d '{"id":"{id}"}' https://montana.xxx/pushwake-msk/tx-get | python3 -c 'import sys,json,base64,hashlib; r=base64.b64decode(json.load(sys.stdin)["rec"]); k={1:(69,2021),2:(101,2053),3:(182,2134)}[r[4]]; print(len(r), hashlib.sha256(r).hexdigest(), hashlib.sha256(r[k[0]:k[1]]).hexdigest())'Что доказывает запись. Каждое движение баланса ключа — запись его цепи: монеты входят только чеканкой MINT (не больше, чем позволяет прожитое ключом время), зачислением RECV (раскрытием перевода, адресованного этому ключу) или возвратом REFUND (перевода, который за сутки никто не принял), а выходят только переводом SEND. Узел цепи отказывает в SEND сверх того, что держит цепь, каждый узел и каждый телефон, хранящий копию, сворачивают ту же цепь, и эта страница сворачивает её снова в вашем браузере.
Ссылка подтверждения перевода — https://montana.xxx/explorer/#tx= и его идентификатор.
Формат: запись монет Montana (MTTX).
