轻量级校验和算法的不错选择?

时间:2009-01-07 18:21:35

标签: java javascript hash checksum

为了保持一致性,我发现自己需要为一串数据生成校验和。广义的想法是客户端可以根据收到的有效负载重新生成校验和,从而检测传输过程中发生的任何损坏。我隐约意识到这种事情背后有各种各样的数学原理,如果你试图自己滚动,那么微妙的错误就很容易使整个算法失效。

所以我正在寻找有关哈希/校验和算法的建议,其中包括以下标准:

  • 它将由Javascript生成,因此需要在计算上相对较轻。
  • 验证将由Java完成(虽然我看不出这实际上是一个问题)。
  • 它将采用中等长度的文本输入(URL编码的Unicode,我相信是ASCII);通常约200-300个字符,在所有情况下都低于2000。
  • 输出也应该是ASCII文本,越短越好。

我主要对轻量级的东西感兴趣,而不是让碰撞的绝对最小潜力成为可能。我是否天真地想象一个八字符哈希适合这个?我还应该澄清,如果在验证阶段没有发现腐败,那么这不是世界末日(而且我确实认识到这不会100%可靠),尽管我的其余代码对每个代码的效率都显着降低通过的腐败入境。

编辑 - 感谢所有贡献。我使用了Adler32选项并且认为它在Java中原生支持,在Javascript中非常容易实现,在两端快速计算并且具有8字节输出,它完全符合我的要求。

(请注意,我意识到网络传输不太可能对任何损坏错误负责,并且不会在这个问题上折叠我的手臂;但是添加校验和验证会消除一个故障点,这意味着我们可以关注在其他领域应该再次发生。)

9 个答案:

答案 0 :(得分:14)

CRC32在任何语言中都难以实现,它足以检测简单的数据损坏,并且在以良好的方式实现时,它非常快。不过你也可以尝试Adler32,它几乎和CRC32一样好,但它实现起来更容易(并且速度相同)。

Adler32 in the Wikipedia

CRC32 JavaScript implementation sample

这两个中的任何一个(或者甚至两个)都可以在Java中使用。

答案 1 :(得分:6)

是否知道TCP和UDP(以及IP,以太网和......)已经为传输中的数据提供校验和保护?

除非你做的事情非常奇怪,否则如果你看到腐败,那就是非常错误的。我建议从memory tester开始。

此外,如果您使用SSL / TLS,则会获得强大的数据完整性保护。

答案 2 :(得分:2)

[更新2013年3月30日:旧JS CRC32实施的链接已经过时,所以我现在已经链接到另一个。]

Google CRC32:速度快,重量轻于MD5等。有一个Javascript实现here

答案 3 :(得分:2)

答案 4 :(得分:2)

其他人已经提到过CRC32,但是这里是W3C implementation of CRC-32 for PNG的链接,作为少数知名的,有信誉的网站之一,参考CRC实现。

(几年前,我试图找到一个着名的CRC算法网站或者至少有一个引用其算法来源的网站,并且在我找到PNG页面之前几乎撕掉了我的头发。)< / p>

答案 5 :(得分:2)

在我搜索良好校验和算法的JavaScript实现时,我遇到了这个问题。 Andrzej Doyle 正确地选择了Adler32作为校验和,因为它确实易于实现并具有一些出色的属性。 DroidOS 然后在JavaScript中提供了一个实际的实现,它展示了简单性。

然而,该算法可以在维基百科页面中详细说明并在下面实现时进一步改进。诀窍是你不需要在每一步中确定模数。相反,你可以推迟到最后。这大大提高了实施速度,Chrome和Safari的速度提高了6倍。此外,这种优化不会影响代码的可读性,使其成为双赢。因此,它绝对符合原始问题,即具有计算上轻量级的算法/实现。

function adler32(data) {
  var MOD_ADLER = 65521;
  var a = 1, b = 0;

  var len = data.length;

  for (var i = 0; i < len; i++) {
    a += data.charCodeAt(i);
    b += a;
  }

  a %= MOD_ADLER;
  b %= MOD_ADLER;

  return (b << 16) | a;
}

编辑: imaya 创建了一个jsperf比较,一段时间后显示了运行简单版本时的速度差异,详见 DroidOS ,与推迟模运算的优化版本相比。我已将名称 全长 的上述实现添加到jsperf page,表明上述实现比中的实现速度快25% imaya 比简单实现(在Chrome 30上运行测试)快约570%:http://jsperf.com/adler-32-simple-vs-optimized/6

edit2:请不要忘记,在处理大型文件时,您最终会在a和b变量方面达到JavaScript实现的极限。因此,在使用大型数据源时,应执行中间模运算,以确保不超过可以可靠存储的整数的最大值。

答案 6 :(得分:1)

使用SHA-1 JS implementation。它并不像你想象的那么慢(Core 2 Duo 2.4Ghz上的Firefox 3.0每秒哈希值超过100KB)。

答案 7 :(得分:1)

这是一个我发明的相对简单的一个 - 它背后没有数学研究,但它非常快,并且在实践中有效。我还包括测试算法的Java等价物,并显示10,000,000失败的可能性不到1(运行需要一两分钟)。

的JavaScript

function getCrc(s) {
    var result = 0;
    for(var i = 0; i < s.length; i++) {
        var c = s.charCodeAt(i);
        result = (result << 1) ^ c;
    }
    return result;
}

爪哇

package test;

import java.util.*;

public class SimpleCrc {

    public static void main(String[] args) {
        final Random randomGenerator = new Random();
        int lastCrc = -1;
        int dupes = 0;
        for(int i = 0; i < 10000000; i++) {
            final StringBuilder sb = new StringBuilder();
            for(int j = 0; j < 1000; j++) {
                final char c = (char)(randomGenerator.nextInt(128 - 32) + 32);
                sb.append(c);
            }
            final int crc = crc(sb.toString());
            if(lastCrc == crc) {
                dupes++;
            }
            lastCrc = crc;
        }
        System.out.println("Dupes: " + dupes);
    }

    public static int crc(String string) {
        int result = 0;
        for(final char c : string.toCharArray()) {
            result = (result << 1) ^ c;
        }
        return result;
    }
}

答案 8 :(得分:0)

这是一个相当古老的线程,但我怀疑它仍然经常被观看 - 如果您只需要一段简短但可靠的代码来生成校验和,Adler32位算法必须是您的选择。这是JavaScript代码

function adler32(data)
{
 var MOD_ADLER = 65521;
 var a = 1, b = 0;

 for (var i = 0;i < data.length;i++) 
 {
  a = (a + data.charCodeAt(i)) % MOD_ADLER;
  b = (b + a) % MOD_ADLER;
 }

 var adler = a | (b << 16);
 return adler;
}

使用该算法的相应小提琴是here