伪加密限制到任意范围

来自 PostgreSQL wiki
跳转到导航跳转到搜索

库片段

pseudo_encrypt_constrained_to_an_arbitrary_range

适用于 PostgreSQL

任何版本

PL/pgSQL

依赖于


pseudo_encrypt 在 32 位范围内(-2,147,483,648 (-231) 到 2,147,483,647 (231 - 1))输出看起来随机的唯一值

为了将值限制在较小的域 [0..N] 中,其中 N 例如是 10 的幂,可以使用循环步进密码技术在 Feistel 网络之上。

需要伪加密() 的变体,并实施以下更改

  • 将块大小缩减到大于范围大小的最近的 2 的偶数次幂。例如,对于范围 [0..10,000,000],最接近的是 224 (16,777,216)。代码中将对 2 个 12 位的半块进行移位和掩码调整。
  • 抑制自反属性,以便值不会立即循环回自身。这是通过在循环结束时重新组合块时反转块来完成的。
  • 添加一个外部循环,该循环应用密码直到结果属于预期范围。为了清晰起见,这在下面在一个单独的函数中完成。

24 位范围的示例源代码

CREATE FUNCTION pseudo_encrypt_24(VALUE int) returns int AS $$
DECLARE
l1 int;
l2 int;
r1 int;
r2 int;
i int:=0;
BEGIN
 l1:= (VALUE >> 12) & (4096-1);
 r1:= VALUE & (4096-1);
 WHILE i < 3 LOOP
   l2 := r1;
   r2 := l1 # ((((1366 * r1 + 150889) % 714025) / 714025.0) * (4096-1))::int;
   l1 := l2;
   r1 := r2;
   i := i + 1;
 END LOOP;
 RETURN ((l1 << 12) + r1);
END;
$$ LANGUAGE plpgsql strict immutable;

CREATE FUNCTION bounded_pseudo_encrypt(VALUE int, max int) returns int AS $$
BEGIN
  loop
    value := pseudo_encrypt_24(value);
    exit when value <= max;
  end loop;
  return value;
END
$$ LANGUAGE plpgsql strict immutable;

示例输出

=> select i,bounded_pseudo_encrypt(i, 10000000) as rnd from generate_series(0,10) as x(i);

 i  |   rnd   
----+---------
  0 | 7388415
  1 | 4878904
  2 | 3247539
  3 | 7670618
  4 | 6551624
  5 | 1212319
  6 | 6156301
  7 |  893851
  8 |  337577
  9 |    4289
 10 |  316941

证明输出是唯一的查询,以及值集是否完全覆盖了预期范围(可能需要几分钟才能运行)

=> select count(distinct rnd) from
   (select bounded_pseudo_encrypt(i, 10000000) as rnd
       from generate_series(0,10000000) as x(i)
   ) as list
 where rnd between 0 and 10000000;

  count   
----------
 10000001