Función pseudo_encrypt () en plpgsql que toma bigint

Estoy trabajando en un sistema que genera identificadores aleatorios como en la respuesta # 2 aquí .

Mi problema es que la function pseudo_encrypt () mencionada funciona con int not bigint. Traté de reescribirlo pero siempre devuelve el mismo resultado:

CREATE OR REPLACE FUNCTION pseudo_encrypt(VALUE bigint) returns bigint AS $$ DECLARE l1 bigint; l2 int; r1 bigint; r2 int; i int:=0; BEGIN l1:= (VALUE >> 32) & 4294967296::bigint; r1:= VALUE & 4294967296; WHILE i < 3 LOOP l2 := r1; r2 := l1 # ((((1366.0 * r1 + 150889) % 714025) / 714025.0) * 32767)::int; l1 := l2; r1 := r2; i := i + 1; END LOOP; RETURN ((l1::bigint << 32) + r1); END; $$ LANGUAGE plpgsql strict immutable; 

¿Alguien puede verificar esto?

4294967295 debe utilizar como la máscara de bits para seleccionar 32 bits (en lugar de 4294967296 ). Esa es la razón por la que actualmente obtienes el mismo valor para diferentes inputs.

También sugiero usar bigint para los types de l2 y r2 , en realidad no deberían diferir de r1 y l1

Y, para una mejor aleatoriedad, use un multiplicador mucho más alto en la function PRNG para get un bloque intermedio que realmente ocupe 32 bits, como 32767 * 32767 en lugar de 32767.

La versión modificada completa:

 CREATE OR REPLACE FUNCTION pseudo_encrypt(VALUE bigint) returns bigint AS $$ 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)::int; l1 := l2; r1 := r2; i := i + 1; END LOOP; RETURN ((l1::bigint << 32) + r1); END; $$ LANGUAGE plpgsql strict immutable; 

Primeros resultados:

 select x, pseudo_encrypt (x :: bigint) de generate_series (1, 10) como x;
  x |  pseudo_encrypt    
 ---- + ---------------------
   1 |  3898573529235304961
   2 |  2034171750778085465
   3 |  169769968641019729
   4 |  2925594765163772086
   5 |  1061193016228543981
   6 |  3808195743949274374
   7 |  1943793931158625313
   8 |  88214277952430814
   9 |  2835217030863818694
  10 |  970815170807835400
 (10 filas)

Viejo, pero sigue siendo una pregunta interesante. Comparando con la respuesta de Daniels, estoy usando una versión ligeramente modificada, cambiando la statement de devolución a esta (intercambié r1 y l1), como también mencioné al final del artículo Pseudo encryption :

 RETURN ((r1::bigint << 32) + l1); 

La razón de este cambio es que el algorithm de Feistel subyacente no debería intercambiarse a la izquierda al final de la última ronda. Con este cambio, la function recupera la capacidad de actuar como su propia function inversa:

 pseudo_encrypt(pseudo_encrypt(x) == x // always returns true 

Aquí está el código completo en pgsql:

 CREATE OR REPLACE FUNCTION pseudo_encrypt(VALUE bigint) returns bigint AS $$ 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)::int; l1 := l2; r1 := r2; i := i + 1; END LOOP; RETURN ((r1::bigint << 32) + l1); END; $$ LANGUAGE plpgsql strict immutable;