这是一个函数,用C表示:
uint32_t f(uint32_t x) {
return (x * 0x156) ^ 0xfca802c7;
}
然后我遇到了一个挑战:如何找到所有固定点?
我知道我们可以测试每个uint32_t
值来解决这个问题,但我仍然想知道是否还有其他方式更优雅 - 特别是当uint32_t
成为uint64_t
时(0x156, 0xfca802c7)
是一对任意值。
答案 0 :(得分:15)
Python代码:
def f(x, n):
return ((x*0x156)^0xfca802c7) % n
solns = [1] # The one solution modulo 2, see text for explanation
n = 1
while n < 2**32:
prev_n = n
n = n * 2
lifted_solns = []
for soln in solns:
if f(soln, n) == soln:
lifted_solns.append(soln)
if f(soln + prev_n, n) == soln + prev_n:
lifted_solns.append(soln + prev_n)
solns = lifted_solns
for soln in solns:
print soln, "evaluates to ", f(soln, 2**32)
输出:150129329评估为150129329
算法背后的理念:我们正在尝试查找x XOR 0xfca802c7 = x*0x156 modulo n
,在我们的案例中n=2^32
。我这样写是因为右侧是一个简单的模乘,与左侧表现良好。
我们将要使用的主要属性是x XOR 0xfca802c7 = x*0x156 modulo 2^(i+1)
的解决方案缩减为x XOR 0xfca802c7 = x*0x156 modulo 2^i
的解决方案。另一种说法是,x XOR 0xfca802c7 = x*0x156 modulo 2^i
的解决方案转换为一个或两个模2^(i+1)
的解:这些可能性是x
和/或x+2^i
(如果我们想要更确切地说,当我们说“解决方案”时,我们只关注0,...,模数大小-1之间的整数。)
我们可以轻松地为i=1
解决此问题:x XOR 0xfca802c7 = x*0x156 modulo 2^1
与x XOR 1 = x*0 mod 2
相同,这意味着x=1
是唯一的解决方案。从那里我们知道只有1和3是模2^2 = 4
的可能解。所以我们只有两个尝试。事实证明,只有一个有效。这是我们目前的解决模4.我们可以将解决方案提升到模8的可能性。依此类推。最终我们得到了所有这些解决方案。
备注1:此代码找到所有解决方案。在这种情况下,只有一个,但对于更一般的参数,可能有多个。
备注2:运行时间为O(最大值[解决方案数量,模数大小(以位为单位)],假设我没有出错。所以除非有很多很多固定点,否则它很快。在这种情况下,似乎只有一个。
答案 1 :(得分:5)
让我们使用Z3 solver:
(declare-const x (_ BitVec 32))
(assert (= x (bvxor (bvmul x #x00000156) #xfca802c7)))
(check-sat)
(get-model)
结果为'#x08f2cab1' = 150129329.
答案 2 :(得分:0)
由于位置n
的输入位仅影响位置≥ n
的输出位,因此您知道可以通过选择第一位,然后选择第二位等来找到解决方案。
以下是如何使用C ++解决64位整数的问题(当然它也适用于32位整数):
#include <cstdint>
#include <cstdio>
uint64_t f(uint64_t x) {
return (x * 0x7ef93a76ULL) ^ 0x3550e08f8a9c89c7ULL;
}
static void search(uint64_t x, uint64_t bit)
{
if (bit == 0)
{
printf("Fixed point: 0x%llx\n", (long long unsigned)x);
return;
}
if (f(x + bit) & bit) search(x + bit, bit << 1);
if ((f(x) & bit) == 0) search(x, bit << 1);
}
int main()
{
search(0x0, 1);
}
使用此输出:
Fixed point: 0xb9642f1d99863811