如何将数据库中的顺序整数编码和解码为伪随机 Base36 6 个字符长的字符串

How to encode and decode sequential integer from DB to a pseudorandom Base36 6 character long string

提问人:csharpelestudiente 提问时间:10/1/2023 更新时间:11/8/2023 访问量:76

问:

几天来,我试图找到解决这个问题的方法,但我还没有成功。

我需要实现 2 个功能: 一个用于将整数编码为字符串,一个用于将字符串解码为原始整数。 编码的字符串长度需要为 6 个字符,由大写字母和数字 (Base36) 组成,并且需要随机显示。它不需要高度安全,它只需要看起来足够随机,这样看到它的人就无法在第一眼看到它与原始整数建立连接。 因为我正在尝试对 ID 进行编码,所以对于每个给定的整数,每个字符串都应该是唯一的(没有冲突)。 我发现并实现了一些满足这些要求的算法,但有一个问题:彼此相邻的数字太相似了。基本上它们只差一个字符。尽管它不必非常安全,但接近的数字需要尽可能不同。 实际上,该算法最多只能编码 100k 的整数,因此很可能永远不会使用更高的值,但要使解决方案变得出色,它需要覆盖最多几百万的值。

我需要的示例: 1 -> A39MNY 2 -> HDY19X ... 15 -> 2I8PZ9 等。

我通过使用种子随机对象实现了这一点,但解码部分是问题所在,因为我从输入的整数中制作了种子,通过某种操作修改,因此要在一次迭代中实现编码,必须知道原始整数。通过运行编码功能实现解码,直到找到数字。

如果这些要求无法通过制作某种更简单的算法来实现,我愿意使用某种加密。

我对这个问题非常感兴趣,我仍在积极寻找解决方案。非常感谢任何让我更接近解决方案的帮助。

算法 编码 解码

评论

1赞 Matt Timmermans 10/1/2023
stackoverflow.com/questions/68792872/......
0赞 Dave S 10/1/2023
如果您使用查找表/数组/向量,那么字符串可以是完全随机的,您只需要在生成每个新条目时检查现有的匹配项。您可以根据需要提前预生成任意数量的条目。
0赞 user3386109 10/1/2023
将 ID 视为 24 位数字。编码时,首先将最低有效字节与最高有效字节交换,然后进行 base-36 编码。要解码,请反转该过程。通常,任何可逆的 1 对 1 映射都可用于使 ID 在 base-36 编码之前看起来是随机的。
0赞 rossum 10/1/2023
查看保留加密的格式可能是一种解决方案,或者至少可以提出一些想法。

答:

2赞 btilly 10/1/2023 #1

选择一个大素数。在范围内选择一个随机数。使用费马小定理来扰乱大范围。

您可以对不同的字符串进行编码。寻找比这小一点的素数,我们能做的最好的事情就是.36^6 = 2176782336p2176782317

所以现在我们只需要一个大数字.n

import random
print(random.randomint(1, 2176782317))

这给了我.1173770130

做一点算术以找到它的倒数。为此,我们使用 if 是素数并且对 p 相对素数的事实,那么 mod ,所以乘法逆是 。pap1 = a^(p-1) = a * a^(p-2)a^(p-2)

def n_pow_m_mod_k (n, m, k):
    answer = 1
    power = n
    while 0 < m:
        if 1 == m % 2:
            answer = (answer * power) % k
            m -= 1
        m = m // 2
        power = (power * power) % k
    return answer

print(n_pow_m_mod_k(1173770130, 2176782317 - 2, 2176782317))

这给出了乘法逆。检查一下。6232931

print((1173770130 * 6232931) % 2176782317)

它给了,这就是我们想要的。1

现在让我们把这些神奇的数字变成工作代码。

# Set up the character/number code.
alphabet = '0123456789ABCDEFGHIJKLMONPQRSTUVWXYZ'

chr_to_pos = {}
for i in range(len(alphabet)):
    chr_to_pos[alphabet[i]] = i


def id_to_code (n):
    m = (n * 1173770130) % 2176782317
    answer = ''
    for _ in range(6):
        answer += alphabet[m % 36]
        m = m // 36
    return answer

def code_to_id (code):
    m = 0
    for i in range(len(code)):
        m += chr_to_pos[code[i]] * 36**i
    return (m * 6232931) % 2176782317


for i in range(20):
    print(i, id_to_code(i), code_to_id(id_to_code(i)))

你有它。易于反转的代码,具有不太容易看到的模式和数十亿的范围。

(免责声明:我听信了你的话,你不需要这个来保证安全。这绝对是不安全的。

评论

0赞 csharpelestudiente 10/1/2023
这正是我所需要的!谢谢。
0赞 Trent Renshaw 11/8/2023
@btilly在调用 n_pow_m_mod_k() 时,您是如何获得值2176782315的?
1赞 btilly 11/8/2023
@TrentRenshaw 我只是根据费马小定理添加了一个解释。