Pseudo encrypt
From PostgreSQL wiki
pseudo_encrypt
Any version
PL/pgSQL
Nothing
This function was posted by Daniel Verite in http://archives.postgresql.org//pgsql-general/2009-05/msg00082.php
Given an input within int32 range, this function produces a different output within the same range. For any given input, the output is the same each time, and for any given output there is only one input that results in that output.
This function is a Feistel network; see http://en.wikipedia.org/wiki/Feistel_cipher
CREATE OR REPLACE FUNCTION pseudo_encrypt(VALUE int) returns bigint AS $$ 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; l1 := l2; r1 := r2; i := i + 1; END LOOP; RETURN ((l1::bigint << 16) + r1); END; $$ LANGUAGE plpgsql strict immutable;
Note that it returns a bigint because we don't have unsigned integers in PG. If you're OK with getting negative values, the return type can be changed to int.
Otherwise if you need a positive result that fits in 32 bits, it's possible to tweak the code to use 15 bits blocks instead of 16, but then the input will have to be less than 2^30.
Jaka Jancar, 7.1.2012: Since a normal Feistel Cipher does't swap left and right in last iteration, I believe the return line should have l1 and r1 reversed. This has the upside of pseudo_encrypt(pseudo_encrypt(X)) returning X. I'm also wondering why the LCG parameters are for 2^29 and whether 1366 really needs to be a float.
