起因
最近有个小需求,需要用到这样的功能,本来是打算直接随机生成写到数据库的,可是这样会有重复的可能(虽然概率极低),
而如果做序号生成,就又会有连续生成结果相似的情况,花了一下午搞了这么一个(可能)简单的生成算法。
特点
这个算法还包含了时间信息,可加入过期数据,可以离线生成,不查数据库的情况下就核验授权码。
而且这个缺点是日期中的年份部分,当前只能表示到2031年或共31年。
序号26位有 67108864 种选择,量小的话,足够使用,如果量大,可以配合日期使用。
一天六千万条序号,只要不是同一天大量生成,应该绰绰有余。
如果真的同一天大量生成,我估摸着应该就没有日期了,可以把日期位拿来用。
这样序号就是 2^40 亿万级了...
掩码20位,1048576种可能,穷举的难度应该也足够,碰撞概率百万分之一。
同时加入了签名,有两位36进制,配合上面的掩码,碰撞难度千万分之一,应该也是足够了。
生成算法
先取年份后两位,月份,日期组成,分别转换为二进制后组合为时间位。
序号位转换为二进制后补足26位,接到时间位后面。
随机生成20位随机数,作为掩码。
然后掩码和上面的日期序号分段交叉打乱,转换为36进制序列号。
生成签名校验位
用另一个固定的加权码,与上面序列号,分段相乘并取余,然后余数相加。
余数之和转36进制后拼接到序列号后面,即可发出使用了。
使用时效验方法
先取出后两位校验位,用上面的生成签名校验位同样的方法生成对比,即可初步验证是否伪造。
然后序列号转换为二进制,取出时间位与序号位,
记录以使用,有两种方法:
- 生成时,将序号全部写入Redis,使用后从Redis移除。
- 离线生成,使用后,将序列号写入Redis,如果写入成功,则说明未使用。