Fibonacci LFSR,这非常简单。 我想用一些Fibonacci的LFSR计算一段时间,然后用生成的序列进行加密。 我们来自wiki:
x 16 + x 14 + x 13 + x 11 + 1;
//code from wiki:
include <stdint.h>
uint16_t lfsr = 0xACE1u;
unsigned bit;
unsigned period = 0;
do {
/* taps: 16 14 13 11; characteristic polynomial: x^16 + x^14 + x^13 + x^11 + 1 */
bit = ((lfsr >> 0) ^ (lfsr >> 2) ^ (lfsr >> 3) ^ (lfsr >> 5) ) & 1;
lfsr = (lfsr >> 1) | (bit << 15);
++period;
} while(lfsr != 0xACE1u);
到目前为止我在php中的弱尝试:
function getPeriod(){
$polynoms = array(16, 14, 13, 11);
$input = $polynoms[0] - 1;
$n = sizeof($polynoms);
for ($i = 1; $i < $n; $i++)
$polynoms[$i] = $polynoms[0] - $polynoms[$i];
$polynoms[0] = 0;
//reversed polynoms == array(0, 2, 3, 5);
$lfsr = 0x1; //begining state
$period = 0;
//gmp -- php library for long numbers;
$lfsr = gmp_init($lfsr, 16);
do {
$bit = $lfsr; //bit = x^16 >> 0;
for($i = 1; $i < $n; $i++) {
//bit ^= lfsr >> 2 ^ lfst >> 3 ^ lfst >> 5;
$bit = gmp_xor($bit, ( gmp_div_q($lfsr, gmp_pow(2, $polynoms[$i])) ));
}
//bit &= 1;
$bit = gmp_and($bit, 1);
//lfsr = $lfsr >> 1 | $lsfr << (16 - 1);
$lfsr = gmp_or( (gmp_div_q($lfsr, 2)), (gmp_mul($bit, gmp_pow(2, $input))) );
$period++;
} while (gmp_cmp($lfsr, 0x1) != 0);
echo '<br />period = '.$period;
//period == 65535 == 2^16 - 1; -- and that's correct;
// I hope, at least;
return $period;
}
问题:
如果我试图调整即工作。
x 321 + x 14 + x 13 + x 11 + 1;
我收到错误消息:“致命错误:/var/www/Dx02/test.php超过30秒的最长执行时间”;
我能以某种方式优化(加速:)计算吗?
任何帮助表示赞赏。谢谢你,请原谅我的英语。
答案 0 :(得分:3)
你不能用x ^ 321 + ...这样的多项式来做这件事;
如果选择多项式,则得到周期长度为2 ^ 231 -1, 这大约是4.27 * 10 ^ 96。如果我没弄错的话,这个数字是 相信超过宇宙中原子的数量...... (严格来说,我指的是发布的C代码,因为我不知道php,但这肯定没有区别。)
但是,有一种数学方法可以计算周期的长度,而不会进行暴力攻击。不幸的是,这不能用几行来解释。如果你有扎实的数学背景(尤其是有限域的计算),我很乐意为你寻找有用的参考。
修改强> 计算通过使用多项式p(x)获得的LFSR的周期的第一步是获得p(x)mod 2的因子分解,即在GF(2)中。为此,我建议使用Mathematica或Maple等软件。你也可以试试免费提供的Sage,参见例如http://www.sagemath.org/doc/constructions/polynomials.html了解使用详情。
p(x)的周期由其阶数e给出,这意味着最小数量使得p(x)偏移x ^ e + 1。不幸的是,我目前无法提供更多信息,我需要几天时间才能找到几年前我所学的课程的讲义......
一个小例子:p(x)=(x ^ 5 + x ^ 4 + 1)=(x ^ 3 + x + 1)*(x ^ 2 + x + 1),各个周期为2 ^ 3-1 = 7和2 ^ 2-1 = 3,并且因为所有多项式因子都不同,所以p(x)的周期是3 * 7 = 21,我也用C ++验证了。
答案 1 :(得分:1)
为了优化这一点,我们需要记住PHP在解析代码时有很大的开销,因为它没有编译,所以我们需要尽可能多地为它做自己的工作。您应该始终使用xdebug + KCachegrind(例如)来分析您的CPU /内存敏感代码,以查看PHP浪费大部分时间的位置。使用代码,只有12%用于gmp_ *函数计算,大部分时间用于代码解析。
在我的笔记本上(它相当慢)我的代码运行2.4秒而不是3.5秒代码,但是对于更大的程度,差异应该更明显(例如19功率给出19对28秒)。它并不多,但它有一些。
我在代码中留下了评论,但如果您有一些问题 - 请随时提问。我使用函数创建来替换主循环中的'for($ i = 1; $ i&lt; $ n; $ i ++)'循环。
另外,我认为您应该将$ period变量的类型更改为GMP(和$ period ++到gmp_ *函数),因为它可能大于系统上的最大整数。
function getPeriod() {
$polynoms = array(16, 14, 13, 11);
$highest = $polynoms[0];
$input = $highest - 1;
//Delete first element of array - we don't need it anyway
array_shift($polynoms);
$polynoms_count = count($polynoms);
//You always repeat gmp_pow(2, $input) and it's result is constant,
//so better precalculate it once.
$input_pow = gmp_pow(2, $input);
//Start function creation.
//If you don't use PHP accelerators, then shorter variable names
//work slightly faster, so I replaced some of names
//$perion->$r,$bit -> $b, $lfsr -> $l, $polynoms -> $p
$function_str = '$r=0;';
$function_str .= 'do{';
//Now we need to get rid of your loop inside loop, we can generate
//static functions chain to replace it.
//Also, PHP parses all PHP tokens, even ';' and it takes some time,
//So, we should write as much one-liners as we can.
$function_str .= '$b=gmp_xor($b=$l';
foreach ($polynoms AS $id => &$polynom) {
//You always repeat gmp_pow(2, $polynoms[$i]) and it's result is constant,
//so better precalculate it once.
$polynom = gmp_pow(2, $highest - $polynom);
//We create our functions chain here
if ($id < $polynoms_count - 1) {
$function_str.=',gmp_xor(gmp_div_q($l, $p[' . $id . '])';
} else {
$function_str.=',gmp_div_q($l, $p[' . $id . '])';
}
}
//Close all brackets
$function_str.=str_repeat(')', $polynoms_count);
//I don't know how to optimize the following, so I left it without change
$function_str.=';';
$function_str.='$l = gmp_or((gmp_div_q($l, 2)), (gmp_mul(gmp_and($b, 1), $i_p)));';
$function_str.='$r++;';
$function_str.='} while (gmp_cmp($l, 0x1));';
$function_str.='return $r;';
//Now, create our funciton
$function = create_function('$l,$p,$i_p', $function_str);
//Set begining states
$lfsr = 0x1;
$lfsr = gmp_init($lfsr, 16);
//Run function
$period = $function($lfsr, $polynoms, $input_pow);
//Use result
echo '<br />period = ' . $period;
return $period;
}