如何自定义Postgres Pseudo Encrypt函数的输出?

avi*_*ian 3 encryption postgresql

我想在StackOverflow上使用几次提到的pseudo_encrypt函数来使我的ID看起来更随机:https://wiki.postgresql.org/wiki/Pseudo_encrypt

如何自定义此选项以便为我输出唯一的"随机"数字.我在某处读到你可以改变1366.0常数,但我不想冒任何ID冒险,因为任何潜在的ID重复会导致重大问题.

我真的不知道每个常数实际上做了什么,所以除非我得到一些方向,否则我不想乱用它.有谁知道我可以安全地改变哪些常数?

这里是:

CREATE OR REPLACE FUNCTION "pseudo_encrypt"("VALUE" int) RETURNS int     IMMUTABLE STRICT AS $function_pseudo_encrypt$
DECLARE
l1 int;
l2 int;
r1 int;
r2 int;
i int:=0;
BEGIN
    l1:= ("VALUE" >> 16) & 65535;
    r1:= "VALUE" & 65535;
    WHILE i < 3 LOOP
        l2 := r1;
        r2 := l1 # ((((1366.0 * r1 + 150889) % 714025) / 714025.0) * 32767)::int;
        r1 := l2;
        l1 := r2;
        i := i + 1;
END LOOP;
RETURN ((l1::int << 16) + r1);
END;
$function_pseudo_encrypt$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

对于bigint的

CREATE OR REPLACE FUNCTION "pseudo_encrypt"("VALUE" bigint) RETURNS bigint IMMUTABLE STRICT AS $function_pseudo_encrypt$
DECLARE
l1 bigint;
l2 bigint;
r1 bigint;
r2 bigint;
i int:=0;
BEGIN
    l1:= ("VALUE" >> 32) & 4294967295::bigint;
    r1:= "VALUE" & 4294967295;
    WHILE i < 3 LOOP
        l2 := r1;
        r2 := l1 # ((((1366.0 * r1 + 150889) % 714025) / 714025.0) * 32767*32767)::bigint;
        r1 := l2;
        l1 := r2;
        i := i + 1;
    END LOOP;
RETURN ((l1::bigint << 32) + r1);
END;
$function_pseudo_encrypt$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

Dan*_*ité 5

替代解决方案:使用不同的密码

其他密码函数现在可以在postgres wiki上找到.它们会明显变慢,但除此之外,它们更适合生成定制的随机系列的独特数字.

对于32位输出,plpgsql中的Skip32将使用10字节宽的密钥加密其输入,因此您只需选择自己的密钥即可拥有自己的特定排列(2 ^ 32个唯一值的特定顺序将会出现).

对于64位输出,plpgsql中的XTEA将执行类似操作,但使用16字节宽的密钥.

否则,只需自定义pseudo_encrypt,请参阅以下内容:

关于pseudo_encrypt实施的解释:

此功能有3个属性

  • 全球产值的唯一性
  • 可逆性
  • 伪随机效应

第一个和第二个属性来自Feistel网络,正如在@ CodesInChaos的答案中已经解释的那样,它们不依赖于这些常量的选择:1366还有150889714025.

确保在更改时f(r1)它在数学意义上保持功能,这x=y意味着f(x)=f(y),或者换句话说,相同的输入必须始终产生相同的输出.打破这一点将打破这种独特性.

这些常数和这个公式的目的f(r1)是产生一个相当好的伪随机效应.使用postgres内置random()或类似的方法是不可能的,因为它不是如上所述的数学函数.

为什么这些任意常数?在这部分功能中:

r2 := l1 # ((((1366.0 * r1 + 150889) % 714025) / 714025.0) * 32767)::int;
Run Code Online (Sandbox Code Playgroud)

式和的值1366,150889714025来自 在C数字食谱,第7章(1992年,由William H.Press,第2版):随机数,具体p.284和285.书不是在网络上直接可转位,但通过这里的界面可读:http://apps.nrbook.com/c/index.html.它也被引用作为实现PRNG的各种源代码的参考.

在本章讨论的算法中,上面使用的算法非常简单且相对有效.从前一个(jran)获取新的随机数的公式是:

jran = (jran * ia + ic) % im;
ran = (float) jran / (float) im;  /* normalize into the 0..1 range */
Run Code Online (Sandbox Code Playgroud)

其中jran是当前的随机整数.

该发电机将必然遍历本身有一定数目的值(以下简称"期间"),所以常量后ia,ic并且im必须被仔细地选择该周期为尽可能地大.这本书提供了一个表p.285,其中建议了不同长度的常数.

ia=1366,ic=150889并且im=714025是2 29位期间的条目之一,这是不仅仅需要的方式.

最后乘以32767或2 15 -1不是PRNG的一部分,而是意味着从0..1伪随机浮点值产生正半整数.除非扩大算法的块大小,否则不要更改该部分.