Подписи, привязанные к цепочке
Подпись ZooBC действительна только в одной цепочке. Прежде чем подписать транзакцию, кошелёк вычисляет дайджест, включающий хеш генезиса цепочки, поэтому платёж, подписанный в testnet, не проходит проверку в mainnet или devnet, хотя один и тот же ключ даёт один и тот же адрес во всех цепочках. Та же привязка защищает соединения между узлами и сообщения, подписанные вне цепочки.
Дайджест
Подписант никогда не подписывает сырые байты транзакции. Он подписывает такой дайджест:
digest = SHA3-256("ZBC-TX" ‖ genesis hash ‖ unsigned transaction bytes)
transaction hash = SHA3-256(unsigned transaction bytes ‖ signature)
transaction id = the first 8 bytes of the transaction hash, little-endian
Метка «ZBC-TX» помечает дайджест как дайджест транзакции; другие подписываемые действия используют другие метки (см. ниже). Хеш генезиса привязывает подпись к одной цепочке. Принимается только этот дайджест, привязанный к цепочке: подпись над голыми байтами, без привязки к цепочке, отклоняется в любой цепочке. Полная процедура подписания описана в статье подписание транзакции.
Хеш генезиса — идентичность цепочки
Хеш генезиса — это хеш самого первого блока цепочки. Он выводится из конфигурации генезиса цепочки, поэтому изменение любого зафиксированного значения этой конфигурации даёт новый хеш, то есть другую цепочку (см. Генезис-блок). Отдельного байта идентификатора сети в ZooBC нигде нет: хеш генезиса — единственная идентичность цепочки. У devnet, testnet и mainnet он свой (см. Devnet, testnet и mainnet), а тестовая сеть, запущенная заново, получает новый.
Узел сообщает genesis_hash своей цепочки и свою signing_version в информационном маршруте /api/v1/node/info (см. API узла), так что кошелёк или инструмент может узнать, для какой цепочки он подписывает.
Повторное воспроизведение между цепочками
Допустим, платёж подписан в testnet, и кто-то копирует его в mainnet. Узел mainnet вычисляет дайджест с хешем генезиса mainnet, получает другое значение, и подпись не проходит проверку: транзакция отклоняется как «not signed for this chain». Сумма роли не играет, и кошельку ничего не нужно добавлять.
Один и тот же ключ даёт один и тот же адрес во всех цепочках ZooBC, и адрес, пополненный в одной цепочке, в другой просто показывает нулевой баланс. Именно поэтому привязка важна: без неё платёж, сделанный в одной цепочке, можно было бы скопировать в другую и переместить там монеты.
Каждый тип аккаунта, каждый подписант
Аккаунтами ZooBC могут управлять ключи многих видов: собственные ключи Ed25519 ZooBC, ключи Bitcoin и Ethereum и другие (см. Ключи и типы аккаунтов). Каждый тип аккаунта подписывает один и тот же дайджест, привязанный к цепочке; некоторые сначала хешируют его ещё раз, как того требует схема подписи их родной цепочки (например, ключи в стиле Ethereum подписывают его хеш Keccak-256). Участники мультиподписного аккаунта подписывают привязанный к цепочке дайджест внутренней транзакции.
Другие подписываемые действия используют собственные дайджесты, тоже привязанные к цепочке: согласия на привязку к группам аккаунтов и управление ими («ZBC-GROUP-LINK», «ZBC-GROUP-CONTROL»), соподпись многостороннего эскроу и запрос, который отменяет ожидающую транзакцию в пуле узла («ZBC-CANCEL»).
Узлы и сообщения
Привязка к цепочке не ограничивается транзакциями:
- Рукопожатие пиров. Когда два узла соединяются, рукопожатие подписывается ключом узла и несёт хеш генезиса. Пир другой цепочки отклоняется с сообщением «Genesis hash mismatch», поэтому узел одной цепочки никогда не становится пиром узла другой.
- Подписанные сообщения. Сообщения, подписанные вне цепочки с помощью инструментов, используют дайджест SHA3-256("ZBC-MSG-v2" ‖ хеш генезиса ‖ сообщение), поэтому сообщение, подписанное в devnet, никогда не проходит проверку в testnet или mainnet (см. Подписанные и зашифрованные сообщения).
Исключение внутри протокола — квитанции: квитанция не называет цепочку, поэтому собственной привязки к цепочке у неё нет. Но она называет опорный блок по высоте и хешу, и валидаторы это проверяют.