function pseudo_encrypt () em plpgsql que leva bigint

Eu estou trabalhando em um sistema que gera ids randoms como na resposta # 2 aqui .

Meu problema é que a function pseudo_encrypt () mencionada trabalha com int não bigint. Tentei reescrevê-lo, mas ele retorna sempre o mesmo 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; 

Alguém pode verificar isso?

4294967295 deve ser usado como bitmask para selecionar 32 bits (em vez de 4294967296 ). Essa é a razão pela qual atualmente você obtém o mesmo valor para inputs diferentes.

Eu também sugiro usar bigint para os tipos de l2 e r2 , eles não devem diferir de r1 e l1

E, para melhor aleatoriedade, use um multiplicador muito maior na function PRNG para obter o bloco intermediário que realmente ocupa 32 bits, como 32767 * 32767 em vez de 32767.

A versão 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; 

Primeiros resultados:

 selecione 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 linhas)

Velho, mas ainda é uma questão interessante. Comparando com a resposta de Daniels estou usando uma versão ligeiramente modificada, alterando a declaração de retorno para esta (trocada r1 e l1), como também mencionada no final do artigo Pseudo criptografar :

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

A razão para essa mudança é que o algoritmo Feistel subjacente não deve trocar à esquerda e à direita no final da última rodada. Com essa mudança, a function recupera a capacidade de agir como sua própria function inversa:

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

Aqui está o código completo em 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;