如何将由DISCOUNT23字符集生成的4位字符串洗牌映射至1-10000范围并实现可逆加密验证
看起来你需要的是一个基于自定义字符集的可逆保密映射,本质是把4位字符串和1-10000的整数做双向加密转换,同时满足无存储验证有效码、非随机、避免直接对应这些要求。我来给你拆解一个可行的方案,完全符合你的需求:
你的需求本质是实现两个可逆步骤:
- 4位字符串 ↔ 0-9999的整数(因为10^4=10000,刚好覆盖所有可能的码值)
- 0-9999的整数 ↔ 0-9999的整数(做保密变换,避免直接对应,同时确保前100个变换结果对应有效码)
最后把变换后的整数+1得到1-10000的最终数字。
首先,你的DISCOUNT23字符集刚好包含10个唯一字符:D、I、S、C、O、U、N、T、2、3,10^4=10000,完美覆盖所有4位组合。
核心关键:绝对不要按字符顺序分配索引,直接打乱对应关系,比如自定义一个保密的字符→索引映射:
D→ 5,I→ 7,S→ 2,C→ 9,O→ 0,U→ 4,N→ 8,T→ 1,2→ 3,3→ 6
这样,一个4位字符串可以转成0-9999的整数:
比如字符串DNT2:
- 对应索引:D=5,N=8,T=1,2=3
- 计算原始整数:
5*1000 + 8*100 + 1*10 + 3 = 5813
反过来,整数转字符串时,把N拆成四位(不足四位补前导0,比如N=23就是0023),每一位数字对应回字符即可:
比如N=23 → 拆分为0、0、2、3 → 对应字符O、O、S、2
我们需要把原始整数N(0-9999)变换成另一个整数E(0-9999),满足:
- 可逆:给定E能还原出N
- 保密:变换规则只有你知晓
- 非随机:同一个N每次得到的E完全一致
我推荐用线性同余变换,这种方式不需要存储大表,只需要记住几个参数,且完全可逆。
加密公式(字符串→数字)
选择两个保密参数:
a:与10000互质的整数(即a是奇数且不被5整除,比如选a=313)b:任意0-9999的整数(比如选b=179)
变换公式:
E = (a * N + b) mod 10000 最终数字 = E + 1 // 转换为1-10000的范围
举个例子,刚才的DNT2对应的N=5813:
E = (313 * 5813 + 179) mod 10000 313*5813 = 1,799,469 → 1,799,469 + 179 = 1,799,648 1,799,648 mod 10000 = 9648 最终数字 = 9648 + 1 = 9649
解密公式(数字→字符串)
首先需要计算a在模10000下的逆元a_inv——也就是满足(a * a_inv) mod 10000 = 1的数(可以用扩展欧几里得算法计算,比如a=313的话,a_inv=8417,你可以自行验证)。
解密步骤:
- 输入数字减1得到E(比如输入9649 → E=9648)
- 计算原始整数N:
N = (E - b) * a_inv mod 10000
注意:如果(E - b)是负数,需要先加10000再取模,比如E=50,b=179 → 50-179=-129 → -129+10000=9871,再乘以a_inv取模。
3. 把N转成4位字符串(用步骤1的字符→索引的逆映射)
你要求映射结果为1-100的数字对应有效码,也就是E=0-99时对应的字符串是有效码。验证时:
- 把输入的字符串按加密步骤转成最终数字
- 如果数字在1-100之间,即为有效码;否则无效。
完全不需要存储任何有效码列表,所有验证都通过加密逻辑实时计算完成。
- 保密性强:字符索引映射、a、b、a_inv这些参数是保密核心,只有知道这些参数的人才能解密或生成有效码。
- 完全非随机:同一个字符串每次得到的数字完全一致,可逆性保证数字也能100%还原回原字符串。
- 无存储需求:不需要在数据库中存储100个有效码,通过加密逻辑直接验证。
- 彻底避免直接对应:字符索引打乱+线性同余变换,完全不会出现字符串和数字的直观对应(比如
DISC绝不会对应1234这类易猜的数字)。
如果你觉得线性同余计算太繁琐,也可以用固定置换表:
- 生成一个0-9999的排列(每个数唯一对应另一个数),这个表是保密的。
- 加密时,把原始整数N映射到表中对应的E,E+1就是最终数字。
- 解密时,查逆表(E对应回N),再转成字符串。
这种方式更直观,适合不想计算线性同余参数的场景,唯一缺点是需要存储一个10000项的表,但现在存储成本可以忽略不计。
内容的提问来源于stack exchange,提问作者Tolga Açıış

