斐波纳契LFSRs计算优化

时间:2011-11-23 10:53:49

标签: c# php perl cryptography mathematical-optimization

在wiki上描述了

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秒的最长执行时间”;

我能以某种方式优化(加速:)计算吗?

任何帮助表示赞赏。谢谢你,请原谅我的英语。

2 个答案:

答案 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;
}