我需要一种算法,可以在另一个32位签名的整数上进行32位签名的整数的一对一映射(即无碰撞)。

我真正关心的是足够的熵,因此该函数的输出似乎是随机的。基本上,我正在寻找类似于XOR密码的密码,但是可以生成更任意的输出。安全不是我真正关心的问题,尽管晦涩难懂。

为了澄清目的编辑:

  1. 算法 必须 保持符号,这样我就可以在没有按键的情况下扭转操作。
  2. 算法 必须 要保持生物,每32位输入号必须生成一个32位唯一的数字。
  3. 该函数的输出必须足够模糊,仅在输入中添加一个,应对输出产生重大影响。

示例预期结果:

F(100)= 98456
F(101)= -758
F(102)= 10875498
F(103)= 986541
F(104)= 945451245
F(105)= -488554

就像MD5一样,改变一件事可能会改变很多事情。

我正在寻找数学函数,因此手动映射整数对我来说不是解决方案。对于那些询问的人,算法速度不是很重要。

有帮助吗?

解决方案

使用任何32位块密码!根据定义,块密码以可逆的方式将其范围内的所有可能输入值映射到唯一的输出值,并且通过设计,很难确定任何给定值将在没有密钥的情况下映射到什么。只需选择一个钥匙,如果安全性或模糊性很重要,请将其保密,然后将密码作为您的转换。

要将这个想法扩展到2个非功率2范围,请参阅我的帖子 使用块密码固定排列.

解决您的具体问题:

  1. 该算法确实是对称的。我不确定您的意思是“没有按键无关的操作”。如果您不想使用密钥,请随机生成一个键并将其视为算法的一部分。
  2. 是的 - 从定义上讲,一个块密码是徒。
  3. 是的。如果不是这样,那将不是一个好密码。

其他提示

我将尝试在一个更简单的示例上解释我的解决方案,然后很容易为您的大型示例扩展。

说我有一个4位。有16个不同的值。看着它是一个四维立方体: 4 dimensional cube
(来源: Ams.org)
.

每个顶点代表这些数字之一,每个位置代表一个维度。因此,它的基本XYZW,每个尺寸都只能具有值0或1。现在想象您使用一个 不同的顺序 尺寸。例如xzyw。现在每个顶点都更改了其数字!

您可以为任何数量的维度执行此操作,只需输入这些尺寸即可。如果安全性不是您的问题,这可能是您的一个不错的快速解决方案。另一方面,我不知道输出是否足以满足您的需求,并且肯定会在完成大量映射后,可以逆转映射(这可能是优势或不利的,具体取决于您的需求。)

以下论文为您提供了4或5个映射示例,为您提供了功能,而不是构建映射集: www.cs.auckland.ac.nz/~john-rugis/pdf/bijectivempapping.pdf

除了生成随机查找表外,您还可以使用功能组合:

  • XOR
  • 对称位置换(例如,移动16位,或将0-31转换为31-0,或将0-3至3-0、4-7至7-4倒转,...)
  • 更多的?

如果您的目标仅仅是为了获得似乎随机的数字置换 大致 定义的大小,然后还有另一种可能的方法:将数字集降低到素数。

那么您可以使用表格的映射

f(i)=(i * a + b)%p

如果p确实是素数,那么这将是所有a!= 0和所有b的培训。对于较大的a和b,它看起来会相当随机。

例如,在我的情况下,我偶然发现了这个问题,我使用了1073741789作为小于1 << 30的数字范围的素数。

我的编码是

((n + 173741789) * 507371178) % 1073741789

解码是

(n * 233233408 + 1073741789 - 173741789) % 1073741789

请注意,507371178 * 233233408%1073741789 == 1,因此这两个数字是数字模型1073741789的倒数(您可以在此类领域中与扩展的Euclidean算法相反)。

我选择了A和B,我只是确保它们大约是P的一半。

您可以使用随机生成的查找桌吗?只要表中的随机数是唯一的,您就会获得一条徒图。不过,这不是对称的。

所有32位值的16 GB查找台可能不切实际,但是您可以使用两个单独的16位查找表来用于高词和低字。

PS:如果这很重要,我认为您可以生成对称的徒查找表。该算法将从空的LUT开始:

+----+        +----+
|  1 |   ->   |    |
+----+        +----+
|  2 |   ->   |    |
+----+        +----+
|  3 |   ->   |    |
+----+        +----+
|  4 |   ->   |    |
+----+        +----+

选择第一个元素,为其分配一个随机映射。要使映射对称,也要分配逆:

+----+        +----+
|  1 |   ->   |  3 |
+----+        +----+
|  2 |   ->   |    |
+----+        +----+
|  3 |   ->   |  1 |
+----+        +----+
|  4 |   ->   |    |
+----+        +----+

选择下一个数字,再次分配随机映射,但选择一个尚未分配的数字。 (即在这种情况下,不要选择1或3)。重复直到LUT完成。这应该生成一个随机的徒对称映射。

取一个数字,乘以9,逆数字除以9。

123  <> 1107 <> 7011 <> 779
256  <> 2304 <> 4032 <> 448
1028 <> 9252 <> 2529 <> 281

应该足够晦涩!!

编辑:这不是0结束整数的培训

900 <> 8100 <> 18 <> 2
2   <> 18   <> 81 <> 9

您始终可以添加一个特定的规则,例如:取一个数字,除以10 x,乘以9,逆数字,除以9,倍数除以10^x。

所以

900 <> 9 <> 81 <> 18 <> 2 <> 200
200 <> 2 <> 18 <> 81 <> 9 <> 900

W00T它可以工作!

编辑2:有关更多淫秽的,您可以添加一个任意号码,并在最后提取。

900 < +256 > 1156 < *9 > 10404 < invert > 40401 < /9 > 4489 < -256 > 4233
123 < +256 > 379 < *9 > 3411 < invert > 1143 < /9 > 127 < -256 > -129

这是我的简单想法:您可以像Peterk提出的那样在数字的位置移动,但是您可以为每个数字置于不同的位置,并且仍然可以破译它。

密码是这样的:将输入编号视为位阵列 I[0..31], ,输出为 O[0..31]。准备一个阵列 K[0..63] 64个随机生成的数字。这将是您的钥匙。从由第一个随机数确定的位置取出输入号的位(I[K[0] mod 32])并将其放在结果的开始(O[0])。现在决定放置哪个位置 O[1], ,使用先前使用的位。如果是0,请使用k [1]生成位置 I 从中拿出来,它是1,使用k [2](这仅表示跳过一个随机数)。

现在,这将无法正常工作,因为您可能需要两次相同的一点。为了避免这种情况,请在每次迭代后重新填充位,省略用过的位。产生占用的位置 O[1] 采用 I[K[p] mod 31], ,其中p是1或2,取决于位 O[0], ,由于剩下31位,数量从0到30。

为了说明这一点,我将举一个例子:

我们有一个4位的数字和8个随机数:25、5、5、28、14、20、0、18。

I: 0111    O: ____
    _

25 mod 4 = 1,所以我们将位置为1的位置(从0计数)

I: 0_11    O: 1___
     _

我们只是花了一点值1,所以我们跳过一个随机数并使用28。剩下3位,因此要计算位置,我们采用28 mod 3 = 1。剩下的位:

I: 0__1    O: 11__
   _

同样,我们跳过一个数字,然后采用14。14mod 2 = 0,所以我们以0位:

I: ___1    O: 110_
      _

现在没关系,但是前面是0,所以我们服用20。20mod 1 = 0:

I: ____    O: 1101

就是这样。

解密这样的数字很容易,只需要做同样的事情即可。从密钥中知道将代码的第一位放置的位置,下一个位置由先前插入的位确定。

显然,这具有任何仅移动周围位的东西的所有缺点(例如,0变为0,Maxint变为Maxint),但是似乎很难找到某人如何在不知道钥匙的情况下对数字进行加密,这必须是秘密。

如果您不想使用适当的加密算法(也许是出于性能和复杂性),则可以使用更简单的密码 Vigenère密码. 。这个密码实际上被描述为 Le ChiffreIndéchiffrable (法语为“牢不可破的密码”)。

这是一个简单的C#实现,该实现基于相应的键值移动值:

void Main()
{
  var clearText = Enumerable.Range(0, 10);
  var key = new[] { 10, 20, Int32.MaxValue };
  var cipherText = Encode(clearText, key);
  var clearText2 = Decode(cipherText, key);
}

IEnumerable<Int32> Encode(IEnumerable<Int32> clearText, IList<Int32> key) {
  return clearText.Select((i, n) => unchecked(i + key[n%key.Count]));
}

IEnumerable<Int32> Decode(IEnumerable<Int32> cipherText, IList<Int32> key) {
  return cipherText.Select((i, n) => unchecked(i - key[n%key.Count]));
}

当输入略微更改时,该算法不会在输出中产生很大的变化。但是,您可以使用另一种徒行动而不是实现这一目标。

在大纸上画一个大圆圈。从圆顶的顶部将所有整数从0到Maxint顺时针方向,同样间隔。将所有整数从0到Minint抗锁定,同样间隔。观察到Minint位于圆底部的Maxint旁边。现在,在一张硬卡的两侧重复了这个数字。将硬卡固定在两者的中心上。选择一个旋转角度,您喜欢的任何角度。现在,您有了1-1的映射,可以满足您的某些要求,但可能不够晦涩。取消卡片,将其围绕直径,任何直径翻转。重复这些步骤(按任何顺序),直到您对自己满意的双眼。

如果您一直在密切关注,则不难用您的首选语言进行编程。

为了澄清 在评论之后:如果您仅针对纸张旋转卡,那么该方法就像投诉一样简单。但是,当您将卡翻转时,映射不等于 (x+m) mod MAXINT 任何 m. 。例如,如果您将卡片保持不息,并将其围绕直径翻转为0(时钟面的顶部),则将1映射到-1、2至-2,等等。 (x+m) mod MAXINT 仅对应于卡的旋转。

将数字分为两个(16位最重要的位和16位最低显着的位),并将两个16位结果中的位视为两个甲板中的卡片。混合甲板将一个迫使一个甲板进入另一个。

因此,如果您的初始号码是 b31,b30,...,b1,b0 你最终得到了 b15,b31,b14,b30,...,b1,b17,b0,b16. 。它是快速,快速实现的,逆向也是如此。

如果您查看结果的小数表示,则该系列看起来非常晦涩。

您可以手动映射0-> MaxValue和MaxValue-> 0,以避免它们映射到自己上。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top