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

Иногда хочется как-то объединить эти две стороны своей жизнедеятельности. Написать скрипт четырёхстопным ямбом. Или наоборот — скрипт, который напишет четырёхстопный ямб. Обычно это желание мимолётно и ни к чему не ведёт. Но недавно мне очень захотелось написать биткоин-стихотворение — и я это сделал.

Ниже вы сможете познакомиться с моим великим творением и историей его создания, а также выяснить, что это вообще за ерунда — биткоин-стихотворение, и чем оно полезно народному хозяйству. Я постараюсь, чтобы статья была интересна и понятна как моим коллегам-программистам, так и моим коллегам-литераторам.

Поэт Александр Пушкин с телом робота сидит перед компьютером и пишет перьевой ручкой стихотворение на экране компьютера, стиль: 4к
Поэт Александр Пушкин с телом робота сидит перед компьютером и пишет перьевой ручкой стихотворение на экране компьютера, стиль: 4к

Чёрная магия с последующим разоблачением

Про стихи есть расхожая фраза: «Если нужно объяснять, то не нужно объяснять». Хорошее стихотворение должно говорить само за себя и не нуждаться в пояснениях автора. На литературных семинарах, где стихотворения анализируют критически, к этой фразе часто добавляют: «…но я всё равно объясню!» Буду следовать семинарской традиции — вначале представлю на ваш суд текст, а затем расскажу, почему он стоит внимания. Итак, внемлите.

Когда бы я припас биткоин
Давно, в шестнадцатом году,
Я был бы благости достоин
И не испытывал нужду.

Не безответственный повеса,
Не безалаберный балбес,
А был бы я криптоинвестор,
Бесценный приз шальных невест!

Я зависал бы на Багамах
Нуждой и буднями забыт,
И абсолютно полигамно
Построил свой семейный быт;

Я был бы светел и спокоен,
Не человек — титан! орёл!
Как жаль, что я тогда биткоин
Задёшево не приобрёл.

Выходит, оказался лохом,
Пью «Пять озёр», не «Абсолют».
А впрочем, жить и так неплохо
Без всяческих криптовалют.

Читатель, обладающий литературным вкусом, наверняка скажет, что текст, мягко говоря, не выдающийся. И будет совершенно прав! Однако же есть нюанс. Скопируйте этот текст, а затем вычислите от него хеш SHA-256 (например, вот на этом сайте). Результат будет такой:

000000004b3d0dcca7f96f3f33f821a0e70a5d0f2726cc768dd1bdb4bc10f6ea

Видите эти восемь нулей в начале? Они означают, что это стихотворение особенное. Таких текстов, как этот — один на четыре миллиарда, или даже меньше. А ещё этот стишок — в некотором смысле биткоин.

Скорее всего, мои коллеги-программисты уже всё поняли, и теперь (надеюсь) хотят узнать, как я добился такого результата. Но мои коллеги-литераторы, скорее всего, не поняли ничего. Для них — следующий раздел статьи. Если вы знакомы с устройством биткоина, можете смело его пролистать.

Биткоин для гуманитариев

Важное свойство денег — их труднодоступность. Иначе каждый сделал бы себе миллион миллиардов, и деньги обесценились бы. Можно добывать в шахтах редкие металлы и чеканить из них монеты, можно наносить на бумажные купюры густую сеть тайных знаков — что угодно, лишь бы повторить это не было легко.

В случае криптовалют труднодоступность обеспечивается разнообразными айтишными средствами. Биткоин основан на так называемой концепции Proof-of-Work, «доказательство работы». Иначе говоря — чтобы доказать, что вы достойны обладать биткоином, вы должны зае совершить некую работу, а именно — произвести трудоёмкие вычисления. Разумеется, не самостоятельно, а с помощью ЭВМ. Задача подбирается так, чтобы на её решение гарантированно потратилось большое количество вычислительных ресурсов компьютера — в ней нельзя схитрить, вспомнить, как побеждал на олимпиаде по математике в восьмом классе, и найти быстрый путь. Только долгая и упорная работа числодробилки, только хардкор.

Но что это за задача такая? Возможно, вы когда-то пользовались файлообменными сервисами, чтобы скачать оттуда программы. Часто неподалёку от ссылки на скачивание пишут контрольные суммы файлов. Например, так:

Контрольные суммы одной не очень лицензионной программы с одного не совсем разрешённого сайта
Контрольные суммы одной не очень лицензионной программы с одного не совсем разрешённого сайта

Скачав файл, вы можете посчитать его контрольную сумму и сравнить с указанной. Если всё сошлось — значит, с файлом всё в порядке, его не подменил коварный хакер и не встроил в него злобный вирус. Однако откуда такая уверенность?

Контрольные суммы основаны на так называемых хеш-функциях. Это особые функции, обладающие следующими свойствами:

  1. На вход они принимают двоичные данные произвольного размера.

  2. На выходе у них двоичная последовательность фиксированного размера, называемая хеш.

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

  3. Подобрать файл, который соответствовал бы заданному хешу — вычислительно сложная задача. В идеале — решаемая только тупым перебором, и даже на мощном компьютере занимающая громадное время.

  4. Любое изменение файла, даже самое маленькое, ведёт к совершенно непредсказуемому изменению хеша.

На пунктах 3 и 4 основаны «защитные свойства» хеша. Чтобы подсунуть вам заражённый файл, хакер должен найти другой файл с тем же хешем, да ещё и обладающий вредоносными (то есть — полезными для хакера) свойствами, да ещё и желательно, чтобы его работа с виду напоминала работу исходной программы. Это задача практически нерешаемая — поэтому хакеры специализируются на пользователях, не проверяющих контрольные суммы.

Однако при чём тут биткоин? Задача, обеспечивающая труднодоступность биткоина — это как раз задача нахождения файла, хеш-функция от которого будет иметь заданное значение. Точнее — заданный диапазон значений.

Давайте ещё раз посмотрим на хеш моего стихотворения:

000000004b3d0dcca7f96f3f33f821a0e70a5d0f2726cc768dd1bdb4bc10f6ea

Несмотря на латинские буквы и нули в начале, это — число. Буквы — потому что число не простое, а в шестнадцатеричной системе счисления. Буква «а» — это цифра 10, «b» — это цифра 11, и так далее. А начальные нули — потому что хеш должен иметь фиксированную длину, и если число получилось маленькое, то оно «добивается» нулями слева.

Теперь мы готовы сформулировать главное утверждение этого раздела. Чтобы намайнить биткоин, нужно сгенерировать файл, числовое значение хеша которого будет меньше, чем некий заранее заданный порог (так называемый difficulty target, целевой уровень сложности). Чем меньше порог, тем меньше диапазон допустимых значений хеша, тем сложнее подобрать нужный файл.

** На самом деле всё немного намного сложнее, но поскольку этот раздел называется «Биткоин для гуманитариев», самых любознательных я отошлю в другую статью.

Чему равен difficulty target биткоина? Ответ зависит от того, когда вы это спрашиваете. Целевой уровень сложности периодически вычисляется заново — чем быстрее майнятся новые биткоины, тем меньше устанавливается порог, чтобы их майнинг усложнить. Максимально возможный difficulty target равен

00000000ffff0000000000000000000000000000000000000000000000000000

Иначе говоря, чтобы намайнить биткоин, нужно получить хеш как минимум с восемью ведущими нулями. Это соответствует целевому уровню сложности 2009 года, когда биткоин только набирал обороты. 15 февраля 2010 года difficulty target уменьшился примерно вдвое и стал равен

0000000065465700000000000000000000000000000000000000000000000000

На тот момент хеш моего стихотворения всё ещё был меньше difficulty target. Однако уже 24 февраля 2010 года целевой уровень сложности уменьшился до значения

0000000043b3e500000000000000000000000000000000000000000000000000

С этого момента хеш моего стихотворения официально перестал быть крутым.

На момент написания статьи (14 апреля 2023 года) difficulty target равняется

00000000000000000005e0b20000000000000000000000000000000000000000

Это почти в 48 триллионов раз меньше, чем было изначально. Думаю, здесь читатель начинает понимать, почему биткоины перестали майнить на домашних компьютерах :)

** Когда я поставил себе задачу написать биткоин-стихотворение, я ориентировался не на текущий, а на изначальный целевой уровень сложности биткоина — «восемь нулей». В конце концов, моё стихотворение первое* в своём роде, поэтому справедливо будет сопоставлять его с самым первым биткоином.

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

Свобода — это рабство

Поэзия в некотором смысле основана на ограничениях. По словам поэта и филолога Ольги Седаковой, поэзия — это танец слов, красота движений, сбитых с естественного (и оттого привычного) пути. Ритм и рифма — первые приходящие на ум примеры таких «сбивающих» ограничений. Однако ритм и рифма воспринимаются читателем непосредственно и вызывают у него эстетические переживания. Насколько нова идея внести в поэзию какие-то чисто формальные ограничения?

Да вообще ни разу не нова. Классический пример — акростих, требование, чтобы по первым буквам строк читалось какое-то слово или фраза. Акростих — очень древняя забава, его примеры можно встретить даже в Ветхом Завете. Приведу пример поновее, за авторством Николая Гумилёва.

Аддис-Абеба, город роз,
На берегу ручьев прозрачных,
Небесный див тебя принес,
Алмазный, средь ущелий мрачных.
Армидин сад... Там пилигрим
Хранит обет любви неясной,
Мы все склоняемся пред ним,
А розы душны, розы красны.
Там смотрит в душу чей-то взор,
Отравы полный и обманов,
В садах высоких сикомор,
Аллеях сумрачных платанов.

Помимо акростихов, бывают также телестихи (слово читается по последним буквам строк), мезостихи (по средним буквам) и всякие другие штуки, вроде, например, той, что Эдгар По посвятил своей тайной возлюбленной.

Для поэта подобные вещи играют двоякую роль. С одной стороны — это «челлендж», способ доказать своё мастерство. С другой — это ещё способ уйти от речевого автоматизма на нехоженые тропинки языка, уйти из движения в танец. Нет никаких гарантий, что этот способ будет удачным (иначе наши классики, мастерство которых несомненно, писали бы исключительно акростихи). Но, по крайней мере, это может быть попыткой.

Однако вернёмся к нашим биткоинам.

(Де)генеративное искусство

Чем отличается написание акростиха от написания биткоин-стихотворения? Тем, что в процессе поэт понимает, насколько он близок к результату. Если написано восемь строк из запланированных десяти — то, скорее всего, 80% работы выполнено. Конечно, может случиться, что последние строки никак нельзя будет подобрать, и придётся переписывать начало. И всё же вероятность этого достаточно мала, чтобы верить — какая-то часть работы уже сделана.

С биткоин-стихотворением всё сложнее, потому что его нельзя писать инкрементально. Значение хеш-функции непредсказуемо. Написав восемь строк, я никак не могу сказать, приближают ли они меня к нужному хешу. Я могу только сказать, что написал восемь строк.

При майнинге биткоина программа не пытается подобрать нужный файл — она просто перебирает все возможные варианты, пока не отыщет нужный. Следовательно, мне нужно было поступить так же. Несложный подсчёт показывает, что если попробовать 10 миллиардов стихотворений, вероятность найти среди них биткоин-стихотворение составляет более 90%.

Несложный подсчёт
1 - (1 - 1/16^8)^{10000000000} \approx 0.9025

Хешей с восемью ведущими нулями в 168 раз меньше, чем всех хешей. Возьмём вероятность, что у случайно взятого хеша меньше восьми ведущих нулей, возведём её в степень количества попыток — получим вероятность, что все попытки были неудачными. Соответственно, если вычесть эту вероятность из единицы — получим вероятность хотя бы одной удачи.

Как же поэту Шевякову за пару дней написать 10 миллиардов стихотворений?

У большинства текстов есть степени свободы. Например, это предложение могло начинаться как с «например», так и с «к примеру» — для читателя эти варианты приблизительно равнозначны. В поэтическом тексте степеней свободы меньше, чем в прозаическом. На него накладывается множество формализуемых и неформализуемых ограничений. Каждое слово помимо того, чтобы иметь нужное автору значение, должно определённым образом звучать, относиться к правильному стилистическому пласту, иметь нужные (и не иметь ненужные) коннотации… Тем не менее, и в поэтическом тексте степени свободы всё-таки можно найти.

Самое простое и очевидное — знаки препинания. Зачастую можно безболезненно заменить запятую на тире и наоборот. Вместо точки в некоторых случаях может быть восклицательный знак или многоточие.

Посмотрим ещё раз на мой биткоин-текст.

Повтор не тщеславия ради, а удобства для

Когда бы я припас биткоин
Давно, в шестнадцатом году,
Я был бы благости достоин
И не испытывал нужду.

Не безответственный повеса,
Не безалаберный балбес,
А был бы я криптоинвестор,
Бесценный приз шальных невест!

Я зависал бы на Багамах
Нуждой и буднями забыт,
И абсолютно полигамно
Построил свой семейный быт;

Я был бы светел и спокоен,
Не человек — титан! орёл!
Как жаль, что я тогда биткоин
Задёшево не приобрёл.

Выходит, оказался лохом,
Пью «Пять озёр», не «Абсолют».
А впрочем, жить и так неплохо
Без всяческих криптовалют.

Запятую в конце второй строки вполне можно заменить на тире. Аналогично с седьмой строкой. Восклицательный знак в конце второй строфы вполне может быть точкой. Итого, чисто за счёт пунктуации первых двух строф, у нас уже есть восемь потенциальных вариантов этого стихотворения. Всего с помощью замен пунктуации я получил 192 варианта. Неплохое начало, но этого явно недостаточно.

Теоретически можно было бы использовать «грязные хаки». Например, заменять русскую «о» на английскую, добавлять лишние пробелы в конце строк — в общем, творить всякие вещи, которые не меняют стихотворение визуально, но делают его другим с точки зрения хеш-функции. Я обдумывал эту идею, но отказался от неё. Стихотворение — это не конкретное бинарное представление в недрах компьютера, а то, что воспринимает читатель. Соответственно, и варьировать надо те вещи, которые доступны читательскому восприятию. Иначе нечестно, и к тому же слишком просто.

Ещё одна очевидная степень свободы — это синонимы. Точнее, даже не обязательно синонимы. Словам не обязательно иметь одинаковое значение — им достаточно одинаково подходить к данному месту текста. Скажем, вместо шестнадцатого года вполне может быть пятнадцатый или семнадцатый. Четырнадцатый год там быть не может — он не укладывается в стихотворный размер. Конечно, с точки зрения смысла идеален был бы двенадцатый — однако и другие ритмически допустимые варианты нам вполне подойдут.

Аналогично бесценный приз может быть желанным или заветным, водку «Пять озёр» вполне можно заменить на бальзам «Бугульма», и так далее, и тому подобное.

В итоге я подобрал такое количество замен, что суммарно набралось 28 665 446 400 потенциальных вариантов моего стихотворения. Дело оставалось за малым — превратить потенциальное в, так сказать, кинетическое.

Неинтересная техническая часть

Я опасаюсь, что эта часть будет одинаково неинтересна как коллегам-программистам, так и коллегам-литераторам. Гуманитариям — потому что ничего непонятно, технарям — потому что всё слишком понятно. Тем не менее, из песни слова не выкинешь, так что — here we go.

В качестве инструмента я избрал хорошо знакомый и удобный мне NodeJS. Для начала я написал шаблон текста стихотворения. Места со степенями свободы в нём были заменены символом $.

const template = 

`Когда бы $ биткоин
$ в $ году$
Я был бы $ достоин
И не испытывал нужду.

Не $ повеса,
Не безалаберный балбес,
А был бы я криптоинвестор$
$ приз $ невест$

Я $ бы на Багамах
$ и $ забыт,
И $ полигамно
$ свой $ быт$

Я был бы $ и спокоен,
Не человек — $! орёл!
Как жаль, что я тогда биткоин
$ не приобрёл.

Выходит, оказался лохом$
Пью $, не «Абсолют»$
А впрочем, $ и так неплохо
Без $ криптовалют$`;

Затем составил список подстановок — точнее, список их списков. Первый символ $ в шаблоне заменяется одной из подстановок первого списка, второй — второго, и так далее.

const substitutions = [
  [`закупил`, `я купил`, `я запас`, `я припас`, `приобрёл`],
  [`Тогда,`, `Давно,`, `Ещё`, `Уже`],
  [`тринадцатом`, `двенадцатом`, `пятнадцатом`, `шестнадцатом`, `семнадцатом`],
  [`,`, ` —`],
  [`радости`, `благости`],
  [`безответственный`, `романтический`],
  [`,`, ` —`],
  [`Желанный`, `Заветный`, `Бесценный`],
  [`любых`, `шальных`, `чужих`],
  [`.`, `!`],
  [`отдыхал`, `загорал`, `зависал`],
  [`Нуждой`, `Судьбой`],
  [`бедами`, `буднями`],
  [`совершенно`, `абсолютно`, `непременно`],
  [`Устроил`, `Построил`],
  [`семейный`, `интимный`],
  [`.`, `;`],
  [`счастлив`, `дерзок`, `весел`, `светел`],
  [`титан`, `кремень`],
  [`Недорого`, `Задёшево`, `По акции`],
  [`,`, ` —`],
  [`«Пять озёр»`, `«Бугульму»`],
  [`…`, ` —`, `.`],
  [`жить`, `мне`, `всё`],
  [`всяческих`, `этих вот`],
  [`.`, `!`]
];

После этого мой скрипт просто перебирал все варианты подстановок и считал для каждой хеш SHA-256. Если хеш был меньше, чем предыдущий наилучший вариант — новый наилучший вариант стихотворения выводился в консоль.

Полный текст скрипта
const {createHash} = require(`crypto`);

const template = `Когда бы $ биткоин
$ в $ году$
Я был бы $ достоин
И не испытывал нужду.

Не $ повеса,
Не безалаберный балбес,
А был бы я криптоинвестор$
$ приз $ невест$

Я $ бы на Багамах
$ и $ забыт,
И $ полигамно
$ свой $ быт$

Я был бы $ и спокоен,
Не человек — $! орёл!
Как жаль, что я тогда биткоин
$ не приобрёл.

Выходит, оказался лохом$
Пью $, не «Абсолют»$
А впрочем, $ и так неплохо
Без $ криптовалют$`;

const parts = template.split(`$`);

const substitutions = [
  [`закупил`, `я купил`, `я запас`, `я припас`, `приобрёл`],
  [`Тогда,`, `Давно,`, `Ещё`, `Уже`],
  [`тринадцатом`, `двенадцатом`, `пятнадцатом`, `шестнадцатом`, `семнадцатом`],
  [`,`, ` —`],
  [`радости`, `благости`],
  [`безответственный`, `романтический`],
  [`,`, ` —`],
  [`Желанный`, `Заветный`, `Бесценный`],
  [`любых`, `шальных`, `чужих`],
  [`.`, `!`],
  [`отдыхал`, `загорал`, `зависал`],
  [`Нуждой`, `Судьбой`],
  [`бедами`, `буднями`],
  [`совершенно`, `абсолютно`, `непременно`],
  [`Устроил`, `Построил`],
  [`семейный`, `интимный`],
  [`.`, `;`],
  [`счастлив`, `дерзок`, `весел`, `светел`],
  [`титан`, `кремень`],
  [`Недорого`, `Задёшево`, `По акции`],
  [`,`, ` —`],
  [`«Пять озёр»`, `«Бугульму»`],
  [`…`, ` —`, `.`],
  [`жить`, `мне`, `всё`],
  [`всяческих`, `этих вот`],
  [`.`, `!`]
];

const maxPoems = substitutions.reduce((acc, next) => acc * next.length, 1);
console.log(`Всего вариантов текста — ${maxPoems}. Ожидаемое количество ведущих нулей хеша — ${Math.round(Math.log(maxPoems) / Math.log(16))}`);

const generatePoem = (n) => {
  let result = parts[0];
  for(let i = 1; i < parts.length; i++){
    let sub = substitutions[i - 1];
    let index = n % sub.length;
    result += sub[index] + parts[i];
    n = (n - index) / sub.length;
  } 
  return result;
}


let minHash = null;
let minPoem = null;
let lastPercent = -1;

for(let i = 0; i < maxPoems; i++){
  const percent = Math.round((i + 1) * 10000 / maxPoems) / 100;
  if(percent > lastPercent){
    console.log(`Проверено ${percent}%`);
    lastPercent = percent;
  }
  const poem = generatePoem(i);
  const hash = createHash(`sha256`);
  hash.update(poem, `utf8`);
  const buff = hash.digest();
  if(minHash == null || (minHash.compare(buff) == 1)){
    console.log(`Стих ${i + 1}/${maxPoems}:

${poem}

Новый рекорд хеша: ${buff.toString(`hex`)}
  `);
    minHash = buff;
    minPoem = poem;
  }
}

На моём домашнем компьютере перебор 28 с лишним миллиардов стихотворений занял примерно двое суток. Впрочем, 95% этого времени было потрачено впустую — наилучшим оказался вариант номер 1 689 545 869, последующие 27 миллиардов текстов не превзошли его результат.

Работу скрипта можно было бы радикально ускорить, распараллелив вычисления (в идеале — перенеся их на GPU). Но учитывая, что задача одноразовая, я решил:

Всё это очень хорошо, но...

Почему же стихотворение такое неказистое? Я так хорошо всё обосновал, рассказал про степени свободы — а в итоге получился отнюдь не шедевр. Может быть, я просто поэт так себе, с гнильцой?

И да, и нет. Я определённо мог постараться получше. Выбрать менее банальную идею, подобрать более точные подстановки, добавить в конце смешной панч. Тем не менее, есть и некое принципиальное ограничение, почему совсем хорошо получиться не могло.

Как писал Кольридж, поэзия — это лучшие слова в лучшем порядке. Произвольный выбор эпитетов — признак плохого поэта. Задавая список подстановок, автор заранее знает, что из этого списка максимум одно слово — то самое, идеальное. Остальные — «осетрина второй свежести». Даже знаки препинания, равно допустимые, всё равно не являются равнозначными — какие-то из них лучше передают авторскую интонацию, а другие хуже. С вероятностью, стремящейся к единице, стихотворение с идеальным хешем — это не то стихотворение, где выбраны все идеальные подстановки.

Можно подобрать подстановки, довольно близкие к идеалу — так сказать, осетрину почти без душка. Но тут возникает другой вопрос. Если стихотворение позволяет без особых проблем заменить слово на другое — проблема не в выборе слова, а в самом стихотворении. Поэтический текст стремится к минимизации своих степеней свободы. Он отличается от прозаического невероятно густой сетью внутренних связей — фонетических, стилистических, семантических и ещё много каких -ических. Как сказал мне однажды поэт Анатолий Михайлов: «В идеальном стихе, который я не написал (и не напишу, наверное) — все зависит от всего».

Гениальный акростих написать возможно. В случае акростиха автор явно видит наложенные на него ограничения и действует с их учётом. Поиск единственно верного слова становится сложнее — но это по-прежнему поиск единственно верного слова. Однако автор никак не может сознательно учесть ограничения, накладываемые хеш-функцией. Единственный способ написать гениальное биткоин-стихотворение — быть редчайшим везунчиком. То есть — просто написать гениальное стихотворение, а затем случайно обнаружить, что у него ещё и «понтовый» хеш.

* Вопрос первенства

В заголовке этой статьи два слова были помечены звёздочками. С биткоином мы разобрались в самом начале — теперь пора заняться другой звёздочкой. Я заявил, что мой текст — первое в мире биткоин-стихотворение. Есть ли у меня основания так считать?

На крупнейшем российском поэтическом портале Стихи.ру на момент написания этих строк опубликовано 58 542 938 стихотворений. Учитывая его популярность и максимальную, гм, демократичность, можно предполагать, что это — львиная доля стихотворений на русском языке, когда-либо где-либо опубликованных. Воспользовавшись формулой, приведённой ранее, можно вычислить вероятность, что одно из этих стихотворений является «биткоиновым» — она приблизительно равна 1.35%. Если предположить, что в других источниках суммарно опубликовано ещё примерно столько же — вероятность повысится до 2.68%. Не так уж много, но всё-таки существенно больше нуля.

Однако русский язык не единственный в мире. Я не знаком с англо- и прочеязычными поэтическими ресурсами, но если экстраполировать «поэтическую плодовитость» россиян на всё человечество, общее число когда-либо опубликованных стихотворений можно оценить примерно в 6.69 миллиардов. Вероятность появления среди них биткоин-стихотворения — около 78.93%. Судя по всему, шанс, что ваш покорный слуга был первым, не так уж и велик. Однако можно хотя бы надеяться?

Нет, никак нельзя. Мои надежды на первенство похоронил французский поэт Раймон Кено. В 1961 году он издал книгу «Сто тысяч миллиардов стихотворений». В книге всего десять страниц, на каждой из которых напечатано четырнадцатистрочное стихотворение-сонет. Однако каждая строка напечатана на отдельной полоске, и эти полоски можно листать независимо друг от друга, в любой комбинации получая новый связный сонет. Шанс, что биткоин-стихотворение найдётся среди 1014 сонетов, настолько велик, что при попытке его подсчитать компьютер выдаёт просто единицу.

Таким образом, на самом деле мне принадлежит значительно более скромное первенство: я первый, кто привёл конкретный пример биткоин-стихотворения.

Жидкие аплодисменты
Жидкие аплодисменты

Вместо послесловия

Моё биткоин-стихотворение — умеренно забавный курьёз, не вносящий ничего принципиально нового ни в поэзию, ни в компьютер сайенс. Однако оно может служить поводом для интересных аналогий и далеко идущих вопросов.

Поэт и критик Алексей Алёхин писал в одной из статей, что в хорошем стихотворении каждая новая строчка должна менять восприятие всего предыдущего текста. В этом смысле можно сравнить читательское восприятие с хеш-функцией, значение которой радикально меняется от добавления каждого нового бита. Впрочем, эта аналогия поверхностная — «функция читательского восприятия» всё же не настолько хаотична.

Более интересной мне кажется мысль о том, что рифма и ритм в силлабо-тоническом стихотворении — некий аналог Proof-of-Work. Если автор потрудился подобрать рифмы и соблюсти стихотворный размер — это его «доказательство работы», свидетельство, что высказанная мысль была ему чем-то важна. Этим «классическая» поэзия выгодно отличается от верлибра. Хороший верлибр написать не менее (а возможно, и более) сложно, чем хороший регулярный стих — однако эта сложность менее формализуема, и вложенную работу тяжело оценить с первого взгляда.

Сейчас, в эпоху стремительно надвигающейся технологической сингулярности, поэты, как и прочие творцы, обеспокоены развитием генеративного искусства. Уже сегодня GPT-4 пишет стихи не сильно хуже среднестатистического графомана. Настанет ли момент, когда нейросеть превзойдёт человека и в поэзии? Кто-то считает, что нет, постулируя уникальность человеческого разума. Другие соглашаются, что да, однако полагают, что это не будет концом «человеческой» поэзии. Для них в стихах важен момент коммуникации, возможность прикоснуться к чужому внутреннему миру, лишь вскользь выразимому словами. А стихотворение, сгенерированное нейросетью — это письмо без отправителя.

Надеюсь, вам было не менее интересно читать эту статью, чем мне — писать её. Если хотите, можете посетить мой поэтический паблик и познакомиться с обыкновенным, не биткоиновым творчеством. А мой рассказ на этом подошёл к концу.

Комментарии (31)


  1. ImranAkhmedov
    14.04.2023 10:48
    +3

    Осталось только намайнить первую биткоин книгу :)


    1. Sirion Автор
      14.04.2023 10:48
      +4

      Эта задача как раз намного проще) в большом прозаическом тексте много степеней свободы, с которыми можно аккуратно поиграть, почти не испортив текст. Думаю, что я могу взять любой классический русский роман и сделать его биткоин-версию настолько тщательно, что даже литературовед не заметит разницу без diff-а.


    1. zhasminryzhova
      14.04.2023 10:48

      Ха-ха, ну да, можно просто взять бумагу и ручку и начать "майнить" исследование книги, правда шансы на успех майнинга чрезвычайно малы. Намного проще и эффективнее просто купить книгу за обзоры, если у вас конечно есть достаточное количество монет в кошельке :)


      1. Sirion Автор
        14.04.2023 10:48

        Я одобрил комментарий, но всё же не очень понимаю, что именно вы хотели сказать)


  1. vladvul
    14.04.2023 10:48
    +1

    можно проверить 100 000 миллиардов стихотворений, вдруг найдется биткойн старше вашего по количеству нулей в хэше.


    1. Sirion Автор
      14.04.2023 10:48
      +1

      Почти наверняка. По той же формуле вероятность того, что найдётся текст с 11 нулями хеша — приблизительно 99.66%


  1. AndreySitaev
    14.04.2023 10:48
    +16

    Вроде бы и замысел абсурден, и реализация тривиальна - а как приятно прочитать. Такими (в частности) статьями и ценен ресурс.


    1. Sirion Автор
      14.04.2023 10:48
      +7

      Писал, надеясь получить именно такой комментарий! Спасибо, очень приятно.


  1. vak0
    14.04.2023 10:48
    +3

    "Если человек талантлив, он талантлив во всем" (с) Автор, Вы большой молодец. Задумка - класс! Реализация тоже порадовала. Статья отличная, читать интересно и весело. Биткоин-стихотворение тоже хорошее получилось, зря вы излишне строги к себе. )


    1. Sirion Автор
      14.04.2023 10:48

      Ну, если я не буду строгим к себе, то кто? Вы вот похвалили, а поругать никто не поругал)


  1. IvanPetrof
    14.04.2023 10:48
    +1

    У меня есть ощущение, (но я не могу это доказать найти этому подтверждение), что если взять последовательность из 256 нулевых бит и "взять" от них sha256, а потом ещё раз sha256 и ещё.. ещё, ещё.., то каждый раз мы будем получать новую уникальную последовательность из 256 бит. И ровно через 2^256 таких операций мы вернёмся к первоначальному значению (из 256 нулей).

    А это будет означать, что каждому вЫходному 256 битному значению соответствует одно (и только одно) 256 битное входное значение. А значит, теоретически может существовать "обратная" функция, которая может однозначно найти 256 битное исходное значение.

    Ради интереса я прокрутил по полному кругу crc32 (это конечно, не полноценная хэш-функция, но зато короткая), и оказалось, что она так себя и ведёт. Т.е. Повторяется через 2^32 "оборота".

    Такую же операцию я проводил с первыми 32 битами sha256.

    Прокрутить полный цикл sha256 пока не представляется возможным.


    1. Sirion Автор
      14.04.2023 10:48

      Не удивлюсь, если в данном частном случае это можно доказать математически. Но у меня зачаточные познания в области современной криптографии, так что конкретнее сказать не могу. На досуге почитаю спеку, возможно, это не очень сложно вывести


      1. pananton
        14.04.2023 10:48

        Я бы посмотрел в области общей алгебры и теории полей. Там исследуются множества с заданной на нем операцией. В этой сфере математики есть понятие фактор-множества, элементами которого являются подмножества исходного множества, которые удовлетворяют условию, что для любых двух элементов А и Б при применении к ним операции получается элемент, также принадлежащий тому же подмножеству.

        В контексте рассматриваемого вопроса, операция - это вычисление хэша, а исходное множество состоит из всех битовых последовательностей длиною 256 бит. С точки зрения общей алгебры можно попытаться доказать теорему, чио фактор-множество в этом случае состоит из единственного множества - исходного. Тогда действительно применение операции даст цикл длиной ровно 2^256, это уже общий результат.

        Вероятно я где-то что-то напутал, т.к. общую алгебру давно не вспоминал, нов целом как-то так)


    1. Format-X22
      14.04.2023 10:48
      +2

      Только хеш обычно от данных сильно длиннее исходных берут.


      1. IvanPetrof
        14.04.2023 10:48

        Я это понимаю. Но мне как раз интересен вариант, когда битность входа не превышает битности выхода.

        Т.к. например, в задаче поиска "красивого" хэша для любой длины первоначального сообщения, всё равно достаточно будет манипулировать, к примеру, первыми 256 битами сообщения, чтобы получить любой красивый хэш (хоть с 256 нулями).

        P.s. Нет, я не биткоин ломаю)). Хотя..


    1. karavan_750
      14.04.2023 10:48

      Также, на правах предположения без доказательства.
      В процессе таких вычислений может обнаружиться "петля/кольцо", которая "замкнет" вычисления в себе и оконечная хэш-сумма (она же изначальная) окажется недостижимой.
      Доказательство моего предположения может быть построено на доказательстве наличия коллизий во всем наборе хэшей 2^256, когда одна сумма будет возможна для различных входных данных.
      Пока писал ответ, понял, что эта "петля/кольцо" может быть доказательством, но уже не для предлагаемого набора нулей.


      1. IvanPetrof
        14.04.2023 10:48

        Я с этого начинал. Хотел понять, существуют ли такие локальные "кольца". Для этого даже научился считать sha256 на бумажке (есть статья на хабре). И вот как раз в процессе размышлений и появилась мысль, что локальных колец скорее всего нет. Глобально я это проверить не смог, но локальные урезанные по битности версии, пока это подтверждают.


      1. IvanPetrof
        14.04.2023 10:48

        с локальными кольцами возможны два варианта:

        1) когда в это кольцо нельзя попасть извне. И тогда мы вернёмся к 0 не совершив полного круга (например 0,1,2,3,0,1,2,3..). Таких колец может существовать несколько. И они не пересекаются (по условию)

        2) когда в это кольцо можно попасть извне. Т.е. Допустим последовательность может выглядеть так 0,1,2,3,4,2,3,4,2,3,4.. Т.е. Не дойдя до 9 мы зациклились на середине. Но это означает, что в узел "2" можно попасть двумя путями: из "1" или из "4" (коллизия). Но это автоматически означает, что какие-то результаты наша хеш-функция не умеет выдавать в принципе. К примеру если последовательность выглядит так 0123456789123..., т.е. В пункт 1 можно попасть из 0 или из 9, а значит результат 0 она не выдаёт в принципе. Т.е. Не существует таких входных данных, чтобы в результате получился 0. А если таких колец будет несколько, то, возможно будут и другие "запрещённые" результаты.

        Кактотак


    1. DGN
      14.04.2023 10:48
      +1

      Некогда ковыряя одну игрушку, менял константу в ПЗУ. Но там была защита, CRC16, и она срабатывала, не давая запуститься. Я брал место с графическим элементом и менял содержимое пока CRC не сходилось. Впоследствии узнал, что настоящии хакеры делали битхак в процедуре проверки CRC.


  1. atrosinenko
    14.04.2023 10:48
    +1

    Весьма изысканный способ доказать превосходство человеческого разума над ChatGPT :)

    Шикарная статья!


    1. Sirion Автор
      14.04.2023 10:48

      Не факт, что это превосходство надолго, но спасибо)


  1. LuigiVampa
    14.04.2023 10:48
    +3

    Тысяча чертей! Вот именно ради такого я до сих пор читаю Хабр. Очень круто, спасибо!


    1. Sirion Автор
      14.04.2023 10:48
      +1

      Да, Хабр иногда ещё торт. Рад, что иногда это «иногда» из-за меня.


  1. Soukhinov
    14.04.2023 10:48
    +1

    Я когда-то делал то же самое — писал текст со степенями свободы. Только цель у меня была другая: сделать так, чтобы текст наилучшим образом выравнивался по обеим сторонам страницы с минимальным количеством переносов и с минимальным растяжением или сжатием пробелов.


    1. Sirion Автор
      14.04.2023 10:48

      О, прекрасное практическое применение)


  1. nevmenandr
    14.04.2023 10:48
    +1

    Вероятности, это, конечно, хорошо. Но реальные данные гораздо слаще.

    Я посмотрел в поэтическом подкорпусе Национального корпуса русского языка и нашел там только одно стихотворение с четырьмя ведущими нулями sha256:

    Вы смущены... такой развязки
    Для ежедневной старой сказки
    Предугадать вы не могли,--
    И, как укор, она пред вами
    Лежит, увитая цветами...
    Не плачьте ж -- поздними слезами
    Не вырвать жертвы у земли!

    Это Надсон. sha256:

    0000bfdc1335b7b04add8eb12bff7034d42548d7ca028e0704f589285536f9a4

    Как исследователь сайта stihi.ru c десятилетним стажем обследовал и все стихотворения, опубликованные там с 2000 по 2010 год (это мало, конечно, на обсчет полной коллекции до 2019 года уйдет где-то неделя). Нашлось 3 текста с пятью ведущими нулями sha256. Например, такой. sha256:

    00000623f875e7bd5dd1c209c08d6cddd0b6ce672fb1469a47c48729eaa1d57f

    Раймона Кено тоже начал считать. Здесь репозиторий с кодом. Выяснил, что на текущей скорости полный перебор займет 38 с половиной лет. Пока отложил. Варианты с 8 и более ведущими нулями в обсчитанных полутора миллиардах комбинаций не попались.


    1. Sirion Автор
      14.04.2023 10:48

      У меня прям на сердце теплеет от вашего комментария. Хотел сам посчитать Кено, но потом подумал — неужто никто из хабровчан не подхватит эстафету)


    1. Sirion Автор
      14.04.2023 10:48

      Да, с большим интересом прочитал вашу статью. Вывел для себя список слов, которые хорошо бы употреблять пореже


  1. akahan
    14.04.2023 10:48
    +1

    Браво!!! Обычно не комментирую, но автор «вынудил»))


  1. Opanagushin
    14.04.2023 10:48
    +1

    Вроде в биткоине используется не SHA256 а HASH256, что есть два раза по SHA256


    1. Sirion Автор
      14.04.2023 10:48

      Судя по всему, вы правы((( Мне очень стыдно за свою невнимательность. Сегодня же вечером запущу числодробилку заново, затем внесу дополнение в статью.