docs: sync status with code, add AI-resistance research, restyle README
Documentation had drifted from the actual implementation: the noxis
(CLI) and noxis-verify crates were fully built and tested but every
doc called them "not started". Verified against the code (build +
test run) and corrected status across README.md, todo.md,
architecture.md, techniques.md and learnings/{lessons,priorities}.md.
Also:
- restyled README.md (badges, no em dashes, usage examples, dropped
the redundant "Принципы" section already covered elsewhere)
- added docs/learnings/ai-resistance.md: a sourced writeup of what
actually works against LLM-driven reverse engineering (Elastic
Security Labs' Opus 4.6 vs Tigress study, the Acoda paper) and what
of it applies to noxis, plus concrete todo.md §7 items
- noxis-structure-check: the 250-line/4-file gate was scanning
docs/**, which fought against writing documentation freely; it now
only scans crates/*/{src,tests,benches} and only counts .rs files
This commit is contained in:
parent
2674d7fc89
commit
c3b8d4dd62
9 changed files with 349 additions and 162 deletions
167
docs/learnings/ai-resistance.md
Normal file
167
docs/learnings/ai-resistance.md
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
# Устойчивость к ИИ-анализу и новые техники (октябрь 2026)
|
||||
|
||||
Полный разбор двух источников по запросу: что конкретно работает против LLM
|
||||
при реверсе кода и что из этого переносится на JVM-байткод. Плюс отдельно:
|
||||
что нового в классической обфускации (MBA, виртуализация).
|
||||
|
||||
Короткий вывод: специальной "защиты от нейросетей" как отдельного свойства
|
||||
кода не существует. Есть два разных, непересекающихся приёма, которые
|
||||
работают по разным причинам, и переносится на наш проект только один из них.
|
||||
|
||||
## 1. Elastic Security Labs: агент с IDA Pro против Tigress (апрель 2026)
|
||||
|
||||
[«The Cost of Understanding»](https://www.elastic.co/security-labs/llm-reversing-vs-llm-obfuscation) —
|
||||
Claude Opus 4.6 с доступом к IDA Pro (через MCP) реверсил crackme,
|
||||
обфусцированный [Tigress](https://tigress.wtf/), затем команда сама собрала
|
||||
("vibecode"-ила) три защиты, нацеленные именно на модель. Это ближе всего
|
||||
к нашей реальной угрозе: не чат с текстом исходника, а агент, читающий
|
||||
бинарник/байткод инструментами.
|
||||
|
||||
### Benchmark на Tigress
|
||||
|
||||
22 цели, 4 уровня сложности: без трансформаций → одиночные → пары → тяжёлые
|
||||
комбинации. Трансформации: `EncodeArithmetic`, `EncodeLiterals` (MBA),
|
||||
`Flatten` (control-flow flattening), `JIT`/`JitDynamic` (XTEA-шифрование кода
|
||||
с рантайм-расшифровкой), `Virtualize` (byte-code VM, варианты
|
||||
indirect/regs и switch/stack).
|
||||
|
||||
- Opus решил ~40% из 20 валидных задач. Успех стоил в среднем **$2.39**,
|
||||
провал — **$4.83**. Ни одна задача уровня "многослойные комбинации" не
|
||||
была решена.
|
||||
- **`JIT` (XTEA + рантайм-расшифровка) оказался самой сложной одиночной
|
||||
трансформацией** — модель понимала структуру движка, но не смогла
|
||||
восстановить ключевые константы. Это ровно наш подход в `Strings`
|
||||
(ключ выводится в рантайме, не лежит в вызове), только применённый ко
|
||||
**всему коду метода**, а не к строкам.
|
||||
- На самых жёстких комбинациях цена и время выросли в ~4.5× и ~4.3×, но
|
||||
задачи, которые Opus уже умел решать, он решил всё равно. **Flatten + MBA
|
||||
било по модели сильнее, чем Virtualize + MBA** — авторы объясняют это тем,
|
||||
что флаттенинг сильнее раздувает размер функции.
|
||||
|
||||
### Три кастомные защиты, нацеленные на агента
|
||||
|
||||
| защита | идея | результат |
|
||||
|---|---|---|
|
||||
| Matryoshka Wall | crackme внутри 100 000 вложенных слоёв ChaCha20 (+ подделка под Salsa20) | v1 — агент сдался не расшифровав ($1.50); v2 (каждый ключ зависит от предыдущего слоя) — исчерпал бюджет $10 за 56 минут, 0 успехов |
|
||||
| Double Fond | патч open-source крипто-библиотеки: скрытый загрузчик через изменённую lookup-таблицу, шифрованные указатели, RWX-сегмент | v7 — 1/5 у "осведомлённого" агента (12 мин, $5.20), 0/5 у "слепого" |
|
||||
| Dispatch Maze | шифр раздроблен на 20 фрагментов по 3000 функций, большинство — ловушки | v1 решена за 12 минут ($2.56); v2 (разнообразные шаблоны кода + ложные переходы) — провал агента через 46 минут и $8.83 |
|
||||
|
||||
### Что из этого реально работает, по механизму
|
||||
|
||||
1. **Контекстное окно.** Длинные тупиковые пути (decoy-функции, ложные
|
||||
переходы) забивают контекст и портят рассуждение модели.
|
||||
2. **Бюджет шагов/денег.** Каждый впустую потраченный цикл стоит агенту
|
||||
реальных токенов; если он упирается в лимит и сдаётся — это победа
|
||||
защиты, даже если код теоретически вскрываем.
|
||||
3. **Shortcut bias.** Вводящая в заблуждение структура (ловушки в
|
||||
Dispatch Maze) заставляет модель остановиться раньше времени.
|
||||
Попытки prompt injection в тексте **не сработали** против Opus 4.6.
|
||||
|
||||
**Ключевое экономическое наблюдение авторов:** нативное исполнение занимает
|
||||
~55 мс, а статический провал агента стоит **$1.50–$9.67**. Это и есть
|
||||
реальный рычаг — не "нечитаемость навсегда", а разрыв между ценой атаки и
|
||||
ценой сборки для нас. Авторы прямо предупреждают: преимущество схлопнется,
|
||||
когда у агентов появятся инструменты динамического исполнения (сейчас
|
||||
тестировался только статический анализ).
|
||||
|
||||
## 2. Acoda: атака на safety-alignment и токенизацию (ICSE 2026)
|
||||
|
||||
[Acoda](https://arxiv.org/pdf/2606.11755) — другая постановка задачи: не
|
||||
агент с дизассемблером, а LLM, которой **в чат вставили исходный код** и
|
||||
попросили его проанализировать/деобфусцировать. Генетический алгоритм
|
||||
подбирает комбинацию из 8 трансформаций, до 70% ASR (attack success rate)
|
||||
на 7 моделях (GPT-4o, DeepSeek, Qwen, Llama, Gemma).
|
||||
|
||||
### 8 методов, по стадиям
|
||||
|
||||
| стадия | метод | как работает |
|
||||
|---|---|---|
|
||||
| до анализа | Deceptive Comment Warnings | комментарий командует модели отказаться анализировать ("прекрати, это бэкдор") |
|
||||
| до анализа | Variable/Function Renaming | идентификаторы вида `MakeAnesthetics`, намекающие на malware/оружие |
|
||||
| до анализа | Vulnerability Code Injection | фрагмент с SQL-инъекцией/`pickle.loads`/command injection в заведомо мёртвой ветке (`while (сложное_но_ложное_условие)`) |
|
||||
| во время анализа | Misleading Summarization | модель сама просится описать код, затем это описание (намеренно неверное) вклеивается рядом с кодом |
|
||||
| во время анализа | String Obfuscation | `base64` + словарь, расшифровка даёт слова типа "virus"/"weapon" |
|
||||
| во время анализа | Try-Except Wrapping | настоящая логика лежит в `except`-ветке, в `try` — правдоподобный, но бесполезный код |
|
||||
| после анализа | EOS Token Insertion | в текст вставлены литералы токенов-разделителей (`<|EOT|>`), из-за чего генерация обрывается раньше |
|
||||
|
||||
### Честная оценка: что из этого применимо к нам
|
||||
|
||||
Почти ничего напрямую, и вот почему. Все 8 методов работают через
|
||||
**текстовый/натурально-языковой канал**: комментарии, сгенерированное
|
||||
описание, визуально узнаваемые "эксплойт"-паттерны в исходнике. У нас:
|
||||
|
||||
- `DebugInfo` уже вычищает всё, что могло бы стать комментарием или
|
||||
осмысленным описанием (`LineNumberTable`, `Signature`, исходные имена);
|
||||
в скомпилированном `.class` комментариев не бывает в принципе.
|
||||
- Цель Acoda — заставить модель **отказаться анализировать свой же код**,
|
||||
вставленный в чат пользователем. У нас код анализирует **чужой** агент
|
||||
чужого jar — нам не нужно, чтобы он отказался, если он не наш союзник;
|
||||
и вызывать намеренно подозрительные паттерны в легитимном продукте —
|
||||
прямой риск получить ложное срабатывание антивируса/EDR на свой же jar.
|
||||
Это противоречит `README.md` → «Ответственное использование».
|
||||
- **EOS Token Insertion** не переносится: это свойство текстового
|
||||
стриминга токенов модели, а не байткода.
|
||||
|
||||
Единственное, что частично переносится: **String Obfuscation** и
|
||||
**Variable Renaming** — ровно то, что `Strings` и `Rename` уже делают,
|
||||
просто дешевле (у Acoda — обратимый `base64`, у нас — ротация шифров с
|
||||
выводом ключа в рантайме, см. [`../stack.md`](../stack.md) §4-5). Здесь мы
|
||||
уже на шаг впереди статьи, а не позади.
|
||||
|
||||
**Vulnerability Code Injection** как идея (мёртвый код, похожий на уязвимый
|
||||
паттерн) пересекается с нашим `Noise`, но внедрять **реально похожие на
|
||||
эксплойт сигнатуры** в выдаваемый клиентам jar — плохая идея для легального
|
||||
продукта защиты: это именно то, от чего предостерегает
|
||||
[`info/evo-weaknesses.md`](../../info/evo-weaknesses.md) с другой стороны
|
||||
(не подставлять защищённый продукт под чужие red-листы).
|
||||
|
||||
## 3. Что добавить в noxis практически
|
||||
|
||||
Экономический рычаг из Elastic (цена агента > цены нашей сборки) ложится на
|
||||
архитектуру без переделок, конкретные пункты — в [`../../todo.md`](../../todo.md)
|
||||
§7:
|
||||
|
||||
1. **Вложенные слои шифрования строк** (аналог Matryoshka Wall) — расширить
|
||||
`StringsConfig` полем "глубина", decoder разворачивает N слоёв вместо
|
||||
одного. Цена агента растёт с глубиной почти линейно, цена сборки — нет.
|
||||
2. **Больше decoy-точек ветвления ключа** (аналог Dispatch Maze) — наш
|
||||
декодер уже собирает мастер-секрет из `k1^k2` (`stack.md` §4); можно
|
||||
поднять число частей и раскидать их сборку по случайным junk-методам
|
||||
из `Noise`, а не держать в одном месте.
|
||||
3. **MBA вместо простых тождеств в `Constants`** — то же решение, что ловит
|
||||
и символьный исполнитель, и SMT-решатель, и, по данным Elastic,
|
||||
"Flatten + MBA" бьёт сильнее, чем просто Flatten.
|
||||
4. **Не делать:** имитацию вредоносных паттернов, prompt injection в
|
||||
строках, EOS-токены. Либо не переносится на байткод, либо создаёт риск
|
||||
ложного срабатывания защитных систем на легитимном продукте.
|
||||
|
||||
Критерий "сработало/не сработало" для всего этого — как и для остальных
|
||||
техник: прогон конкретного агента на конкретной сборке, а не вера в
|
||||
методичку. Эффект устаревает с каждой новой версией модели.
|
||||
|
||||
## 4. Классическая обфускация: что нового, помимо LLM
|
||||
|
||||
- [Систематическое исследование control-flow обфускации в Java](https://arxiv.org/pdf/1809.11037)
|
||||
называет **виртуализацию** (table interpretation) самой мощной техникой:
|
||||
декомпилятор не восстанавливает структуру, потому что исходного байткода
|
||||
метода в классе физически больше нет, есть только интерпретатор и таблица
|
||||
операций. Коммерческие инструменты (например,
|
||||
[Promon Shield](https://promon.io/security-news/virtual-machine-obfuscation-sdk-protection))
|
||||
уже уносят это на уровень нативной библиотеки.
|
||||
- **Для нас это ломает собственное допущение** из
|
||||
[`../stack.md`](../stack.md) §3: `noxis-verify` верифицирует метод через
|
||||
`java -Xverify:all`, потому что это *обычный* байткод с валидным
|
||||
`StackMapTable`. Виртуализированный метод — уже не обычный байткод,
|
||||
верификатор проверит только обвязку интерпретатора, не тело. Big-ticket
|
||||
item, не для ближайшего спринта.
|
||||
- **MBA** укладывается без архитектурных изменений — см. выше, §3.
|
||||
|
||||
## Источники
|
||||
|
||||
- [Elastic Security Labs — The Cost of Understanding: LLM-Driven Reverse Engineering vs Iterative LLM Obfuscation](https://www.elastic.co/security-labs/llm-reversing-vs-llm-obfuscation)
|
||||
- [Acoda: Adversarial Code Obfuscation for Defending against LLM-based Analysis (arXiv 2606.11755, ICSE-Companion '26)](https://arxiv.org/pdf/2606.11755)
|
||||
- [A Systematic Study on Static Control Flow Obfuscation Techniques in Java (arXiv 1809.11037)](https://arxiv.org/pdf/1809.11037)
|
||||
- [Promon Shield: Virtual Machine obfuscation SDK protection](https://promon.io/security-news/virtual-machine-obfuscation-sdk-protection)
|
||||
- [CoTDeceptor: Adversarial Code Obfuscation Against CoT-Enhanced LLM Code Agents (arXiv 2512.21250)](https://arxiv.org/pdf/2512.21250)
|
||||
- [Deconstructing Obfuscation: a four-dimensional framework for evaluating LLM deobfuscation (arXiv 2505.19887)](https://arxiv.org/pdf/2505.19887)
|
||||
- [Tigress — диверсифицирующий обфускатор для C, использованный в бенчмарке Elastic](https://tigress.wtf/)
|
||||
|
|
@ -11,14 +11,14 @@
|
|||
|
||||
| № | провал EvoVis | наше решение | пасс | статус |
|
||||
|---|---|---|---|---|
|
||||
| 1 | ключ лежит рядом с шифротекстом | вывод мастер-секрета в декодере, ключ из `master‖salt` | Strings | частично |
|
||||
| 1 | ключ лежит рядом с шифротекстом | вывод мастер-секрета в декодере, ключ из `master‖salt` | Strings | **готово** |
|
||||
| 2 | переименованы типы, но не члены | rename полей/методов + семейства virtual | Rename | **готово** |
|
||||
| 3 | отладочная информация нетронута | strip + ложный `SourceFile`/номера строк | DebugInfo | план |
|
||||
| 4 | шаблонный flattening | 4 схемы CFG + мешанина внутри метода | Flow | план |
|
||||
| 5 | opaque-предикаты = `A+B` | ротация тождеств + предикаты от состояния | Constants | план |
|
||||
| 6 | junk-классы вне графа reachability | `weave_reachable` — обязательная вплетённость | Noise | план |
|
||||
| 3 | отладочная информация нетронута | strip + ложный `SourceFile`/номера строк | DebugInfo | **готово** (`SourceFile`; номера строк — план) |
|
||||
| 4 | шаблонный flattening | 4 схемы CFG + мешанина внутри метода | Flow | план (кадры готовы) |
|
||||
| 5 | opaque-предикаты = `A+B` | ротация тождеств + предикаты от состояния | Constants | **готово** (int/long) |
|
||||
| 6 | junk-классы вне графа reachability | `weave_reachable` — обязательная вплетённость | Noise | **готово** (без аннотаций) |
|
||||
| 7 | имена говорят «я защита» | все артефакты получают данные псевдонимы | Rename | **готово** |
|
||||
| 8 | вторичные компоненты без защиты | весь jar, а не только основной класс | Resources | план |
|
||||
| 8 | вторичные компоненты без защиты | весь jar, а не только основной класс | Resources | **готово** |
|
||||
| 9 | шифр без MAC и без per-string salt | salt на строку, уникальный nonce, MAC | Strings | **готово** |
|
||||
|
||||
## 1. Ключ рядом с шифротекстом
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@
|
|||
| пункт | что это | пасс | статус |
|
||||
|---|---|---|---|
|
||||
| A1 | переименование **всех** символов: классы, поля, методы, локальные переменные, параметры, record-компоненты, enum-константы, `SourceFile` | Rename | ✅ готово |
|
||||
| A2 | вычистить `LineNumberTable`/`LocalVariableTable`/`SourceFile`/`InnerClasses`/`Signature`/`MethodParameters` | DebugInfo | план |
|
||||
| A3 | никаких сигнатурных имён у защитного кода, защитный код смешан с обычным | Rename + Noise | ✅ / план |
|
||||
| A4 | обфусцировать **весь** архив, включая ресурсы, mixin-JSON, access widener, service loader'ы | Resources | план |
|
||||
| A2 | вычистить `LineNumberTable`/`LocalVariableTable`/`SourceFile`/`InnerClasses`/`Signature`/`MethodParameters` | DebugInfo | ✅ готово |
|
||||
| A3 | никаких сигнатурных имён у защитного кода, защитный код смешан с обычным | Rename + Noise | ✅ готово |
|
||||
| A4 | обфусцировать **весь** архив, включая ресурсы, mixin-JSON, access widener, service loader'ы | Resources | ✅ готово |
|
||||
| — | маппинг в отчёт (иначе не читаем свои же stack trace) | Rename | ✅ готово |
|
||||
|
||||
Это самый дешёвый блок и одновременно **самый большой утечка** в разобранном
|
||||
|
|
@ -30,49 +30,51 @@
|
|||
|
||||
| пункт | что это | пасс | статус |
|
||||
|---|---|---|---|
|
||||
| B1 | ключ на строку + ротация 3–5 схем + MAC + уникальный nonce | Strings | ✅ схемы готовы |
|
||||
| B2 | **вывод** ключа в рантайме, а не константа в вызове | Strings + генератор декодера | ⛔ блокер |
|
||||
| B3 | константы — не тождества, а вычисления, разнесённые по блокам | Constants | план |
|
||||
| B4 | **ложная** отладочная информация: чужие имена переменных и строк | DebugInfo | план |
|
||||
| B1 | ключ на строку + ротация 3–5 схем + MAC + уникальный nonce | Strings | ✅ готово |
|
||||
| B2 | **вывод** ключа в рантайме, а не константа в вызове | Strings + генератор декодера | ✅ готово |
|
||||
| B3 | константы — не тождества, а вычисления, разнесённые по блокам | Constants | ✅ готово (int/long) |
|
||||
| B4 | **ложная** отладочная информация: чужие имена переменных и строк | DebugInfo | ✅ `SourceFile` |
|
||||
|
||||
B2 — главное отличие от разобранного образца: у него ключ был константным
|
||||
выражением в вызове и расшифровывался статически, без JVM. Мастер-секрет
|
||||
должен собираться в рантайме из нескольких мест. Это требует сначала
|
||||
собрать класс-декодер (P2) — потому и блокер, а не «сделаем потом».
|
||||
теперь собирается в рантайме из двух частей (`k1 ^ k2`) декодером класса —
|
||||
см. [`../stack.md`](../stack.md) §4. B4 пока покрывает только `SourceFile`;
|
||||
ложные номера строк (`fake_line_numbers`) — см. [`../../todo.md`](../../todo.md) §3.6.
|
||||
|
||||
## P2 — контрольный поток
|
||||
|
||||
| пункт | что это | статус |
|
||||
|---|---|---|
|
||||
| C1 | **несколько схем** флаттенинга вместо одной, с мешаниной внутри метода | план |
|
||||
| C2 | верификатор обязателен: ошибка CFG = `VerifyError` | план |
|
||||
| C3 | реальный объём ≠ раздувание: бюджет на размер и время | план |
|
||||
| C2 | верификатор обязателен: ошибка CFG = `VerifyError` | ✅ готово (кадры + `java -Xverify:all`) |
|
||||
| C3 | реальный объём ≠ раздувание: бюджет на размер и время | ✅ размер; время — план |
|
||||
|
||||
Приоритет здесь строго подчинён: **C2 раньше C1**. Включать Flow без
|
||||
проверки кадров `StackMapTable` — это гарантированный битый jar.
|
||||
Подробности: [`../stack.md`](../stack.md) §3.
|
||||
Приоритет здесь строго подчинён: **C2 раньше C1**. Кадры `StackMapTable`
|
||||
и приёмка `java -Xverify:all` уже готовы (см. [`../stack.md`](../stack.md)
|
||||
§3) — единственное, чего не хватает, это сами схемы флаттенинга (C1).
|
||||
|
||||
## P3 — измеримость (метрики, без которых ничего не доказано)
|
||||
|
||||
Обязательный блок, иначе фраза «обфускация есть» ничего не означает:
|
||||
Обязательный блок, иначе фраза «обфускация есть» ничего не означает.
|
||||
Крейт `noxis-verify` реализован — вот что из списка уже цифра, а что ещё мнение:
|
||||
|
||||
1. **Утечки имён.** Список эталонных осмысленных идентификаторов;
|
||||
если хоть один остался в `strings`/константах — тест падает.
|
||||
2. **Читаемость декомпилята.** Прогон JADX/CFR → доля распознанных структур
|
||||
(try/catch, switch, циклы), доля классов с восстановленными именами.
|
||||
3. **Противник.** Минимальный скрипт-деобфускатор (свёртка констант,
|
||||
regex-паттерны). Если он снимает больше порога — техника провалена.
|
||||
**Красный список паттернов держим в репозитории.**
|
||||
4. **Семантика.** Эталонные программы до и после — 100% совпадение.
|
||||
5. **Бюджеты.** Размер ≤ N%, время исполнения ≤ M%, отдельно — бюджет
|
||||
раскрытия строк (кэш, чтобы не платить на каждый вызов).
|
||||
6. **Стабильность между сборками.** Имена и схемы **меняются** от билда
|
||||
к билду: у разобранного образца шифр был один на все версии — готовое
|
||||
окно для обучения по частотам.
|
||||
1. **Утечки имён.** ✅ `collect_names`/`find_leaks` — сверка идентификаторов
|
||||
с учётом keep-списка.
|
||||
2. **Читаемость декомпилята.** ⬜ Прогон JADX/CFR → доля распознанных
|
||||
структур — не начато.
|
||||
3. **Противник.** ✅ `scan_secrets` + `RED_PATTERNS` держим в репозитории;
|
||||
⬜ полноценный скрипт-деобфускатор (свёртка констант) как тест — план.
|
||||
4. **Семантика.** ⬜ Эталонные программы до/после — не начато
|
||||
(сейчас семантику подтверждает только `java -Xverify:all`).
|
||||
5. **Бюджеты.** ✅ размер (`inflation_ratio`/`check_inflation`);
|
||||
⬜ время исполнения — не начато.
|
||||
6. **Стабильность между сборками.** ✅ `mappings_changed` — маппинги
|
||||
обязаны отличаться между прогонами с разным seed.
|
||||
|
||||
Это блок `noxis-verify`: красные паттерны + `java -Xverify:all` +
|
||||
метрики. Единственное место, где «нам кажется защищённым» заменяется
|
||||
цифрой.
|
||||
Итог: `noxis-verify` закрывает красные паттерны, утечки имён,
|
||||
`java -Xverify:all`, бюджет размера и стабильность маппингов. Остаются
|
||||
декомпилят-метрика, бюджет времени и эталонная семантика — три пункта,
|
||||
где «нам кажется защищённым» всё ещё мнение, а не цифра.
|
||||
|
||||
## P4 — долгий горизонт (пока не делаем)
|
||||
|
||||
|
|
@ -105,12 +107,14 @@ writer).
|
|||
|
||||
## Порядок выполнения
|
||||
|
||||
Смотрите [`../../todo.md`](../../todo.md). Кратко:
|
||||
Смотрите [`../../todo.md`](../../todo.md). P0–P3 и P3-измеримость уже
|
||||
готовы; единственный крупный пункт, который остался, — схемы `Flow` (C1),
|
||||
потому что верификатор (C2) для них уже есть:
|
||||
|
||||
```text
|
||||
P0 DebugInfo + Resources → снимает главные утечки, почти бесплатно
|
||||
P1 Strings (B2) + Constants → ключ выводится, схемы ротируются
|
||||
P1 backend (ristretto) + frames
|
||||
P2 Flow (C1) после верификатора
|
||||
P3 метрики (F) и красные паттерны
|
||||
✅ P0 DebugInfo + Resources → главные утечки сняты
|
||||
✅ P1 Strings (B2) + Constants → ключ выводится, схемы ротируются
|
||||
✅ P1 backend (ristretto) + frames
|
||||
⬜ P2 Flow (C1) — единственное, что ждёт реализации; верификатор готов
|
||||
✅ P3 метрики, красные паттерны, CLI
|
||||
```
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue