Шум в эмбеддингах не защищает данные: проверил 8 схем, и при 100 известных парах узнаётся ~90% документов

Коротко. Если хранить эмбеддинги с добавленным шумом, текст по ним восстановить трудно, но это не значит, что данные защищены. Я измерил, можно ли по защищённой записи узнать, какому документу она принадлежит, если атакующий знает часть соответствий (для основного сравнения 1000 из 5183 документов, ~19%). Для шума узнаётся 99% записей, даже когда качество поиска упало вдвое. При 100 известных парах (2% корпуса) узнаётся около 90%.
С чего всё началось
Векторные базы для RAG и поиска хранят эмбеддинги документов. Если утекла такая база, возникает вопрос: что можно узнать по векторам? Есть работа про vec2text (Understanding and Mitigating the Threat of Vec2Text to Dense Retrieval Systems), где показали: из эмбеддинга можно восстановить текст. Её авторы предложили защиты: добавить шум, сжать векторы (product quantization) или применить секретное линейное преобразование. По их данным, шум сводит точное восстановление текста к 0%, а качество поиска почти не страдает (0,748 → 0,730 по top-10).
Но восстановить текст и узнать, какому из известных документов принадлежит запись, это разные задачи. Защита может пройти первую проверку и полностью провалить вторую. Для публичных или частично утёкших корпусов (документация, научные статьи, ранее утёкшие базы) вторая задача реальна: атакующему нужны не неизвестные тексты, а сопоставление записи с текстами, которые он уже знает.
Я написал стенд, который не оценивает цену защиты, а запускает атаку и смотрит, что она реально предотвращает.
Как проверял
8 схем: гауссов шум, шум после секретного поворота, SAP/DCPE (шум, равномерный в шаре), бинарный LSH, случайная проекция, product quantization (PQ), секретная нелинейность, k-анонимное квантование.
Две коллекции BEIR (SciFact, 5183 документа; NFCorpus, 3633) и две модели эмбеддингов (all-MiniLM-L6-v2, bge-small-en-v1.5). Всё на английском.
Для каждой схемы менял силу защиты и на каждом шаге смотрел две вещи: сколько качества поиска осталось и может ли атакующий понять, какому документу принадлежит каждая защищённая запись.
SAP/DCPE я реализовал сам по алгоритму 2 из статьи Fuchsbauer, Ghosal, Hauke, O’Neill (SCN 2022). Проверялась научная схема, а не какой-либо коммерческий продукт.
Самопроверки: при нулевой силе защиты качество, соседи, кластеры и узнаваемость должны быть ровно 100%, иначе замер прерывается. Эти проверки поймали две реальные ошибки: k-means менял разбиение при масштабировании, а 2,2% NFCorpus оказались дубликатами, которые по построению неразличимы (я исключил их из подсчёта).
Условия замера: коллекция SciFact (5183 документа), модель all-MiniLM-L6-v2, атакующий знает 1000 пар «документ — защищённая запись» и подбирает линейное отображение обратно в пространство эмбеддингов.
Результат 1. Шум, который побеждает восстановление текста, не побеждает узнавание
Доля узнанных записей в точке, где качество поиска упало вдвое:
Схема | Узнано |
|---|---|
Гауссов шум | 99,9% |
Секретный поворот + шум | 99,2% |
SAP / DCPE | 98,7% |
Бинарный LSH | 81,1% |
Случайная проекция | 60,8% |
Product quantization | 27,0% |
Секретная нелинейность | 100% при всех настройках |
k-анонимное квантование | меньше 1%, но до 50% качества не доходит |
Порядок схем одинаков на всех четырёх сочетаниях «коллекция × модель», абсолютные числа плавают. Вид шума ничего не меняет: равномерный в шаре (как задуто в DCPE), обычный гауссов и гауссов после поворота дают почти одинаковые кривые.

Вывод: если подбирать шум по метрикам восстановления текста, в таблице оценки будут нули, а узнаваемость при этом будет 99%.
Результат 2. Секретное преобразование не спасает, если у атакующего есть пара сотен известных пар
Секретный поворот полностью побеждает наивную атаку: сопоставление по косинусу с публичным корпусом падает со 100% до 0,0%. Но атака с линейным выравниванием (метод наименьших квадратов) по-прежнему даёт 100%.
Чтобы найти, где ломается моя линейная атака, я добавил секретную нелинейность tanh(gain · Qv). Она не сломалась: узнаваемость 100% на всём диапазоне параметра gain (разброс в 2000 раз, от почти линейной до насыщенной), а качество поиска не падало ниже 90%. Нелинейность одинаково бесплатна и для защитника, и для атакующего.
Сколько нужно знать атакующему. Ему нужно около 100–200 известных пар «документ — защищённая запись» из 5183, то есть 2–4% корпуса. Доля узнанных записей при настройке, оставляющей ~80% качества:
Известных пар | % корпуса | SAP | Гауссов | Поворот | Проекция | LSH | PQ |
|---|---|---|---|---|---|---|---|
25 | 0,5% | 2% | 2% | 2% | 1% | 1% | 0% |
50 | 1% | 38% | 34% | 34% | 22% | 15% | 8% |
100 | 2% | 91% | 89% | 88% | 72% | 61% | 37% |
200 | 4% | 100% | 98% | 98% | 96% | 92% | 67% |
1600 | 31% | 100% | 100% | 100% | 100% | 100% | 91% |

Это важно, потому что секретное линейное преобразование, зависящее от пользователя, как раз то, что предлагает работа про vec2text. Против атакующего с ~100 известными парами оно не даёт защиты от узнавания вообще.
Результат 3. Помогает только потеря информации, и PQ здесь лучший, но не бесплатный
Проекция, LSH и PQ двигают кривую, потому что выбрасывают информацию, а не добавляют шум. PQ даёт 27,0% узнаваемости при половине качества против 60,8% у проекции и ~99% у шумовых схем.
Но настройка решает. В работе про vec2text PQ «полностью защищает» от восстановления без потери качества (0,748 → 0,749). Это режимы высокой точности, и в них узнаваемость почти полная:
Подвекторов | Байт на вектор | Осталось качества | Узнано |
|---|---|---|---|
192 | 192 | 100% | 100% |
48 | 48 | 96% | 100% |
32 | 32 | 93% | 99,8% |
16 | 16 | 77% | 92,0% |
8 | 8 | 59% | 44,5% |
4 | 4 | 41% | 9,7% |
Чтобы опустить узнаваемость ниже 50%, нужно сжать до ~8 байт на вектор и потерять около 41% качества поиска. Возможно, такая цена подходит. Но это цена, а не бесплатный обед.
Ещё одно предостережение: защита PQ зависит от корпуса. При тех же 50% качества узнаваемость составила 27,0% и 25,4% на SciFact, но 1,6% и 1,7% на NFCorpus, разброс в 17 раз. Моё объяснение: NFCorpus тематически однороден (питание и медицина), грубое квантование склеивает похожие документы в одинаковые коды, и различать их уже нечем. Если это так, защита PQ получается побочным эффектом однородности корпуса, а не свойством схемы. Меряйте на своём корпусе.
Результат 4. Доказуемая граница возможна, но моя реализация хуже обычного PQ
Всё выше эмпирика: число, которое умная атака может сдвинуть. Я захотел границу, которую сдвинуть нельзя, и построил k-анонимное квантование: документы намеренно собираются в группы не меньше k, и хранится один общий вектор на группу. Если у k документов запись побайтно одинакова, никакая атака их не разделит, узнаваемость не выше mean(1/размер группы) ≤ 1/k до всякого запуска.
Граница выполняется: при k=2 граница 29,8%, измерено 8,3%; при k=3 граница 16,5%, измерено 0,5%. Но моя конструкция проигрывает PQ:
Осталось качества | Узнано | |
|---|---|---|
k-анонимность, k=2 | 34% | 8,3% |
PQ, m=4 | 41% | 9,7% |
Причина в том, что я собирал группы через k-means с последующим слиянием мелких, и размеры получились перекошены (минимум 2, медиана 3, среднее 6,2, длинный хвост). Граница задаётся самой маленькой группой, а цена по качеству берётся со средней, поэтому крупный хвост тратит качество и ничего не покупает. Будет ли лучше честное сбалансированное назначение, я не проверял и не утверждаю.
Что здесь не измерено
Это важнее всего. Мой стенд проверяет узнавание: по защищённой выгрузке и набору известных текстов можно ли сказать, какая запись какому документу принадлежит. Он не проверяет, можно ли восстановить текст неизвестного документа. Это разные утверждения, и вторым чаще торгуют производители защит.
Атаке нужны тексты-кандидаты. Это реалистично для публичных или частично утёкших корпусов (RAG по открытой документации, научные статьи, ранее утёкшие базы) и нереалистично для корпуса, к которому у атакующего нет доступа вообще.
Все 8 схем геометрические: на сервере лежит что-то, пространственно связанное с исходным вектором. Поэтому атака работает: где есть геометрия, есть отображение назад, и я его подбираю. Схемы вне геометрии (гомоморфное шифрование, PIR, многосторонние вычисления, ORAM) мой стенд атаковать не может, и пустой результат против них ничего бы не значил. «Восемь защит провалились» не значит «ничего не работает». Работающее дорогое и вне этой работы.
Две коллекции, две модели, всё на английском, по меркам продакшена мало.
Только «снимок»: одна выгрузка. Без наблюдения за запросами и активного воздействия.
Линейная атака даёт нижнюю оценку возможностей атакующего: более сильная сделала бы числа хуже. Но секретное преобразование, разработанное специально против выравнивания, возможно, прошло бы.
Восстановление текста целиком (GTR-base + vec2text) я пробовал, но эксперимент неубедительный: потолок на чистых эмбеддингах получился 45,9% по token-F1 и 0% точных совпадений при 92% в статье про vec2text, так что различать условия было нечем. Причины, которые я нашёл: обрезка до 32 слов вместо 32 токенов, выключенный beam search и инвертор, обученный на Natural Questions, а не на научных аннотациях. Пока это не переделано, считайте восстановление текста по восстановленным векторам открытым вопросом, а не результатом.
Что из этого следует
Не оценивайте защиту эмбеддингов только по восстановлению текста. Проверяйте узнавание на корпусе, похожем на ваш.
Секретное преобразование без остального не защита, если у атакующего может оказаться несколько сотен известных пар.
Если защита нужна, платите качеством поиска: quantization даёт реальный эффект, но на высоких настройках его нет, и результат зависит от корпуса.
Данные, которые нельзя отдавать, проще не отдавать вовсе: держать модель и базу у себя.
Побочное наблюдение. Более сильная модель оказалась хрупче: bge-small-en-v1.5 (nDCG@10 = 72,0 на SciFact) теряет половину качества при 100% относительного шума, а более слабая all-MiniLM-L6-v2 (64,5) доживает до 150%. Узнаваемость от этого не зависит. Преимущество хорошей модели в тонких различиях, шум стирает их первыми, а узнавание грубая задача.
Как повторить. Всё считается на обычном процессоре, без видеокарты, самый долгий шаг, векторизация коллекций, около 5 минут на коллекцию на двух ядрах. Код и результаты: github.com/makltd123/semantic-cryptography. Если у вас получились другие числа, пришлите: для этого стенд и написан.
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.