Как настроить вывод функции псевдо-шифрования Postgres?
Я хотел бы использовать функцию pseudo_encrypt, упомянутую несколько раз в StackOverflow, чтобы мои идентификаторы выглядели более случайными: 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;
Для бигинта
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;
2 ответов:
Альтернативное решение: использовать различные шифры
Другие функции шифрования теперь доступны на postgres wiki. Они будут значительно медленнее, но помимо этого, они являются лучшими кандидатами для создания индивидуальных случайных серий уникальных чисел.
Для 32-битных выходов, Skip32 в plpgsql будет шифровать свой вход с ключом шириной 10 байт, так что вам просто нужно выбрать свой собственный секретный ключ, чтобы иметь свою собственную конкретную перестановку (the особый порядок, в котором 2^32 уникальных значения выйдут).
Для 64-битных выходов, XTEA в plpgsql будет делать то же самое, но с использованием ключа шириной 16 байт.
В противном случае, чтобы просто настроить
pseudo_encrypt, смотрите ниже:Пояснения к реализации
pseudo_encrypt:Эта функция имеет 3 свойства
- глобальная унификация выходных значений
- обратимость
- псевдослучайный эффект
Первый и второе свойство исходит из сети Фейстеля, и, как уже объяснялось в ответе @CodesInChaos, они не зависят от выбора этих констант:
1366, а также150889и714025.Убедитесь, что при изменении
f(r1)она остается функцией в математическом смысле, то естьx=yподразумеваетf(x)=f(y), или, другими словами, один и тот же вход всегда должен производить один и тот же выход. Нарушение этого означало бы нарушение единства.Назначение этих констант и этой формулы для
f(r1)состоит в том, чтобы произвести достаточно хороший псевдослучайный эффект. Использование Postgres built-inrandom()или подобного метода невозможно, потому что это не математическая функция, как описано выше.Почему эти произвольные константы? В этой части функции:
r2 := l1 # ((((1366.0 * r1 + 150889) % 714025) / 714025.0) * 32767)::int;Формула и значения
Среди алгоритмов, рассмотренных в этой главе, один, используемый выше, очень прост и относительно эффективен. Формула для получения нового случайного числа из предыдущего (1366,150889и714025исходят изчисленных рецептов в C (1992, Уильям Х. Пресс, 2-е изд.), Глава 7: случайные числа, в частности стр. 284 и 285. Книга не является непосредственно индексируемой на веб, но читаемый через интерфейс здесь: http://apps.nrbook.com/c/index.html . Он также упоминается в качестве ссылки в различных исходных кодах, реализующих PRNGs.jran) такова:jran = (jran * ia + ic) % im; ran = (float) jran / (float) im; /* normalize into the 0..1 range */Где
jran- текущее случайное целое число.Этот генератор обязательно замкнет сам себя после a определенное количество значений ("период"), поэтому константы
ia,icиimдолжны быть тщательно выбраны для того, чтобы этот период был как можно больше. В книге приводится таблица с. 285, где предлагаются константы для различных длин периода.
ia=1366,ic=150889иim=714025является одной из записей на период 229 бит, что намного больше, чем нужно.Наконец, умножение на
32767или 215-1 не является частью PRNG, но предназначен для произведите положительное полуцелое число от 0..1 псевдослучайное значение с плавающей точкой. Не меняйте эту часть, если только не хотите расширить размер блока алгоритма.
Эта функция выглядит как блок - шифр, основанный на сети Фейстеля - но ей не хватает ключа.
Конструкция Фейстеля является биективной, то есть она гарантирует отсутствие столкновений. Интересная часть:r2 := l1 # f(r1). Покаf(r1)зависит только отr1,pseudo_encryptбудет биективным, независимо от того, что делает функция. Отсутствие ключа означает, что любой, кто знает исходный код, может восстановить последовательный идентификатор. Так что вы полагаетесь на безопасность-хотя-неизвестность. Альтернативой является использование блочного шифра, который принимает ключ. Для 32-битных блоков существует относительно мало вариантов, я знаю Skip32 и ipcrypt. Для 64-битных блоков есть много шифров на выбор, включая 3DES, Blowfish иXTEA .
Comments