我有一個關於the pseudo-encrypt function for postgres的問題。 有什麼辦法可以將輸出減少到6?我真的很喜歡這個功能,並希望使用它,但只需要1至999999之間的輸出。減少僞加密函數輸出的長度
此問題與my last question。我想用它來創建1至999999之間的唯一數字。
謝謝。
我有一個關於the pseudo-encrypt function for postgres的問題。 有什麼辦法可以將輸出減少到6?我真的很喜歡這個功能,並希望使用它,但只需要1至999999之間的輸出。減少僞加密函數輸出的長度
此問題與my last question。我想用它來創建1至999999之間的唯一數字。
謝謝。
所產生的價值使用mod
在範圍內產生數start_value
到end_value
:
select start_value + mod(pseudo_encrypt(number), end_value - start_value + 1);
對於你的情況,這將是這樣的:
select 1 + mod(pseudo_encrypt(23452), 999999);
這不是很簡單的設置一個999999的上限,因爲該算法對比特塊進行操作,所以很難擺脫兩者的冪。
您可以解決此通過cycle walking - 只是嘗試encrypt(n)
,encrypt(encrypt(n))
,encrypt(encrypt(encrypt(n)))
......直到你最終的範圍是[1,999999]的結果。爲了使迭代次數保持最小,您需要調整塊大小以儘可能地接近此範圍。
這個版本將讓您指定的輸入/輸出範圍:
CREATE OR REPLACE FUNCTION pseudo_encrypt(
value INT8,
min INT8 DEFAULT 0,
max INT8 DEFAULT (2^62::NUMERIC)-1
) RETURNS INT8 AS
$$
DECLARE
rounds CONSTANT INT = 3;
L INT8[];
R INT8[];
i INT;
blocksize INT;
blockmask INT8;
result INT8;
BEGIN
max = max - min;
value = value - min;
IF NOT ((value BETWEEN 0 AND max) AND (max BETWEEN 0 AND 2^62::NUMERIC-1)) THEN
RAISE 'Input out of range';
END IF;
blocksize = ceil(char_length(ltrim(max::BIT(64)::TEXT,'0'))/2.0);
blockmask = (2^blocksize::NUMERIC-1)::INT8;
result = value;
LOOP
L[1] = (result >> blocksize) & blockmask;
R[1] = result & blockmask;
FOR i IN 1..rounds LOOP
L[i+1] = R[i];
R[i+1] = L[i] # ((941083981*R[i] + 768614336404564651) & blockmask);
END LOOP;
result = (L[rounds]::INT8 << blocksize) | R[rounds];
IF result <= max THEN
RETURN result + min;
END IF;
END LOOP;
END;
$$
LANGUAGE plpgsql STRICT IMMUTABLE;
我不能保證其正確性,但你可以很容易地表明,它映射[1,999999]返回[1 ,999999]:
SELECT i FROM generate_series(1,999999) s(i)
EXCEPT
SELECT pseudo_encrypt(i,1,999999) FROM generate_series(1,999999) s(i)
不錯的答案,但是當我使用這個選擇我再次有獨特的問題。它很難用999999條目測試它,但是當我嘗試使用例如99.我再次遇到unqiue驗證問題。 – Pauli