任意偶数系统的Verhuff算法

KDPV 有时会出现一项保护标识符字符串免受人为意外错误的任务。 例如,支付卡号。 为此,将以特殊方式计算出的校验位添加到该行,并且当有人输入该数字时,您可以进行初始错误校验,而无需访问数据库。 最简单的选择是将所有数字之和除以10的余数相加,在这种情况下,任何一位数字(包括控制一位)的失真都将很容易检测到,并且这样的行将无法通过测试。 但是诸如校验和之类的其他一些错误将丢失,例如,在位置上两位数的排列,这也是一个相当常见的错误。

为了保护银行卡号,选择了一种稍微复杂一些的算法, 即Moon算法。 其中添加了一个修改:将偶数位置的数字乘以2,然后求和(如果结果超过9,则减去9)。 除了使任何数字失真之外,这还允许您捕获相邻数字的大部分(尽管不是全部)排列。

是否有算法可以检测相邻数字的任何排列(除了使任何单个数字失真之外)? 是的,它们存在,尽管由于某些原因它们并不十分常见。 这是基于二面体组的Verhuff算法 ,以及基于Damm拟组的Damm算法 。 听起来很吓人,但实际上并没有什么复杂的(对于那些熟悉“组”概念的人)。

荷兰数学家和雕塑家Jacobus Verhoeff(照片中的雕塑之一)提出了一种基于二面体组的算法。 二面体组是规则的N边形的一组对称性,包括旋转和轴向对称性。 这样的组不是可交换的:如果先对称显示具有重编号顶点的规则多边形,然后旋转它,则在大多数情况下,它与先旋转然后显示是不同的。 因此,当使用二面体组的操作顺序“乘”原始字符串的数字时,即 在规则的N-gon上连续应用旋转和对称映射操作,我们得到了针对大多数排列的保护。 从大多数,但仍然不是每个人。 Verkhuff建议改进此算法,并在将每个数字相乘以根据特殊表替换另一个数字之前,具体取决于数字在行中的位置。 该表是从一个排列中获得的,方法是将其依次应用于先前的结果,然后经过8个此类应用,我们便恢复了原始顺序,因此您可以预先构建表8x10并从中获取值。 其中一些排列使我们能够按源字符串的相邻数字的顺序确定所有100%的可能错误,也就是说,这对于找到防止这两种类型的错误的校验位的问题是一种完全正确的解决方案。 显然,Verkhuff通过随机选择找到了成功的排列,其中有很多。

关于是否存在允许人们找到相邻数字的任何排列而无需进行其他修改的问题,这个问题长期以来一直存在。 在二十一世纪,2004年,德国数学家迈克尔·达姆(Michael Damm)证明了这类基团的存在,它们被称为弱完全反对称拟群。 我还没有完全弄清楚如何构建它们;那些希望的人可以尝试通过发布来自己做。 尽管快速浏览时看起来并不复杂(问题悬而未决,甚至很奇怪),但对于实际实施而言,有一种更简单的方法:使用现成的表格

现在让我们继续下一个主要问题:如果我需要保护的不是字符串的十进制数字,而是字符串的任意字符,例如十六进制,base64或base58,该怎么办? 即,不是以十进制数字系统的特定情况而是以一般形式来解决问题。

Moon算法可以毫无问题地扩展到这种情况,但是它并不是那么有趣,因为它无法找到相邻数字的所有排列。 构造任意大小的反对称拟群的方法尚不完全清楚。 对于Verhuff算法,大小为N的二面体组很容易构造,但是您仍然需要一个置换表,该表也不清楚从何处获得(甚至不清楚它是否存在)。 这是对最后一个问题的研究,我开始了。

在单独搜索和使用N = 64时使用“相当好的”解决方案(即检测几乎所有排列)之后,Google谷歌搜索什么都没有产生。

也许我不会描述找到所需排列的所有尝试和测试的方法,但是都没有得出结果。 我试图解决一个特殊的问题:找到base64和base58的置换,以防止更改相邻数字的顺序。 我只能说,使用不同的优化选项通过随机或顺序搜索找到这种排列的尝试失败了。 但是最后,我找到了任何偶数n的通用解决方案。

排列如下:

0, N-1 .. N/2+1, 1 .. N/2

例如,对于N = 10,这将是:

0, 9, 8, 7, 6, 1, 2, 3, 4, 5

此置换还有另一个显着的特性:它始终具有12的周期(对于N> = 8),这使您可以预先构造12xN表并从那里取一个数字。

这是针对base58提议的Verhuff算法扩展的实现示例 (严格来说,这不是Verkhuff算法,而是其概括)。 可以说,它不是一个完整的库,而只是一个实用程序,证明了概念。

我将在以后的某个时间提供此置换具有必要性质且周期为12的证明。 边距中的空间太小,无法容纳在这里。

Source: https://habr.com/ru/post/zh-CN435446/


All Articles