Проверка загруженного файла
Воспроизводимая сборка утверждает: это получено из этого исходного кода, и проверить может любой — и именно такую гарантию анонимно публикуемый проект может предложить вместо сертификата подписи кода. Ниже — как ею воспользоваться.
Три проверки, и они отвечают на разные вопросы. Выполняйте их в этом порядке; каждая стоит меньше без предыдущей.
| Проверка | Что доказывает | Чего не доказывает |
|---|---|---|
| Контрольная сумма | Файл не был изменён при передаче. | Ничего о том, кто его произвёл и что внутри. |
| Подпись | Список контрольных сумм исходит от держателя ключа проекта. | Что этот ключ принадлежит кому-то, кому у вас есть причины доверять. |
| Пересборка | Бинарник содержит этот исходный код и ничего больше. | Что исходный код честен — прочтите его или прочтите разборы. |
Контрольная сумма#
curl -fsSLO https://zycord.com/releases//download/v<version>/SHA256SUMS.randomx
sha256sum --check --ignore-missing SHA256SUMS.randomx
# on macOS:
shasum -a 256 --check --ignore-missing SHA256SUMS.randomx
--ignore-missing не опционален и не является послаблениемРелизы теперь поставляют только архивы -randomx, поэтому
SHA256SUMS.randomx — это список, покрывающий то, что вы скачали;
SHA256SUMS.deb и SHA256SUMS.desktop покрывают пакеты Debian и
настольный кошелёк. Каждый покрывает несколько файлов, а вы скачали один. Без этого флага пять отсутствующих у вас файлов отмечаются как
FAILED open or read, и команда завершается с ненулевым кодом на совершенно исправной загрузке — на той самой
странице, которая говорит вам, что несовпадение означает скомпрометированный бинарник. Проверку, чей нормальный результат —
сбой, люди приучаются игнорировать.
Подпись#
Релизы сейчас поставляют zycord-release-key.asc — открытый ключ — но
ничего подписанного им, кроме манифеста обновлятора: ни у одного файла контрольных сумм нет отделённой
подписи, и ни один не подписан внутри себя. Поэтому gpg --verify ниже сегодня
завершается ошибкой об отсутствующем файле, и это пробел релиза, а не ваша ошибка. Пока он не закрыт,
проверка, которая на деле несёт аргумент доверия, — это пересборка: ей не нужна никакая подпись, потому что байты вы получаете сами и сравниваете.
Когда подпись контрольных сумм будет опубликована, она будет сделана ключом проекта. Полный отпечаток таков:
E724 39CE DD85 11F9 D607 550B 87FD 60D5 EB4A 0B29
Он опубликован в заголовке технического описания, в архивном депозите и в объявлении о генезис-блоке. Он никогда не меняется молча: ключ, изменившийся без подписанного заявления от старого, неотличим от компрометации и должен считаться ею.
Возьмите ключ откуда удобно, а затем сверьте полученное со строкой выше. Файл ключа, чей отпечаток совпадает с ней, — это ключ проекта, кто бы вам его ни отдал, а файл с любым другим отпечатком ничего не стоит, каким бы надёжным ни выглядел хост.
Его несут три места. Подойдёт любое из них:
# 1. The repository, if you have a clone. No network, no keyserver.
gpg --import packaging/zycord-release-key.asc
# 2. The release page, as an asset beside the archives.
curl -fsSLO https://zycord.com/releases//download/v<version>/zycord-release-key.asc
gpg --import zycord-release-key.asc
# 3. A keyserver. Use this one.
gpg --keyserver hkps://keyserver.ubuntu.com --recv-keys E72439CEDD8511F9D607550B87FD60D5EB4A0B29
Затем подтвердите, что именно попало в вашу связку ключей, прежде чем на это полагаться:
gpg --fingerprint E72439CEDD8511F9D607550B87FD60D5EB4A0B29
keys.openpgp.org для этого ключаЭто сервер ключей по умолчанию в нескольких сборках GnuPG, и он отдаёт урезанную копию: голый
пакет открытого ключа, без идентификатора пользователя и без самоподписи. GnuPG отвергает такую копию —
gpg: key 87FD60D5EB4A0B29: new key but contains no user ID - skipped — и
ключ так и не попадает в связку, поэтому проверка ниже падает с тем, что выглядит как неверная подпись, а на деле
является отсутствующим ключом. Этот сервер по своим правилам вырезает идентификаторы пользователя, пока через него не подтверждён
адрес, а этого псевдонимный проект сделать не может.
gpg --verify SHA256SUMS.randomx.asc SHA256SUMS.randomx
Сегодня это сообщает No such file or directory,
потому что ни один релиз ещё не опубликовал такой файл. См. примечание в начале этого раздела.
gpg добавит, что ключ не заверен доверенной подписью. Это
ожидаемо и не является сбоем. Это значит, что вы не сообщили своей связке ключей, что
лично ручаетесь за этот ключ, а именно этот вопрос и призван закрыть отпечаток. Важно то,
что подпись проверяется и что ключ, против которого она проверена, — это ключ с напечатанным выше
отпечатком.
Техническое описание тоже подписано#
У PDF, отдаваемого с этого сайта, рядом лежит отделённая подпись, сделанная тем же ключом:
curl -fsSLO https://zycord.com/assets/zycord-whitepaper.pdf
curl -fsSLO https://zycord.com/assets/zycord-whitepaper.pdf.asc
gpg --verify zycord-whitepaper.pdf.asc zycord-whitepaper.pdf
Пересборка — проверка, которая на деле заменяет сертификат#
Хеш говорит вам, что файл не был изменён при передаче. Он ничего не говорит о том, что издатель в него положил. А вот это говорит:
git clone https://gitlab.com/zycord-group/zycord-node.git
cd zycord-node
git checkout v<version>
make build
sha256sum bin/zcd bin/zycordd
Сравните с SHA256SUMS.binaries из релиза. Они должны совпасть
точь-в-точь. Если совпали, то скачанный вами бинарник содержит этот исходный код и ничего больше
— утверждение, которого ни один сертификат никогда ни о чём не делал.
Набор инструментов Go — часть того, что вы воспроизводите#
Это go1.26.2. Один и тот же исходный код, собранный двумя разными выпусками Go, — это два
разных бинарника; это не тонкость, это измеримо — собственный релизный процесс этого репозитория
однажды зафиксировал три разных значения SHA-256 для одного коммита и одного набора флагов, по одному на
версию Go. Поэтому make build закрепляет GOTOOLCHAIN=go1.26.2 и останавливается с
пояснением, если этот набор инструментов недоступен, вместо того чтобы выдать несовпадение, выглядящее как
подделка, ради обнаружения которой вся эта страница и существует.
Два полезных следствия:
- Вам не нужно доверять версии, написанной выше. Выпущенный бинарник сам её
сообщает:
go version -m zcdпечатает набор инструментов, которым он собран, рядом с модулем и флагами сборки. Если эта строка и закрепление вMakefileкогда-либо разойдутся, бинарник собран не так, как говорит эта страница. - Выгрузка старого тега выгружает вместе с исходным кодом и его закрепление, так что пересборка старого релиза продолжает работать и после перехода проекта на более новый Go.
Переводы строк здесь — часть исходного кода#
wallet/webui встраивает фронтенд кошелька через //go:embed, поэтому переводы строк в этих
файлах — это байты в бинарнике: рабочая копия, преобразованная в CRLF, собирает другой
zcd из того же коммита — несовпадение с невинной причиной и пугающим
видом. Файл .gitattributes со строкой * text=auto eol=lf даёт LF в
рабочем дереве на любой платформе и при любой конфигурации git, так что свежий клон
даёт один и тот же ответ везде.
Два случая, которые он не покрывает: пересборка тега старше этого файла (задайте
core.autocrlf=input перед выгрузкой) и уже существующий клон, сделанный с
core.autocrlf=true, который не исправляется при получении изменений.
-randomx невоспроизводимы по устройствуRandomX написан на C++, поэтому сборка с cgo уносит в результат системный набор инструментов C, и никто не может
пересобрать её байт в байт. Контрольные суммы этих архивов лежат в SHA256SUMS.randomx, и они
намеренно отсутствуют в SHA256SUMS.binaries, который перечисляет, какие хеши должна дать сборка, которую
вы делаете из исходного кода. Это единственное место, где
уровень, подключающийся к сети, и уровень, который аттестован, не пересекаются — см. таблицу двух уровней
в разделе Установка.
Смысл в том, что это сказано вслух: это ваше решение, а не предположение, сделанное за вас.
Проверьте реализацию на соответствие протоколу#
Отдельно от проверки происхождения бинарника вы можете проверить, что он реализует протокол. Эталонные векторы и есть протокол; независимая реализация, проходящая их, — равноправный участник, а не форк.
zcd vectors # check this build against spec/vectors
zcd genesis --testnet # rebuild block 0 and print its id
zcd params --testnet # print the frozen parameters
zcd genesis — важнейшая из команд: объявление о запуске обязуется, за недели
вперёд, к тегу кода, хешу параметров и идентификатору генезис-блока — и эта команда пересобирает всё
это за миллисекунды, из исходного кода, на любой машине. Значения публичного testnet приведены на
странице testnet; сборка, печатающая другие, — это сборка на
другой цепочке, и она не подключится.
Независимые аттестации#
Один человек, пересобравший тег, доказывает, что тег воспроизводим. Несколько незнакомых людей, пересобравших его и подписавших результат, доказывают заметно больше, и именно к этому образцу серьёзные проекты пришли ровно по этой причине. Пересоберите тег, а затем опубликуйте полученный дайджест и собранный тег в ветке анонса — в том числе если он не совпал: именно об этом случае и стоит услышать.