Я попытался расшифровать манускрипт Войнича. Спойлер: не расшифровал — но выяснил, почему это не удалось и АНБ

от автора

Код и данные: https://github.com/fvy8cz864x-art/voynich-lab

Манускрипт Войнича почти сто лет отбивает атаки профессиональных криптографов, лингвистов и энтузиастов с Reddit. В его послужном списке — криптоаналитики Блетчли-парка и взломщики японских военных шифров, а также штатные сотрудники АНБ, которые в 1970-х официально признали задачу нерешённой. У меня не было ни их квалификации, ни ресурсов. Зато был чистый Python, транскрипция всего манускрипта и полдня на то, чтобы честно посчитать статистику вместо того, чтобы гадать по картинкам с русалками и незнакомыми растениями.

Итог заранее: расшифровки не будет. Будет разбор того, как один и тот же статистический тест сначала «доказал», что в тексте есть смысл, а потом, после более жёсткой проверки, сам же это опроверг. По-моему, это честнее очередной попытки прочитать текст как латынь наоборот.

Что такое манускрипт Войнича

Манускрипт Войнича — рукопись примерно из 240 сохранившихся страниц, исписанная неизвестным письмом на неизвестном (или искусственном) языке. Хранится в библиотеке редких книг Бейнеке Йельского университета под шифром MS 408. Название получила по имени книготорговца Уилфрида Войнича, который приобрёл её в 1912 году в иезуитской коллекции под Римом. Радиоуглеродный анализ пергамента, проведённый Аризонским университетом, датировал изготовление телячьей кожи 1404–1438 годами — то есть манускрипт точно не позднейшая подделка на современном материале, хотя вопрос о времени и способе нанесения самого текста это не закрывает.

Иллюстрации разбивают рукопись на разделы, которые исследователи условно называют травником (рисунки растений), астрономическим/астрологическим (диаграммы, зодиакальные круги), «купальным» или биологическим (обнажённые фигуры в сосудах, соединённых трубками) и разделом рецептов (короткие абзацы со звёздочками на полях). Текст при этом визуально однороден: одни и те же буквы, похожий ритм слов вне зависимости от раздела — это само по себе странно для рукописи, где разные темы в обычных языках обычно тянут за собой разную лексику.

Список тех, кто пробовал её взломать, впечатляет и удручает одновременно: от Уильяма Ф. Фридмана, взломавшего японский дипломатический шифр PURPLE, до штатных лингвистов АНБ. Именно они написали монографию Мэри Д’Империо «An Elegant Enigma» (1978), изданную агентством, — на тот момент самый полный обзор попыток взлома манускрипта. С тех пор список «расшифровок» в интернете не иссякает — от протороманских языков до искусственного гибрида, — но ни одна не проходит проверку независимым переводом второго отрывка текста тем же методом.

Инструменты

Всё сделано на чистом Python (stdlib: collections, math, random, statistics, re) плюс matplotlib для двух графиков — никаких внешних NLP-библиотек и без интернета для основных расчётов (только на шаге загрузки корпуса). В качестве текста использовалась EVA-транскрипция Такахаши — построчная расшифровка глифов манускрипта в буквы латиницы. Первоисточник — Interlinear Archive транскрипций манускрипта на voynich.nu (изначально собран Габриэлем Ландини и Хорхе Стольфи); для удобства воспроизводимости я скачал её из зеркала-репозитория github.com/alephmembeth/voynich. После очистки (снятие меток страниц, маркеров неуверенного чтения !, *, %, склейка слов, перенесённых через границу строки) получилось 33615 слов, размеченных по 225 сторонам листов. Отдельно на первом заходе я работал с меньшей выборкой в кодировке Currier (17526 слов, только разделы «купальный» и «рецепты») — часть цифр ниже относится именно к ней, это оговорено в тексте.

Акт 1: аномалии

Первое, что бросается в глаза при подсчёте статистики слов — это межбуквенная (условная) энтропия второго порядка H2|1: насколько буква b предсказуема по предыдущей букве a. У меня на первой, малой Currier-выборке получилось H2|1 = 2.41 бит для всего текста, при этом внутри отдельных разделов — 2.20 бит («купальный») и 2.48 бит («рецепты»). Число 2.48 я потом использовал как ориентир для проверки синтетики.

Насколько это мало? На независимом ресурсе voynich.nu (страница «what we learn from entropy», подсчёт на разных вариантах транслитерации) условная энтропия для нескольких реальных языков — латыни XVI века, классической латыни Плиния, итальянского Данте и современного немецкого — лежит в диапазоне 3.0–3.3 бит, тогда как сам манускрипт (в зависимости от алфавита транскрипции) даёт 1.8–2.1 бит. Разница огромная: буквы в войничских словах предсказывают друг друга значительно сильнее, чем в любом известном естественном языке — то есть слова гораздо более «шаблонные» и однообразные по внутренней структуре.

Вторая аномалия — повторы. В моей малой выборке 0.91% соседних пар слов — буквально одно и то же слово два раза подряд («qokeedy qokeedy» — характерный пример из литературы по манускрипту, встречается в тексте многократно). Явление известное и обсуждаемое в сообществе voynich.ninja — вопрос, насколько это больше нормы для естественного языка, там прямо называют открытым; я не нашёл верифицируемой количественной оценки для сравнения и потому не привожу здесь конкретный множитель — только собственную цифру 0.91% (0.76–1.15% по разделам) как факт, который дальше нужно было объяснить.

Акт 2: слотовая модель бьёт форму

Гипотеза, которую разрабатывали ещё Currier и позже Хорхе Стольфи: войничское «слово» — не случайная строка, а собирается по жёсткой цепочке слотов: [префикс][gallows-глиф][ядро][суффикс], где gallows — это четыре особых высоких глифа (в EVA — k, t, p, f). Я разложил каждое слово этой малой выборки на такие слоты, обучил марковскую цепь переходов между ними (какой gallows следует за каким префиксом, какое ядро — за каким gallows, и так далее) и сгенерировал 25000 синтетических «слов».

Результат обескуражил в хорошем смысле: синтетика получила H2|1 = 2.49 бит — при цели 2.48 ± 0.15 отклонение составило всего 0.01. Символьная энтропия H1 совпала до сотых (3.81 у обоих). Распределение длин слов почти легло одно на другое (пик на 4–5 буквах у обоих: 24.6%/24.2% у оригинала против 23.7%/22.2% у синтетики). Иначе говоря: чисто механическая, бессмысленная по построению цепочка «слот → слот» полностью воспроизводит статистику отдельного войничского слова. Для формы слова никакого «языка» не требуется — достаточно жёсткой грамматики слотов.

Заодно эта же малая выборка не подтвердила старую гипотезу verbose-cipher («одна латинская буква = одно войничское слово»): число уникальных слов в разделе («купальный» — 1546, «рецепты» — 3094) в 67–135 раз больше, чем разумный размер латинского алфавита (23 буквы), а информационная ёмкость типового слова (8.6–9.8 бит по H1 распределения типов) намного выше, чем энтропия одной буквы английского эталонного корпуса (4.17 бит). Слишком много уникальных «слов» и слишком много информации на «слово» для гипотезы один-к-одному.

Акт 3: ложный сигнал

Форма — механика, ладно. Но что насчёт содержания? Тут я перешёл на полный корпус (33615 слов, все разделы) и три более тонких теста.

Закон Ципфа (ранг-частота слова в log-log, показатель alpha по МНК) дал разочаровывающий результат: у оригинала alpha = 0.72, у английского эталона — 0.83, у синтетики (та же слотовая модель, обученная уже на полном корпусе) — 0.88. Критерий |alpha − 1.0| < 0.2 не прошёл ни один из трёх, а синтетика воспроизвела оригинал ещё хуже, чем ожидалось (разница 0.166 при пороге 0.15).

Ранг-частота слов в log-log: оригинал, синтетика, английский

Ранг-частота слов в log-log: оригинал, синтетика, английский

Взаимная информация соседних слов (MI, топ-500 самых частых слов каждой выборки) выдала интересную методическую ловушку: сырые значения получились подозрительно большими (2.96 бит у оригинала, 3.95 у английского) — и 2.73 бит даже у синтетики, которая по построению генерирует слова независимо друг от друга! Это классическое смещение оценки MI при малой выборке относительно числа совместных ячеек (500×500). Я использовал синтетику как встроенный измеритель этого шума и вычел его: избыток оригинала над шумом — всего +0.23 бит при пороге значимости 0.3, то есть межсловных зависимостей сверх слотовой модели статистически не нашлось. У английского избыток +1.23 бит — вот как выглядит настоящая биграммная структура языка на фоне того же шума.

А вот третий тест выстрелил. Burstiness (по методике Монтемурро и Занетте, 2013) — мера кучности редких слов: считается дисперсия расстояний между повторными вхождениями слова в тексте и делится на квадрат среднего расстояния (CV²). Для случайного, «пуассоновского», размещения слова по тексту CV² ≈ 1. Для оригинала CV² = 2.78 — заметно выше единицы, выше английского эталона (1.86) и намного выше независимой синтетики (0.99, ровно как ожидалось от i.i.d.-генератора). Первая реакция: вот оно — слова кучкуются по темам, как в осмысленном тексте. Монтемурро и Занетте в своей настоящей статье 2013 года в PLoS ONE делали похожий вывод на основе анализа ко-встречаемости слов и семантических сетей и осторожно говорили в пользу «подлинного сообщения» в тексте.

Burstiness CV² редких слов: оригинал против синтетики и английского

Burstiness CV² редких слов: оригинал против синтетики и английского

Акт 4: контроль убивает сигнал

Здесь я не остановился на красивом числе 2.78 и устроил ему проверку на прочность — именно тот шаг, который я не увидел ни в одном любительском разборе манускрипта в интернете.

Первый контроль: посчитать burstiness не по всему корпусу разом, а отдельно внутри каждого раздела (травник, астрономия, «купальный», рецепты). Если тематическая кучность — настоящее свойство текста, она должна сохраняться и внутри одного раздела, где тема примерно одна и та же на всём протяжении. Получилось: astro — 0.77, «купальный» — 1.08, травник — 1.33, рецепты — 1.46. Все четыре значения заметно ниже, чем 2.78 для всего корпуса, и ни одно не удержалось выше моего порога значимости 1.3 по всем разделам сразу.

Второй контроль — жёстче: burstiness внутри скользящих окон по 1000 слов (шаг 500), усреднённая по всем окнам, и то же самое проделано с английским эталоном для сравнения. Оригинал: 0.741. Английский: 0.608. На масштабе тысячи слов разница почти стёрлась, и в обоих случаях число ушло ниже пуассоновской единицы — сигнал явно ослаб.

Третий, решающий контроль — синтетика-2: та же слотовая модель, но переобученная отдельно на словах каждого раздела (то есть с собственным словарём и частотами для травника, для астрономии и так далее), а затем куски по разделам склеены в один текст. Модель по-прежнему генерирует каждое слово независимо, без всякой памяти между соседними словами. И тем не менее burstiness такой синтетики на всём корпусе — 2.42, почти вплотную к настоящим 2.78 оригинала! Единственное, что отличает синтетику-2 от синтетики-1 (обученной на всём корпусе сразу) — это то, что разные разделы получили разный словарь. Этого одного достаточно, чтобы механически сгенерировать почти весь наблюдаемый эффект «кучности редких слов»: слово, характерное для раздела рецептов, будет казаться «кучкующимся», просто потому что весь раздел рецептов идёт одним куском текста, а вовсе не потому, что кто-то писал про одну тему в одном месте манускрипта осмысленно.

Иными словами: то, что в Акте 3 выглядело как многообещающий признак смысла, в основном оказалось побочным эффектом смены словаря между разделами — тем самым «дрейфом диалектов» A/B, который в войничских исследованиях известен с работ Prescott Currier ещё 1970-х. Я не берусь сказать, что настоящая статья Монтемурро и Занетте 2013 года ошибочна — это полноценная рецензируемая работа с более аккуратной методологией, чем мой учебный скрипт на выходных, — но мой собственный маленький пример показывает, как легко получить похожий по масштабу сигнал из чисто механического источника, если не проконтролировать эффект границ раздела.

Вывод

Форма войничского слова механична: слотовая грамматика prefix-gallows-core-suffix воспроизводит распределение длин, символьную энтропию и условную энтропию H2|1 практически один в один, без единой капли смысла в генераторе. Закон Ципфа не выполняется ни у оригинала, ни (тем более) у синтетики — редкие слова манускрипта распределены не так, как в естественном языке. Взаимная информация соседних слов не показывает статистически значимого избытка зависимости сверх слотовой модели. Кучность редких слов по темам (burstiness), которая на уровне всего корпуса выглядела многообещающе, при проверке по разделам и на масштабе плавающего окна почти полностью объясняется дрейфом словаря между разделами, а не устойчивой семантической структурой внутри однородного текста.

Собранные вместе, эти результаты не доказывают, что манускрипт Войнича — бессмысленный набор символов. Гипотеза о хоаксе (Тимм и Шиннер, Cryptologia, 2019, предложили конкретный ручной алгоритм генерации текста через «self-citation» — повторное использование фрагментов уже написанных слов, — который воспроизводит ключевые статистические свойства текста, включая ципфовское распределение) вполне совместима с тем, что я увидел. Но то же самое совместимо и с реальным языком или шифром, чья статистика слов просто не несёт информации о содержании на уровне, доступном частотному и энтропийному анализу — например, если смысл закодирован не в самих словах-токенах, а во внешнем ключе (номенклаторе, таблице замены смысловых единиц), не восстанавливаемом из статистики самого текста без этого ключа. Ключевой практический вывод для меня — методологический: столкнувшись с красивым числом («burstiness = 2.78, есть смысл!»), нужно сразу спросить, какой механический процесс мог бы дать то же число, и синтетика-2 в этой статье — ровно такой процесс. Расшифровать манускрипт я не смог. Но, кажется, честно показал, почему ни один статистический тест на уровне отдельных слов сам по себе эту задачу не решит — а заодно почему сообщество вокруг манускрипта раз за разом наступает на одни и те же грабли с преждевременными объявлениями «смысл найден».

Тут есть симметрия с Вавилонской библиотекой Борхеса: она содержит абсолютно все возможные тексты из фиксированного алфавита и именно поэтому в среднем не несёт ни бита полезной информации — найти осмысленную страницу среди бесконечности комбинаций можно, только уже зная заранее, что искать. Манускрипт Войнича, подозреваю, устроен ровно наоборот: в нём вполне может быть закодировано конкретное сообщение, но без внешнего ключа — утраченного номенклатора, персонального метода автора — оно статистически неотличимо от шума, что мои тесты и продемонстрировали. Два зеркальных способа ничего не сказать читателю: библиотека тонет в переизбытке информации, манускрипт — в отсутствии ключа к уже имеющейся. Ни один тест в этой статье не отличает одно от другого — и, боюсь, ни один тест, работающий только со статистикой самого текста, в принципе не отличит.

Ссылки

  • Reddy, S., Knight, K. (2011). What we know about the Voynich manuscript. ACL Workshop on Language Technology for Cultural Heritage.

  • Montemurro, M. A., Zanette, D. H. (2013). Keywords and Co-Occurrence Patterns in the Voynich Manuscript: An Information-Theoretic Analysis. PLoS ONE, 8(6), e66344.

  • Timm, T., Schinner, A. (2019). A possible generating algorithm of the Voynich manuscript. Cryptologia, 44(1).

  • voynich.nu — транскрипции, статистика, страница про энтропию (/extra/sol_ent.html).

  • Такахаши, Т. Полная EVA-транскрипция манускрипта — Interlinear Archive на voynich.nu (первоисточник); зеркало, использованное в этой работе: github.com/alephmembeth/voynich.

ссылка на оригинал статьи https://habr.com/ru/articles/1064438/