需求場景:預計 token 最多為 7 位數
1:1 可逆推的攪亂器需要三個數字
- 最大值 MAX
- 任一質數
- 質數 與 MAX 互質的數
只有最後一個可以靠前兩個推算,所以一開始的任務先找出最大值和任一質數就能反推。
找數值
進制最後一碼都是字串 “10”,所以進制數減 1 看最後一碼是什麼,以 32 進制來就去看 31 可以轉成什麼,就是 32 進制的最後一碼。
31.to_s(32)
# "v"
所以我們最多能夠接受七位數的話, 7 個 v 就是極限。
"vvvvvvv".to_i(32)
# 34359738367
我們找到了最大數值
所以 CP_MAX = 34359738367
這時候挑一個質數來用
require 'prime'
Prime.each(CP_MAX) do |prime|
puts prime
end
假設我挑了 18195539 做為這次的質數,驗證一下是不是質數?
CP_COP = 18195539
Prime.prime?(CP_COP)
# true
接下來反算出 inverse
def inverse(a, n)
t = 0 ; newt = 1
r = n ; newr = a
while newr != 0
quotient = r / newr
t , newt = newt , t - quotient * newt
r , newr = newr , r - quotient * newr
end
return "a is not invertible" if r > 1
return t < 0 ? t + n : t
end
CP_COI = inverse(CP_COP, MAX)
反推算出來 CP_COI = 30261274580
ID 攪亂實作
接下來做 ID 攪亂
class User < ApplicationRecord
CP_MAX = 34359738367
CP_COP = 18195539
CP_COI = 30261274580
def encode_id
return (self.id.to_i * CP_COP % CP_MAX).to_s(32)
end
def self.decode_id(id)
return id.to_i(32) * CP_COI % CP_MAX
end
end
試試看 user.id = 1 會拿到什麼?
user = User.first
user.id
# 1
user.encode_id
# "hb92j"
假設拿到攪亂過後的,反推呢?
User.decode_id("hb92j")
# 1
總結
嗯,太煩了,Rails 的話直接用 SecureRandom
放一個欄位打 unique 就可以了。
放欄位還可以很方便 application 做搜尋