Перейти к содержанию

Verified Relay R1 — Direction State Validation

Отдельный эксперимент проверяет восемь чистых функций examples/apps/relay/direction.liza, используемых TCP-прокси. 16 обязательств: для каждой функции отсутствие trap и точное совпадение результата с независимой спецификацией, включая полноту покрытия путей. Восемь мутаций исходника обнаруживаются и воспроизводятся отдельным конкретным интерпретатором Semantic IR.

R1 проверяет координаты очереди. Он не доказывает сохранность байтов, корректность сетевого runtime, LLVM или машинного кода прокси. Проверки V0–V4, общий verification pipeline и направление Verification Bundle не меняются.

Контракт

Входы — все значения u32 для head, tail, count, включая 0xFFFFFFFF, и все комбинации eof/fin. Предположения о корректности входного Direction нет. Неверное состояние также должно обрабатываться без trap.

Спецификация независимо определяет:

Valid(d) = 0 <= head <= tail <= 2048
           and (fin implies (eof and head == tail))
ReadyFin(d) = Valid(d) and eof and head == tail and not fin
Функция Ожидаемый результат
empty (0, 0, false, false)
valid В точности Valid(d)
readable 2048-tail, если Valid(d) и нет EOF; иначе 0
queued tail-head, если Valid(d); иначе 0
read Err, если состояние неверно, есть EOF, tail=2048 или count>2048-tail; иначе переход ниже
write Err, если состояние неверно, count=0 или count>tail-head; иначе переход ниже
needs_fin В точности ReadyFin(d)
shutdown Ok(head,tail,true,true) при ReadyFin(d); иначе Err

Успешный read(0) устанавливает EOF, сохраняя координаты и снимая FIN. Положительный read увеличивает tail на count, оставляя head и устанавливая eof=false, fin=false. При полностью заполненном буфере read(0) возвращает Err: приложение сначала должно освободить место для следующего чтения.

Успешный write увеличивает head на count. Если очередь опустела, оба индекса сбрасываются в ноль; eof и fin сохраняются. Все ошибки — Err(Error.InvalidTransition). Сравнение включает тег Result и активный payload.

Что исполняет проверяющий инструмент

Исходник сохраняется побайтно без изменений. Маленький import-harness позволяет обычному компилятору получить Semantic IR модуля. Сериализованный JSON сохраняется и затем читается независимым интерпретатором. Значения вычисляются из операций, ветвлений, phi и тел вызываемых функций. may_trap и storage_contract не используются как аксиомы.

Поддерживается Semantic IR версии 20, чистый ациклический CFG, скалярные вызовы вспомогательных функций, u32, bool, структура Direction и её Result/Error. Инструкции: constant, struct.construct, struct.field, variant.construct, phi, call, not, eq, ule, ugt, checked add/sub; терминаторы return, branch, jump. phi выбирается по предшественнику. Циклы, рекурсия, эффекты и неподдерживаемые операции дают unknown.

Для u32 интерпретатор использует математические целые с диапазоном [0, 2^32-1]. Переполнение checked-операции создаёт отдельный исход Trap. Каждая ветвь имеет собственное условие достижимости, поэтому неисполняемая арифметика не вызывает trap. Например, readable при tail=0xFFFFFFFF возвращает 0, не вычисляя 2048-tail.

Два SMT-запроса на функцию ищут: достижимый Trap; либо Trap, неверный результат или непокрытый исход. unsat означает доказанное обязательство в этой модели. sat подтверждается отдельным конкретным исполнением того же IR на Python-значениях, без Z3 и без вызова символического интерпретатора. Если свидетельство не воспроизводится, результат — unknown, а не установленный дефект программы. Тайм-аут также даёт unknown и не позволяет эксперименту завершиться успешно.

Отрицательные контроли

Каждый контроль меняет именно Liza-исходник, заново компилируется и сохраняет свой IR. Спецификация остаётся неизменной.

Мутация Нарушение
Удалена проверка tail<=2048 Принято недопустимое состояние
Вместимость 2047-tail Неверный результат или Trap
queued возвращает tail Не учтён уже отправленный префикс
Удалён предел count в read Неверный переход или переполнение
read(0) не устанавливает EOF Потеря EOF
write не продвигает head Потеря прогресса
write не обнуляет пустую очередь Неверное конечное состояние
shutdown допускает непустую очередь Преждевременный FIN

Например, удалённая проверка count допускает tail=1, count=4294967295: конкретное исполнение подтверждает trap на сложении. Значения остальных свидетелей выбирает решатель; фиксированный конкретный вход не является доказательством для всех входов.

Воспроизведение и артефакты

Из корня репозитория, в окружении с зависимостями verification/requirements.txt:

python -m unittest verification.relay_r1.test_model -v
python -m verification.relay_r1.check --output build/verified-relay-r1

Каталог вывода должен быть новым или пустым, чтобы не смешивать артефакты разных запусков. По умолчанию на каждый SMT-запрос отводится 10000 мс; положительный лимит можно изменить через --timeout.

Сохраняются оригинальный исходник, harness, восемь мутантов, фактический IR, SMT-LIB запросы, результаты и конкретные трассы. tools/ содержит копии Python-исходников компилятора и проверяющего инструмента, независимую спецификацию и закреплённые зависимости. Отчёт фиксирует версии Python/Z3/IR, лимит решателя, область проверки и SHA-256 артефактов. Сам отчёт не включён в собственный список хешей; он не подписан и не является сертификатом доказательства или герметичным bundle.

Отдельный workflow запускает тесты и полный R1 на Linux, macOS и Windows и публикует артефакты. Успешный статус требует всех 16 доказанных обязательств и всех восьми подтверждённых мутаций. Обычной сборке Liza решатель не нужен.

Доверенная база и следующий шаг

Доверенная база включает спецификацию, интерпретатор IR, сериализацию IR, Python и Z3. Это проверка конкретных функций конкретного сохранённого IR, не универсальная теорема о компиляторе или любой пользовательской программе.

Ранее созданная математическая модель verification/relay_model продолжает отдельно проверять R = W ++ Q. R1 не связывает её последовательности с реальными чтениями и записями регионального буфера.

Будущий R2 — Byte Conservation должен проверить связь R = W ++ Buffer[head:tail] с фактическими операциями программы. До этого проверенные координаты не означают доказанную сохранность передаваемых байтов.