Для защиты номеров банковских карт выбран несколько более сложный алгоритм, алгоритм Луна. В нём добавлена одна модификация: цифры, стоящие на чётных местах, перед суммированием умножаются на 2 (а если получается больше девяти, то вычитается 9). Это позволяет словить помимо искажения любой цифры большинство (хотя и не все) перестановок соседних цифр.
Существуют ли алгоритмы, позволяющие обнаружить любые перестановки соседних цифр (помимо искажения любой одиночной цифры)? Да, существуют, хотя они почему-то не очень распространены. Это алгоритм Верхуффа, основанный на диэдральных группах, и алгоритм Дамма, который основан на квазигруппах Дамма. Звучит пугающе, но на самом деле там нет ничего сложного (для тех, кто знаком с понятием «группа»).
Якоб Верхуфф (Jacobus Verhoeff), нидерландский математик и скульптор (на фотографии одна из его скульптур), предложил алгоритм на основании диэдральных групп. Диэдральная группа — это группа симметрий правильного N-угольника, включающая как вращения, так и осевые симметрии. Такая группа не является коммутативной: если правильный многоугольник с перенумерованными вершинами сначала симметрично отобразить, а потом повернуть, то в большинстве случаев получится не то же самое, что если сначала повернуть, а потом отобразить. А поэтому при последовательном «умножении» цифр исходной строки, используя операцию диэдральной группы, т.е. последовательно применяя операции поворота и симметричного отображения над правильным N-угольником, мы получим защиту от большинства перестановок. От большинства, но всё-таки опять не от всех. Верхуфф предложил усовершенствовать этот алгоритм, и перед умножением каждую цифру заменять на другую по специальной таблице, в зависимости от места цифры в строке. Таблица получена из одной перестановки путём последовательного её применения к предыдущему результату, и через 8 таких применений мы приходим к исходному порядку, поэтому можно заранее построить таблицу 8x10 и брать значение оттуда. Некоторые из таких перестановок позволяют определять все 100% возможных ошибок в порядке соседних цифр исходной строки, то есть это является полным и корректным решением задачи нахождения контрольной цифры, защищающей от этих двух типов ошибок. Судя по всему, удачную перестановку Верхуфф нашёл методом случайного подбора, их таких существует довольно много.
Вопрос о том, существуют ли группы, позволяющие находить любые перестановки соседних цифр без дополнительных модификаций, долгое время оставался открытым. И уже в XXI веке, в 2004 году немецкий математик Michael Damm доказал существование таких групп, они называются слабо полностью антисимметричными квазигруппами (weakly totally anti-symmetric quazigroup). Я не полностью разобрался в способе их построения, желающие могут попробовать это сделать самостоятельно по его публикации. И хотя при беглом просмотре она не выглядит такой уж сложной (даже странно, что вопрос оставался открытым так долго), для практической реализации есть более простой способ: воспользоваться готовыми таблицами.
Теперь перейдём к следующему и основному вопросу: что делать, если нужно защитить не строку десятичных цифр, а строку произвольных символов, например, 16-ричных или base64 или base58? То есть, решить задачу не для частного случая десятичной системы счисления, а в общем виде.
Алгоритм Луна расширяется на этот случай без проблем, но это не так интересно, потому что он находит не все перестановки соседних цифр. Способ построения антисимметричной квазигруппы произвольного размера не вполне понятен. Для алгоритма Верхуффа диэдральная группа размера N строится несложно, но ещё нужна таблица перестановок, которую тоже непонятно, где взять (и даже непонятно, существует ли она). Вот исследованием последнего вопроса я и занялся.
Гугление ничего не дало, кроме отдельных попыток и применения «достаточно хороших» решений (т.е. обнаруживающих почти все перестановки) для N=64.
Пожалуй, не буду описывать все испробованные способы поиска нужной перестановки, которые не дали результата. Я пытался решить частную задачу: найти перестановку для base64 и base58, дающую защиту от изменения порядка соседних цифр. Скажу лишь, что попытки найти такую перестановку методом случайного или последовательного перебора с разными вариантами оптимизации ни к чему не привели. Но в итоге я нашёл общее решение для любого чётного n.
Перестановка такая:
0, N-1 .. N/2+1, 1 .. N/2
Например, для N = 10 это будет:
0, 9, 8, 7, 6, 1, 2, 3, 4, 5
Эта перестановка обладает ещё одним замечательным свойством: у неё период всегда (для N >= 8) равен 12, что позволяет заранее построить таблицу 12xN и брать цифру оттуда.
Вот здесь пример реализации предлагаемого расширения алгоритма Верхуффа для base58 (строго говоря, это уже не алгоритм Верхуффа, а его обобщение). Не полноценная либа, а просто утилитка, так сказать, proof of concept.
Доказательство того, что эта перестановка обладает нужным свойством, и что у неё период 12, я предоставлю как-нибудь потом. На полях слишком мало места, чтобы поместить его здесь.
Комментарии (15)
amarao
09.01.2019 12:06Буквально только что на Computerfile был рассказ про isbn и контрольную сумму в нём. Там используется модульная арифметрика по основанию 11. Они обещают способность обнаружить любые перестановки и искажение любой одной цифры.
www.youtube.com/watch?v=bqtE6Q79PPstbl
09.01.2019 12:28Почти все алгоритмы для forward error correction работают над конечными числовыми полями, и очень большой класс из них решают 2 задачи: обнаружение ошибки, исправление ошибки. Скорее всего схема, используемая в isbn — частный случай уже существующего кодирования.
Fragster
09.01.2019 18:19ISBN он же EAN-13 он же GS1-13 использует алгоритм модуло10, он же алгоритм Луна, только умножение происходит не на два, а на три. Хотя ранее (года примерно до 2007) был иной алгоритм, с модулем 11 и возможным контрольным символом X. Собственно, переход к EAN-13 и состоял в добавлении префикса 978 и перерасчете контрольной цифры.
gul_kiev Автор
10.01.2019 07:42При использовании арифметики по модулю 11 нужно как-то записывать остаток 10. Обычно его записывают как 0, и в результате получается защита от большинства (больше 90%) ошибок, но не от всех.
В Википедии тоже обещают, что код ОКПО, основанный на том же принципе (умножение цифр на их номер в строке, и как контрольную цифру берём остаток от деления на 11 суммы), даёт 100% защиту и от искажения одиночной цифры, и от любой перестановки соседних цифр, но на самом деле это не так, там возможны коллизии, и даже одиночная ошибка может быть пропущена.
В ОКПО сделан такой финт:
Если получается остаток, равный 10, то для обеспечения одноразрядного контрольного числа необходимо провести повторный расчет, применяя вторую последовательность весов, сдвинутую на два разряда влево (3, 4, 5,…). Если в случае повторного расчета остаток от деления вновь сохраняется равным 10, то значение контрольного числа проставляется равным «0».
Но он не уменьшает количество определяемых ошибок. Например, для числа 2256261 получается контрольная цифра 2 — такая же, как и для чисел 5256261, 2956261, 2266261, 2254261, 2256761, 2256211 и 2256263, которые отличаются от него всего одной цифрой.Zenitchik
10.01.2019 14:57+1При использовании арифметики по модулю 11 нужно как-то записывать остаток 10.
В ISBN его записывают буквой X.gul_kiev Автор
10.01.2019 16:07Спасибо.
Да, римская цифра X гарантирует защиту от ошибок, но это выход за рамки изначального алфавита. Причём выход необоснованный, т.к. достаточно было выбрать другой алгоритм, чтобы контрольной цифрой всегда была именно десятичная цифра.
VaalKIA
10.01.2019 09:08Такая группа не является коммутативной: если правильный многоугольник с перенумерованными вершинами сначала симметрично отобразить, а потом повернуть, то в большинстве случаев получится не то же самое, что если сначала повернуть, а потом отобразить.
А нарисовать 4 картинки — не, зато КДПВ — нате!gul_kiev Автор
10.01.2019 16:22Я не ставил целью объяснять, что такое диэдральные группы и вообще группы. Цель поста — показать полученное мной решение для задачи, которая, похоже, до сих пор была нерешённой. Остальное — лишь необходимое введение в контекст. О том, что такое системы счисления и какие они бывают, где применяется base58, что такое группа и т.д. я не писал, иначе это было бы слишком долго, да и незачем — об этом есть другие статьи.
Про диэдральные группы можно подробнее почитать хоть в Википедии, там с картинками.
Лично мне нравится, когда помимо сухого материала что-то говорится об авторе, когда он «оживляется», и из названия теоремы превращается в живого человека, поэтому и показал работу Верхуффа как скульптора. Если вам это не по душе — извините.
AntonSazonov
А в реализации намеренно пропущены символы "0IOl" (ноль, ай, оу, эль) в массиве alphabet, или это алгоритм такой? Из статьи не удалось понять.
tbl
По сравнению с Base64 в Base58 в том числе отсутствуют символы, которые могут быть неоднозначно восприняты человеком
AntonSazonov
Как раз это я и пропустил. Благодарю за подсказку.
a-tk
А для чего такие алфавиты нужны? Архивы передавать голосом по телефону?
tbl
Алфавит используется для биткоин-адресов, чтобы можно было без ошибок перепечатать с картинки
gul_kiev Автор
Помимо bitcoin-адресов это может быть произвольная строка-идентификатор, будь то аккаунт в соц-сети, ИНН, номер паспорта, идентификатор брони в отеле, авиабилета и т.п. Иногда передаются и голосом по телефону, да. Как base58 он получается короче, а потому удобнее, чем набор десятичных цифр.
Кроме того, такие идентификаторы удобно передавать баркодом (например, печатать на посадочном талоне).