【问题标题】:Create ordered hash function by timestamp按时间戳创建有序哈希函数
【发布时间】:2021-05-05 14:39:01
【问题描述】:

我想创建一个散列函数,给定一个时间戳,它将返回一个整数散列以用作“有序索引”

statement: x > y = f(x) > f(y) // x, y are primitive long timestamps (e.g. 1612181315000)

// f(x) or f(y) is aimed to be used in the frontend as "ordered index"

我计划将这个新的“有序索引”而不是真正的时间戳返回给前端,这将允许我“按时间”对前端消费者的结果进行排序,而不是出于隐私原因返回真正的时间戳。

但是,一些真实的时间戳(标记为可见)将返回到前端。因此,不能使用线性函数,因为可以为不可见的时间戳计算此静态偏移量。

一些限制:

  • 需要为每个时间戳执行解决方案(我们无法预先对时间戳进行分组)
  • 我认为线性函数是不可能的,因为有时我们还要传递真正的时间戳,因此可以在前端使用时间戳和 f(timestamp) 轻松计算偏移量。

请您指出一个可行的算法/解决方案吗?

提前致谢。

【问题讨论】:

  • "x > y = f(x) > f(y)" 那是不可能的。哈希函数生成哈希码,32位哈希码不能代表所有输入的所有不同值,这意味着一些不同的输入可能会生成相同的哈希码,即x > y = f(x) >= f(y)可能是可行的。
  • 您需要支持什么日期范围?例如。如果f(x) = x / 10000,那么您将在 10 秒块中获得相同的哈希码,并支持从1289-06-282650-07-05 的日期范围。
  • 您只能获得 1289 - 2650 年的日期范围和 10 秒的块。如果您更改为f(x) = x / 1000 以获得相同哈希码的1 秒块,则支持的日期范围将减少到1901-12-142038-01-18。 --- 这就是为什么我们会在 2038 年看到另一个“千年虫”错误,因为仍然有代码将时间存储为 32 位值中自纪元以来的秒数。
  • 是否可以在要散列的数据中放入一个序列号,然后使用散列值的位子集来存储该序列号?可能需要额外的工作来确保剩余的“散列”位仍然是表现良好的散列函数。
  • 几年前,我们研究是否可以在端到端加密文件存储解决方案中添加一些服务器端搜索功能。该问题与您的问题相似,在不知道您正在处理的实际数据的情况下进行有意义的计算。我所知道的唯一“真正”的解决方案是使用同态密码学,但 AFAIK 到今天仍然不可行。编辑:在你的情况下,即使是同态密码学也行不通,因为知道有序列表本身就是问题,会泄露信息。

标签: java algorithm sorting math hash


【解决方案1】:

仅供那些好奇的人使用:我为非加密目的制作了一个随机单调函数,只是为了让我们可以一睹我对此类函数图的期望喜欢。我仍然不建议将它用于 OP 的订购任务,但它让我认为这些要求毕竟是有意义的。

  • 使用的单调函数应该是保密的(我的意思是它应该是一个密钥加密函数,密钥在服务器上隐藏和保护)
  • 必须仔细编写服务器,不要提供将时间戳转换为“哈希”的预言机。这样的预言机将使从哈希中获取时间戳成为可能。

const N = 1000000n;
const SEED = 0x2545F4914F6CDD1Dn;
const RES = 200;

function main() {
    let ctx = mycanvas.getContext("2d");
    ctx.moveTo(0, 0);
    for (let xs = 0; xs < RES; xs++) {
        let x = BigInt(xs / RES * Number(N));
        let y = monorand(x);
        ctx.lineTo(Number(x) * RES / Number(N), Number(y) * RES / Number(N));
    }
    ctx.stroke();
}

function monorand(x) {
    return _monorand(x, 0n, N, 0n, N, SEED);
}

function _monorand(x, xmin, xmax, ymin, ymax, seed) {
  if (xmax - xmin <= 1n || ymax - ymin <= 1n) {
      return ymin;
  }
  let xpivot = _between(seed, xmin, xmax);
  seed = _xorshift_like(seed);
  let ypivot = _between(seed, ymin, ymax);
  seed = _xorshift_like(seed);

  if (x < xpivot) {
    seed ^= 0x545F4914F6CDD1D2n;
    return _monorand(x, xmin, xpivot, ymin, ypivot, seed);
  } else {
    return _monorand(x, xpivot, xmax, ypivot, ymax, seed);
  }
}

function _between(seed, xmin, xmax) {
    return (seed % (xmax - xmin - 1n)) + (xmin + 1n);
}

function _xorshift_like(x) {
  x ^= x >> 12n;
    x ^= x << 25n;
    x ^= x >> 27n;
  return x & 0xffffffffffffffffn;
}

main();
&lt;canvas width=200 height=200 id=mycanvas&gt;&lt;/canvas&gt;

【讨论】:

    【解决方案2】:

    我建议您在服务器端订购条目,并将“时间索引”发送到前端。严格来说,该算法不是哈希函数,因为输出取决于所有输入条目,而不仅仅是一个,但在您的用例中应该没问题。从隐私的角度来看,这是最好和最简单的解决方案。任何其他功能都会泄漏比需要更多的信息。所有的单调函数都可以使用二分搜索来求逆,因此它们并不真正满足哈希函数的要求,至少在密码学意义上是这样。

    【讨论】:

    • 我无法在服务器端订购条目,因为我有不同的后端。一些后端将信息作为推送通知推送到前端。这意味着所需的机制应该由每个注册表独立运行。
    猜你喜欢
    • 2015-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-15
    • 2011-05-04
    • 2013-12-20
    • 2011-04-20
    相关资源
    最近更新 更多