【问题标题】:Can't quite understand this simple pseudo random generator from Schneier in 19921992 年 Schneier 的这个简单的伪随机发生器不太明白
【发布时间】:2014-12-06 03:53:02
【问题描述】:

Schneier 发帖https://www.schneier.com/paper-pseudorandom-sequence.html:

int VERYRANDOM()  {
    static unsigned long regA, regB, regC;
    /*regA, regB, and regC should be initialized with some random value.*/
    regA = ((((regA>>31)^(regA>>6)^(regA>>4)^(regA>>2)^(regA<<1)^regA)
        & 0x00000001)<<31) | (regA>>1);
    regB = ((((regB>>30)^(regB>>2)) & 0x00000001)<<30) | (regB>>1);
    regC = ((((regC>>28)^(regC>>1)) & 0x00000001)<<28) | (regC>>1);
    /*regB is a 31-bit LFSR.  regC is a 29-bit LFSR.*/
    /*Both feedback sequences are chosen to be maximum length.*/
    return ((regA & regB) | (!regA & regC)) & 0x00000001;
    /*Above is equivalant to:  if A then return B else return C.*/
    /* Variants:  return ((regA & regB) | (regA & regC) | (regB & regC)) &
    0x00000001; Above variant returns the majority of A, B, and C.
    return (regA ^ regB ^ regC) & 0x00000001;
    Above variant returns the XOR of A, B, and C.  */
}

最后警告不要盲目地选择不同的反馈顺序。为了避免走上这样的死胡同,我阅读了 LFSR 和定义它们的多项式。

在一个地方,http://www.newwaveinstruments.com/resources/articles/m_sequence_linear_feedback_shift_register_lfsr.htm 非常友好地列出了针对任何抽头的最大长度多项式(为了清晰起见,由于可以选择更多抽头,因此对其进行了删节)。对于 32 位 LFSR,我不明白 Schneier 从哪里得到多项式:

    regA = ((((regA>>31)^(regA>>6)^(regA>>4)^(regA>>2)^(regA<<1)^regA)
        & 0x00000001)<<31) | (regA>>1);

根据 LFSR 上的维基百科,等效多项式将是:

    //Fibonacci x^1         x^26      x^28     x^30      x^31     x^32      
    regA = ((((regA>>31)^(regA>>6)^(regA>>4)^(regA>>2)^(regA<<1)^regA)
        & 0x00000001)<<31) | (regA>>1);

不在桌子上:

[32、31、30、29、5、1]
[32、31、30、28、27、3]
[32、31、30、28、26、13]
[32、31、30、28、23、21]
[32、31、30、28、23、18]
[32、31、30、28、20、15]
[32、31、30、28、20、3]
[32、31、30、28、19、2]
[32、31、30、28、19、1]
[32、31、30、28、17、9]
[32、31、30、28、17、4]
[32、31、30、28、17、3]
[32、31、30、28、15、5]
[32、31、30、28、14、2]
[32、31、30、28、12、9]
[32、31、30、28、10、7]
[32, 31, 30, 27, 26, 9]

我不想在学习加密的基础知识时误解任何东西,为什么我不明白呢?在尝试应用维基百科示例中的术语之前,我已经诊断多项式为:

    //                      25      27          29      30      31
    regA = ((((regA>>31)^(regA>>6)^(regA>>4)^(regA>>2)^(regA<<1)^regA)
        & 0x00000001)<<31) | (regA>>1);

但它是对(最左边的)MSbit 进行异或运算,然后下落不明,此外,奇数的抽头肯定表明我错了。

多项式的维基百科翻译是:

    /* taps: 16 14 13 11; feedback polynomial: x^16 + x^14 + x^13 + x^11 + 1 */
    bit  = ((lfsr >> 0) ^ (lfsr >> 2) ^ (lfsr >> 3) ^ (lfsr >> 5) ) & 1;

我猜维基百科和 newwaveinstruments 使用不同的术语,但如果我无法破译它是什么,我就会忘记理解密码学。

【问题讨论】:

  • 目前我只能投赞成票,但如果您想了解密码学,那么您首先需要了解这不是加密。永远不要忘记添加语言标签;如果您认为您的问题可以不使用它们:请改用crypto.stackexchange.com
  • 我无法回答您的问题,但我认为代码中有错字(错字在 Schneier 的文章中)。我认为代码((((regA&gt;&gt;31)^(regA&gt;&gt;6)^(regA&gt;&gt;4)^(regA&gt;&gt;2)^(regA&lt;&lt;1)^regA) 应该是((((regA&gt;&gt;31)^(regA&gt;&gt;6)^(regA&gt;&gt;4)^(regA&gt;&gt;2)^(regA&gt;&gt;1)^regA)。也就是说,最后的移位操作应该是右移而不是左移。
  • 迈克尔·伯尔是对的。这只是一个印刷错误。在 Schneier 的同一篇文章中将其与 RANDOM 进行比较。其次,LFSR 没有周期 2^32 - 1。只需将 regA 分配给任何非零值并循环,直到获得相同的值。周期为 0x5553EAAA = 1,431,562,922。 Schneier 的工作从未给人留下深刻印象。

标签: c random cryptography xor prng


【解决方案1】:

哇。这段代码真的很烂。

当种子值为 1 时,第一个 LFSR 仅在 107,359,437 次迭代后重复自身。这远远低于使用最大长度 32 位 LFSR 可获得的 40 亿次迭代。使用其他种子值,结果可能会更糟。

事实上,由于其他两个 LFSR 在反馈循环中不包含位 0,因此将其中任何一个设为 1 将导致它们立即生成无限的零序列。

坦率地说,我很惊讶拥有 Schneier 资质的人竟然会想出这么垃圾的东西。

无论如何,LFSR 对加密应用完全没有用处。 ARCFOUR 包括一个简单的伪随机生成器,它比Shneier 的工作要好得多,而且可能也快很多。但是不要去发明自己的密码学方法。真的没必要:-)

【讨论】:

  • 我放入了一些其他种子,得到了相同的重复周期。我想像这样将代码塞进一行可能会被认为是suck,尽管它可能被认为是看不见的,因为它被严重破坏了,是的,那就是垃圾好吧。我不会讨论它的加密功效,它在适当的安全性开销太大的情况下充当混淆器。
【解决方案2】:

这是 [32, 7, 5, 3, 2, 1, 0] 的正确版本(Schneier 的符号来自 Applied Cryptography, 2nd Edition 中的表 16.2)。

#include <cstdio>

// regA should be initialized with some random n0n-zero value.
static unsigned long regA;

int rand_bit()
{
    int length = 32;
    regA = (((
          (regA >> 7)
        ^ (regA >> 5)
        ^ (regA >> 3)
        ^ (regA >> 2)
        ^ (regA >> 1)
        ^ (regA >> 0))
        & 0x00000001)
        << (length - 1))
        | (regA >> 1);
    return regA & 0x00000001;
}

int main()
{
    const unsigned long start = 0x00000001;
    regA = start;
    for (unsigned long c = 1; ; ++c)
    {
        int bit = rand_bit();
        //printf("%d\n", bit);

        if (regA == start)
        {
            printf("%#010x\n", c);

            break;
        }
    }

    return 0;
}

如果您想从http://www.newwaveinstruments.com/resources/articles/m_sequence_linear_feedback_shift_register_lfsr/32stages.txt 执行 [32, 31, 30, 29, 5, 1],您将使用以下版本的 rand_bit。请注意,使用 Schneier 的符号,这将是 [32, 31, 30, 29, 5, 1, 0]。

int rand_bit()
{
    int length = 32;
    regA = (((
          (regA >> 31)
        ^ (regA >> 30)
        ^ (regA >> 29)
        ^ (regA >> 5)
        ^ (regA >> 1)
        ^ (regA >> 0))
        & 0x00000001)
        << (length - 1))
        | (regA >> 1);
    return regA & 0x00000001;
}

【讨论】:

    猜你喜欢
    • 2013-11-07
    • 2013-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-05
    • 2010-11-18
    • 2011-03-05
    • 1970-01-01
    相关资源
    最近更新 更多