【问题标题】:Understanding Cyclic Redundancy Code algorithm for beginners了解初学者的循环冗余码算法
【发布时间】:2020-09-21 20:57:41
【问题描述】:

section 5.5 of the PNG Specification,它以称为“CRC”或“循环冗余码”的PNG 文件格式讨论了这个概念。我以前从未听说过它,所以我试图理解它。

使用的 CRC 多项式是

x32 + x26 + x23 + x22 + x16 sup> + x12 + x11 + x10 + x8 + x7 sup> + x5 + x4 + x2 + x + 1

在PNG中,32位CRC被初始化为全1,然后数据 从每个字节被处理从最低有效位(1)到 最高有效位 (128)。处理完所有数据字节后, CRC 被反转(取其补码)。这个值是 首先传输(存储在数据流中)MSB。为了...的目的 分成字节和排序,最低有效位 32位CRC被定义为x31项的系数。

那么让我告诉你我理解和不理解的地方。

我听说过多项式,但在这种情况下,我对它们在此处的实现方式有些困惑。

在这种情况下,“x”应该代表什么? 32 位循环中的当前位?这将我们带到下一部分:

所以它说创建一个空的 32 位数字(或者更确切地说,全部设置为 1,所以 32 个 1),然后它说它“从最低有效位 (1) 处理到最高有效位 (128) ”,但问题是,what 的“最少...最多..significant bit”?

块中的其他数据?

如果块以字节为单位设置,并且这只有 32 位,那它是如何工作的?如果块数据中有超过 32 位怎么办(肯定有?)

这是否意味着“多项式”的“最少..最多..有效位”?

但是多项式究竟代表什么? x^32 是什么?

x 代表什么?

对上述问题的任何帮助,也许还有一个简单的例子,比如 IDATA 块(AKA 用基本解释为它计算 CRC 块)会很好:

0 0 2 3 IDAT 0 1 0 1 0 1 0 1 0 1 0 C

最后一个字节“C”应该被替换为它所说的 32 位 CRC。

谁能给我一个实际的例子?

【问题讨论】:

  • "我不知道他们在 for 循环中从哪里得到这么大的位数,也不知道在哪里插入字节数组" - 这是 32 位的标准数字之一CRC。转到wiki article,然后向下滚动到 32 位 CRC,您会在那里看到 CRC 的选择方式很复杂,我不知道为什么要从一组具有相同的 CRC 中选择特定的 CRC错误检测能力。
  • @rcgldr 嗨,谢谢,我在 wiki 上注意到它提供了一些示例,使用来自其他示例问题的相同多项式。问题是我想了解如何从多项式中得出那个 32 位数组。我仍然很困惑“x”代表什么,它在另一个答案中提到没有“插入”它,但是它是什么,该多项式如何给出 4 个不同的位结果?另一点是,一旦我 拥有 32 位字符串,那么我该如何处理另一个输入,我是否会遍历另一个字节数组然后做一些事情,但是呢?
  • @rcgldr 我也搜索了一个 javascript 解决方案,我能找到的只是这个 medium.com/the-guardian-mobile-innovation-lab/… 但他们使用了 CRC 的内置函数.. 大多数其他人要么使用画布,或其他一些库,或服务器端代码
  • @rcgldr 问题是我对多种格式和压缩都不感兴趣,我只对一个非常简单的 PNG 生成器感兴趣(主要在谷歌应用程序脚本中运行),而且几乎没有重量极轻的 javascirpt PNG 库(pngJS 太矫枉过正)无法实现我想要的
  • 好的,但是即使压缩被关闭,zlib 压缩头和 CRC(我的印象是与 PNG CRC 是分开的)不是必需的吗?你需要一些东西。

标签: javascript png crc libpng crc32


【解决方案1】:

我会推荐阅读罗斯威廉姆斯的经典作品"A Painless Guide to CRC Error Detection Algorithms"。您将在其中找到深入的解释和示例。

多项式只是解释一串位的另一种方式。当您在寄存器中有 n 位时,它们通常被解释为 n 个独立位的列表,或者它们被解释为整数,您可以在其中将每个位乘以 0n-1 次方的 2,然后将它们相加。多项式表示是您将每个位解释为多项式系数的地方。由于位只能是 01,因此生成的多项式实际上不会显示 01 .相反,xn 术语要么存在,要么不存在。所以1011这四位可以解释为1 x3 + 0 x2 + 1 x1 + 1 x 0 = x3 + x + 1。请注意,我选择最高有效位是 x3 项的系数。这是一个随意的选择,我本可以选择另一个方向。

至于x是什么,它只是x的系数和幂的占位符。您永远不会将 x 设置为某个值,也不会确定有关 x 的任何内容。它的作用是允许您将这些位串作为多项式进行运算。在对这些多项式进行运算时,您就像在代数类中的多项式一样对待它们,只是系数被限制在 GF(2) 域中,其中系数只能是 0 或 1。乘法变为与运算,加法变为异或运算。所以 1 加 1 就是 0。你得到了一种新的不同的方法来加、乘和除位串。这种不同的方式是许多错误检测和纠正方案的关键。

有趣但最终无关紧要的是,如果您在位串的多项式表示中将 x 设置为 2(使用正确的排序选择),您获取该位字符串的整数解释。

【讨论】:

【解决方案2】:

规范包含示例代码的链接:

https://www.w3.org/TR/2003/REC-PNG-20031110/#D-CRCAppendix

规范有错误或令人困惑。

应该是“每个字节的数据从最低有效位(0)到最高有效位(7)处理。

CRC 是一个 33 项多项式,其中每个项都有一个位系数,0 或 1,在描述多项式时忽略 0 系数。

将 CRC 视为保存在 32 位寄存器中。该序列是将一个数据字节异或到 CRC 寄存器的最右边字节,第 7 位到第 0 位(技术上对应于 x^24 到 x^31 的多项式系数)。然后 CRC 向右“循环” 8 位(通过查表)。一旦所有数据字节都经过了这个循环,根据 Mark Adler 的评论,CRC 会先附加到数据最高有效字节,(CRC>>24)&0xff, (CRC>>16)&0xff, (CRC>> 8)&0xff, (CRC)&0xff.

维基文章可能会有所帮助。对于计算部分中的示例,被除数将是一个数据字节数组,其中每个字节的位反转,33 位多项式的位将不反转(0x104C11DB7)。完成计算后,余数的位将被反转并附加到数据字节中。

https://en.wikipedia.org/wiki/Cyclic_redundancy_check


Mark Adler 的回答包括一个指向 CRC 的优秀教程的链接。他的回答还解释了多项式中使用的 x。它就像代数中的多项式,只是系数只能是 0 或 1,加法(或减法)是使用 XOR 完成的。


什么是x

来自 wiki 示例:

data     = 11010011101100 = x^13 + x^12 + x^10 + x^7 + x^6 + x^5 + x^3 + x^2
divisor  =           1011 = x^3 + x + 1

三个 0 位附加到数据中,有效地将其乘以 x^3:

dividend = 11010011101100000 = x^16 + x^15 + x^13 + x^10 + x^9 + x^8 + x^6 + x^5

然后是 crc = 被除数 % 除数,系数限制为 0 或 1。

(x^16 + x^15 + x^13 + x^10 + x^9 + x^8 + x^6 + x^5) % (x^3 + x + 1) = x^2
11010011101100000 % 1011 = 100

【讨论】:

  • 不,CRC 并不总是按照给出固定残基的顺序附加到数据中。事实上,在这种特殊情况下,PNG 以相反的字节顺序附加 CRC。计算类型和数据字段上的 CRC,然后将其在数据中的大端顺序重新组装后与块中的 CRC 进行简单比较。
  • @MarkAdler - 谢谢 - 我更新了我的答案。链接首先声明 MSB,不清楚 MSB 是指反转多项式的最高有效字节,还是保存 CRC 的寄存器的 MSB。
  • 我的理解是肯定的,因为它是在HDLC中使用的。
  • 您询问 CRC 是否已在硬件中实现。 PNG不太可能在硬件中实现。
  • 是的,这个 CRC 已经在硬件中实现了。 PNG没有。
【解决方案3】:

注意:如果您使用 (00000000)_2 和 (00000001)_2 作为示例 IDAT 块中 0 和 1 的二进制表示,您将错误地计算 CRC。 '0' 和 '1' 的 ASCII 值是 48 = (00110000)_2 和 49 = (00110001)_2;同样,“I”、“D”、“A”和“T”的 ASCII 值是 73 = (01001001)_2、68 = (01000100)_2、65 = (01000001)_2 和 84 = (01010100) _2。因此,假设你的意思是值0和1,而不是字符 '0' 和 '1',你必须计算的CRC(01001001 01000100 01000001 01010100 00000000 00000001 00000000 00000001 00000000 00000001 00000000 00000001 00000000 00000001 00000000)2。

与CRC无关,但与块的有效性无关,块的长度字段(即前4个字节)应仅包含数据的字节长度,即11,即ASCII值垂直制表符 (VT),它是一个非打印字符,但可以通过十六进制转义序列 \x0B(其中 (B)_16 = 11)在字符串中表示。同样,前 3 个字节必须包含 ASCII 值为 0(而不是 48)的字符,即为空(NUL),可以用十六进制转义序列 \x00 在字符串中表示。因此,长度字段必须包含类似“\x00\x00\x00\x0B”的内容。

【讨论】:

  • 在 JavaScript 中,\0 是 NUL 的另一个转义序列;并且,\v 是 VT 的另一个转义序列。
  • 嗨,谢谢,我只是在理解这一点时遇到了一些麻烦。 CRC32 是不是像一个函数一样,它接受一个输入(你提到的字节值的数组)并返回一个响应?
  • 是的。对于 PNG 块:输入是 4 字节类型(如“IDAT”),后跟长度*字节数据;并且,输出是一个 4 字节 = 32 位无符号整数(因此,CRC-32)。 *注意:不包括 4 字节长度。
  • aha 很有趣,所以我感到困惑的另一部分是 CRC 函数的输入总是正好 4 个字节?如果不是,那么它如何根据大于 4 字节的内容给出 4 字节的输出? PNG文件的某些块不会占用超过4个字节,例如是否有10mb的像素?还是将该数据的每 4 个字节拆分为一个单独的 CRC 内容?
  • 没有。对于您的示例块,输入将是 4 + 11 = 15 个字节。字节在处理时循环通过待输出(寄存器)(因此,循环 RC)。最小块大小为 12 字节——一个包含 0 的 4 字节长度,后跟一个 4 字节类型,然后是该类型的 4 字节 CRC。
猜你喜欢
  • 1970-01-01
  • 2016-01-05
  • 1970-01-01
  • 2014-07-18
  • 2023-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-21
相关资源
最近更新 更多