Хеш публикации в Solidity: что доказывает совпадение
Подготовленный манифест курса 17 имеет определённые байты. Теперь свяжем его с коротким значением, которое можно сохранить в реестре. Разберём криптографический отпечаток и отделим реальную проверку совпадения от обещаний, которые этот механизм не даёт.
Для общего веб-примера договоримся использовать SHA-256 от точных сохранённых байтов файла. Это согласовано с браузерным курсом учебной библиотеки. Keccak-256 остаётся полезен для отдельного разбора ABI и типизированных ключей, но его результат нельзя незаметно подставить в этот договор. Размер bytes32 сам по себе не выбирает хеш-функцию.
От файла к значению фиксированного размера
Хеш-функция получает последовательность байтов и возвращает значение установленного размера. Файл может быть коротким манифестом или большим документом, но результат нашего выбранного алгоритма занимает 32 байта. Поэтому реестр хранит компактную связь с выпуском, а не копию всего материала.
Пусть H1 = SHA256(байты первого выпуска). Издатель сохраняет H1 в записи курса 17. Читатель получает файл, вычисляет значение тем же алгоритмом и сравнивает. При совпадении он получает основание считать, что скачанные байты соответствуют объявленному отпечатку, с учётом свойств выбранной хеш-функции и доверия к реализации вычисления.
Издатель: release-17-v1.json → SHA-256 → H1
Реестр: publish(17, H1)
Читатель: полученный файл → SHA-256 → Hdownload
Сравнение: Hdownload == H1
Это модель, а не выполненный расчёт. H1 обозначает неизвестное здесь значение реального артефакта. Мы не вставляем случайную строку и не называем её результатом нашего файла. Если читатель выполнит упражнение самостоятельно, он должен сохранить фактические байты и полученный полный отпечаток.
Что именно доказано
Совпадение отпечатков помогает проверить целостность выбранного выпуска. Оно не доказывает, что материал безошибочен, разрешён к использованию или написан конкретным профессором. Для связи с издателем нужно доверять адресу и процедуре объявления. Для оценки качества требуется прочитать материал и проверить его содержание.
Пусть злоумышленник подготовил неверный урок и честно вычислил его отпечаток. Байты будут успешно проходить проверку собственного отпечатка. Проблема находится в выборе доверенного издателя и содержимом, а не в арифметике сравнения. Это объясняет, почему сайт не должен превращать зелёную отметку целостности в универсальную надпись «материал безопасен».
Похожая граница есть у доступности. Если никто больше не хранит файл, отпечаток остаётся известным, но не позволяет восстановить весь исходный документ. Хеш не является методом сжатия, из которого затем распаковывается учебник. У приложения должны быть независимые способы доставки и сохранения выпуска.
Также нельзя скрыть личные данные простым хешированием предсказуемого значения. Если в поле хеша записана электронная почта с небольшим пространством возможных вариантов, наблюдатель может проверять кандидаты. Для нашего проекта такая публикация не нужна: хешируется публичный артефакт курса, а не идентификатор читателя.
Неоднозначность входа
В Solidity есть несколько способов кодировать набор значений перед хешированием. Динамические значения, соединённые без достаточных границ, могут дать одинаковые входные байты для разных наборов. Поэтому нельзя механически заменить проверку файла выражением keccak256(abi.encodePacked(title, release)) и считать, что оно однозначно описывает любой документ.
function releaseKey(uint256 courseId, uint256 revision, bytes32 fileHash)
external
pure
returns (bytes32)
{
return keccak256(abi.encode(courseId, revision, fileHash));
}
Это отдельный учебный пример ключа из типизированных полей. Он не равен отпечатку самого файла и не заменяет договор H1 = SHA256(fileBytes). Результаты двух операций могут иметь одинаковый тип bytes32, но отвечают на разные вопросы. Поэтому имена fileHash и releaseKey лучше сохранять различными.
Если требуется подпись на разрешение публикации, помимо содержимого понадобится домен: сеть, адрес проверяющего контракта, назначение и другие условия. Подписанный хеш файла сам по себе не сообщает, где разрешено использовать подпись. Эту тему мы изучим отдельно в курсе безопасности, не смешивая её с первой проверкой целостности.
Издатель заменяет выпуск
В исходном CourseCatalog функция publish может заменить H1 на H2 и снова установить активность. Это явная семантика изменяемого реестра. Значение H1 по-прежнему определяет прежний артефакт, но текущая запись теперь ссылается на другой выпуск. Нельзя обещать неизменность указателя, если контракт допускает замену.
Для истории пригодятся события, а для отдельных постоянных версий — явно введённый журнал. Сам тип хеша не создаёт такого журнала. Если сайт хочет дать читателю ссылку на выпуск первого мая, ему нужны реквизиты этого выпуска, а не только текущая запись по courseId 17.
| Наблюдение | Корректное объяснение |
|---|---|
| Файл совпал с H1 | Байты соответствуют объявленному отпечатку |
| В реестре уже H2 | Издатель назначил другой текущий выпуск |
| Файл не скачивается | Проблема доставки, не доказательство неверного H1 |
| Два инструмента дали разные значения | Сверить алгоритм, байты и кодирование |
Перед сравнением необходимо получить запись из нужного экземпляра и выбранного состояния. Если случайно читать чужой реестр, даже правильно вычисленный отпечаток будет сравниваться с неподходящим ожиданием. Поэтому предыдущие уроки о сети и адресе входят в процедуру целостности, а не являются отдельной формальностью.
Мы получили компактную связь с выпуском и точное описание её пределов. В следующей части реестр начнёт хранить эту связь постоянно, а читатель сможет отличать состояние storage от временных вычислений. Синтаксис кодирования и встроенных функций описан в руководстве Solidity.
Проверка на доверенном устройстве
Если сама страница подменена, она может показывать выдуманный результат сравнения. Поэтому механизм целостности включает доверие к инструменту вычисления. Для более строгой самостоятельной проверки читатель использует известную реализацию алгоритма и сверяет реквизиты реестра независимым способом.
Это не означает, что каждый обычный читатель обязан выполнять сложную процедуру. Интерфейс может честно сообщать, что проверку выполнило текущее приложение, и давать сведения для повторения. Уровень наблюдения становится понятным вместо абсолютного обещания, которого одна страница не обеспечивает.
Важно также сохранять полный отпечаток. Сокращение подходит компактной карточке, но при проверке используются все байты. Совпадение нескольких первых символов недостаточно. Дайте человеку возможность скопировать значение и увидеть название алгоритма; это полезнее декоративной иконки замка рядом с неизвестной строкой.
Оглавление курса. Листинги, расчёты и наблюдения здесь разобраны как ожидаемое поведение; компиляция, учебные программы и проверки при написании не запускались.