Ad 1136 Geometric Watermark

Обновлено: 2026-08-02

Геометрический forensic-watermark в моделях конструктора — спайк (AD-1136)

Статус: спайк закрыт, решение принято — НЕ ВНЕДРЯЕМ
(основатель, 2026-07-31; docs/adr/ad-1136-geometric-watermark-not-implemented.md).
Причина — § 4.3: перенос детали на столе слайсера, штатное действие перед
печатью, сбивает чтение метки до случайного угадывания, поэтому схема даёт
ложное чувство защищённости. Документ остаётся как результат замеров, а не как
открытый вопрос: подключать описанное здесь к экспорту нельзя, и повторный
спайк на ту же тему не нужен — условия пересмотра названы в § 5 ADR.
Родитель — эпик AD-1133 (защита моделей: provenance + юридическая,
не DRM); соседи по эпику — LICENSE.txt в архиве (AD-1134) и метка
происхождения в заголовке STEP / имени тела STL (AD-1265) — они остаются
в силе.

1. Вопрос, на который отвечает спайк

Можно ли спрятать идентификатор пользователя в самой геометрии детали так,
чтобы одновременно выполнялось всё:

  1. не ломает печать — деталь печатается как прежде;
  2. не меняет аэродинамику — обводы остаются теми же;
  3. не виден глазом на напечатанной детали;
  4. извлекается из файла — по файлу можно назвать владельца.

Тикет прямо допускает отрицательный ответ: если незаметность и извлекаемость на
наших размерах несовместимы — это честный результат. Они совместимы.
Несовместимо другое, и об этом § 5.

2. Что померили и на чём

Стенд — обычный экспорт v2-редактора (борт размахом 1 м, фюзеляж 0.8 м):
ASCII-STL 32.5 МБ, 385 812 вершин; STEP 623 КБ, 6 995 контрольных точек.

Разрешающая способность самих форматов (замер, не оценка):

Формат Как пишутся координаты Наименьший различимый шаг
ASCII-STL (OCCT) %.6e — 7 значащих цифр (4.259878e+02) ~10⁻⁴ мм на габарите 0.4 м, ~10⁻³ мм на 1.5 м
STEP (OCCT) полная двойная точность (425.98775446637) ~10⁻¹¹ мм

То есть формат не является ограничением: в него влезает шаг модуляции на
порядки мельче того, что различает печать.

3. Схема PoC

Слепая (blind) QIM-модуляция по значению координаты. Для каждой вершины:

индекс бита = hash(round(X/Δ), round(Y/Δ)) mod N
сам бит     = чётность round(Z/Δ)          → Z «дотягивается» до нужной ячейки

Три свойства, ради которых схема выбрана именно такой:

  • ключ по X/Y, а меняется Z — одинаковые вершины соседних фасетов сдвигаются
    одинаково, и меш остаётся водонепроницаемым без разбора смежности (в ASCII-STL
    вершина дублируется в каждом фасете). Замер: вырожденных треугольников после
    встраивания — 0 (до встраивания тоже 0);
  • извлечение слепое — исходный файл не нужен;
  • адресация по позиции, а не по порядку вершин — отрезанный кусок детали
    несёт метку целиком. Для нашего экспорта по печатным деталям (AD-1128, борт
    режется на сегменты) это не бонус, а необходимое условие.

4. Результаты замеров

Прогон: node scripts/ad1136_watermark_poc.mjs <файл.stl> [--step=мм] [--bits=N]

4.1 Ёмкость и стоимость (Δ = 0.01 мм, 128 бит)

Величина Значение
вершин обработано 385 812
покрыто бит 128 / 128
голосов на самый «бедный» бит 2 744
прочитано из нетронутого файла 100 %
сдвиг поверхности max 10 мкм, средний 5 мкм
вырожденных треугольников 0
прирост размера файла −1.2 % (перезапись чисел, не рост)
время встраивание 0.54 с, извлечение 0.16–0.29 с

Ёмкость не является ограничением: 512 бит читаются так же на 100 %, самый
бедный бит собирает 545 голосов.

4.2 Незаметность — сравнение с физикой печати

Сдвиг 10 мкм (Δ = 0.01 мм) против того, что умеет FDM:

Величина Порядок Отношение к метке
высота слоя 100–200 мкм в 10–20 раз крупнее
ширина экструзии (сопло 0.4) 400–450 мкм в 40 раз крупнее
шероховатость поверхности Ra 10–20 мкм того же порядка или крупнее
шаг позиционирования XY ~50 мкм в 5 раз крупнее
цена деления штангенциркуля 10–20 мкм того же порядка

Ключевая строка — шероховатость: метка мельче собственного микрорельефа
печати
, то есть на напечатанной детали её физически нечего увидеть и нечем
измерить. Аэродинамика: 10 мкм на хорде 200 мм — это 5·10⁻⁵ относительной
деформации обвода, на два порядка ниже шероховатости той же поверхности; вклад в
поляру неотличим от нуля любым доступным нам методом (ни XFOIL, ни VLM таких
величин не различают в принципе).

Пункты 1–4 из § 1 выполняются одновременно. Ответ на вопрос спайка —
положительный.

4.3 Устойчивость — где схема ломается (главный результат)

Доля верно прочитанных бит после операции над файлом. Идентификатор читается
только при 100 %; ~50 % — это случайное угадывание, то есть метки нет.

Операция над файлом Δ = 0.002 мм Δ = 0.01 мм Δ = 0.05 мм
копия файла 100 % 100 % 100 %
сдвиг по Z на целое число ячеек 100 % 100 % 100 %
перенос детали на (0.137, 0.041, 0.213) мм 44 % 48 % 53 %
шум ±2 мкм (пересчёт координат) 48 % 100 % 100 %
шум ±20 мкм (грубый пересчёт/ремеш) 53 % 50 % 100 %
масштаб ×1.001 (подгонка размера) 99 % 95 % 74 %

Читается это так:

  • Δ задаёт компромисс, а не качество. Мельче — незаметнее, но ломается от
    любого пересчёта координат; крупнее — переживает шум, но подбирается к
    разрешению печати и всё равно не переживает масштабирование.
  • Ни одно значение Δ не спасает от переноса и масштабирования. Оба — один
    клик в любом mesh-редакторе или слайсере (и, что важнее, штатная операция:
    человек двигает деталь на столе принтера).
  • Настоящий ремеш/децимация (не эмулированные здесь шумом, а перестроение сетки)
    убивает метку тем более: она живёт в координатах ИСХОДНЫХ вершин.

⚠ Методическая заметка: первый прогон PoC «доказал» устойчивость к переносу на
7.3 мм — потому что 7.3 мм это ровно 730 ячеек сетки, и чётность сохранилась.
Ложно-успешный замер, атака переписана на некратное смещение. Строка «сдвиг на
целое число ячеек» оставлена в таблице как контроль: она показывает, что схема
инвариантна к сдвигу ПО СЕТКЕ и ни к какому другому.

5. Выводы

  1. Незаметность и извлекаемость на наших размерах совместимы — с запасом в
    один-два порядка по каждому из четырёх требований § 1. Это НЕ то место, где
    идея упирается.
  2. Упирается она в устойчивость. Метка переживает то, что делает
    недобросовестный пользователь ЛЕНИВО (скачал → выложил как своё, сконвертировал
    формат, разрезал на печатные детали), и не переживает того, что делает
    пользователь ОБЫЧНО (подвинул деталь на столе, подогнал масштаб) — не говоря
    о том, что сделал бы намеренно (ремеш в 3 клика). То есть это forensic-метка
    против ленивой перепубликации, а не защита.
  3. Секретность схемы — не защита. Универсальная атака у этого класса схем
    одна и тривиальна: пересчитать координаты (шум/переквантование/ремеш).
    Стойкость не в том, что метку нельзя снять, а в том, что снимать её никто не
    станет, пока не знает, что она есть.
  4. Это НЕ замена AD-1265, а другой слой. Заголовок STEP / имя тела STL —
    ЯВНАЯ метка: её видно, её легко удалить, но она честная и работает как
    provenance. Геометрическая метка — наоборот: снять её случайно нельзя, а
    найти без исходного ключа тоже нельзя. Слои дополняют друг друга и не
    конкурируют.

6. Чего внедрение будет стоить (если решат внедрять)

Это оценка, а не план: тикет — спайк, продовой части в нём нет.

  • Только STL. PoC работает по вершинам сетки. Для STEP та же схема ложится на
    контрольные точки (точности формата хватает с запасом), но любой пересчёт
    B-rep в CAD её снимает; отдельный замер по STEP не делался.
  • Память. Метку приходится ставить ПОСТ-ФАКТУМ, текстом поверх готового
    блоба: сетку пишет OCCT, до неё не дотянуться. Для 32 МБ STL это ~65 МБ
    JS-строки в воркере, который и без того упирается в порог перезапуска по
    WASM-heap (AD-1140, 512 МБ). Это прямо противоречит конструкции AD-1265, где
    метка происхождения читает только КРАЯ блоба именно ради независимости цены от
    размера модели. Потоковая (по-чанковая) реализация — отдельная работа.
  • Секрет. В проде хэш обязан солиться секретом из web/config.py, иначе
    сопоставить метку с пользователем сможет любой, кто видел код. Соль — новый
    секрет в контуре эксплуатации.
  • Юридически — решение основателя, не исполнителя. Скрытая метка в файле
    пользователя без раскрытия в «Условиях использования» (раздел 19, AD-1132) —
    это скрытое отслеживание. Раскрытие метки её forensic-ценность НЕ снижает
    (стойкость не зависит от секретности факта, § 5.3), но снижает
    репутационный риск до нуля. Внедрять без явного решения по этому пункту
    нельзя.

7. Решение основателя (2026-07-31): не внедряем

Спайк спрашивал три вещи — внедряем ли вообще, раскрывать ли метку в «Условиях
использования» и как резать работу на тикеты. Ответ на первый вопрос
отрицательный, поэтому два остальных сняты: ни правки раздела 19, ни
потоковой реализации, ни соли в конфиге не будет.

Обоснование — § 4.3: перенос детали на некратное смещение оставляет 48 %
верно прочитанных бит, то есть метки не остаётся. Двигают деталь на столе
слайсера все и всегда, это первое действие перед печатью, а не атака. Схема,
которая исчезает у того, кто файл просто напечатал, и работает только против
того, кто переслал его байт-в-байт, даёт ложное чувство защищённости при
настоящей цене внедрения (§ 6).

Полная формулировка решения, что остаётся в силе из эпика AD-1133 и при каких
условиях к теме уместно вернуться —
docs/adr/ad-1136-geometric-watermark-not-implemented.md. Отдельного тикета
реализации не заводить.