Adler32算法
2018-09-05 16:33:11 阿炯

本站赞助商链接,请多关照。 Adler-32是Mark Adler发明的校验和算法,和32位CRC校验算法一样,都是保护数据防止意外更改的算法,但是这个算法较容易被伪造,所以是不安全的保护措施。但是比CRC好点的是,它计算的很快。这个算法那是从Fletcher校验和算法中修改过来的,原始的算法形式略快,但是可依赖性并不高。


Adler-32已经在很多地方替代了CRC-32,比如Zip,宣称跟CRC-32一样可靠而且速度快很多,速度快是可以说得过去,不过使用余式表的CRC-32速度也慢不到哪里去,而重要的是可靠性。


Adler-32的一种滚动哈希版本被用在了rsync工具中。该算法通过求解两个16位的数值A、B实现,并将结果连结成一个32位整数。

A就是字符串中每个字节的和,而B是A在相加时每一步的阶段值之和。在Adler-32开始运行时,A初始化为1,B初始化为0,最后的校验和要模上65521(继216之后的最小素数)。

A = 1 + D1 + D2 + ... + Dn (mod 65521)
B = (1 + D1) + (1 + D1 + D2) + ... + (1 + D1 + D2 + ... + Dn) (mod 65521)
   = n×D1 + (n-1)×D2 + (n-2)×D3 + ... + Dn + n (mod 65521)
Adler-32(D) = B × 65536 + A

其中D为字符串的字节,n是D的字节长度。

参考来源:

Adler-32



在Perl下与自带的CRC(核心)模块相比,确实有一个数量级是提升(在对一个118k的文件的计算上)。

use v5.20;
use Data::Dumper;
use Time::HiRes qw(time sleep);
use Digest::file qw(digest_file_hex);

my ($st,$f1)=(time(),'ps.log');
my $cs_hex = digest_file_hex($f1, "CRC-32");

END{
    say "Crc32 of File:$f1:$cs_hex";
    say 'Time Used(s):',(time()-$st);
}

Crc32 of File:ps.log:a78fb4b8
Time Used(s):0.002184

-------------------------------
use v5.20;
use Data::Dumper;
use Time::HiRes qw(time sleep);
use Crypt::Checksum::Adler32 ':all';

my ($st,$f1)=(time(),'ps.log');
my $cs_hex = adler32_file_hex($f1);

END{
    say "Adler32 of File:$f1:$cs_hex";
    say 'Time Used(s):',(time()-$st);
}

Adler32 of File:ps.log:c2a857b4
Time Used(s):0.000453

两者计算的结果不一要,在用7z的crc32算法计算结果与Digest的相同。。。

对一个52M的zstd压缩文件的校验

AdlerCrc32 of File:otp-21.2.compiled.zst:d6e50d1b
Time Used(s):0.076895

DigestCrc32 of File:otp-21.2.compiled.zst:877e5c48
Time Used(s):0.273890

相比起来,Adler还是有相当的优势的,来看看Crypt::Checksum::CRC32模块的时间性能:
use v5.20;
use Data::Dumper;
use Time::HiRes qw(time sleep);
use Crypt::Checksum::CRC32 ':all';

my ($st,$f1)=(time(),'otp-21.2.compiled.zst');
my $cs_hex = crc32_file_hex($f1);

END{
    say "CryptCrc32 of File:$f1:$cs_hex";
    say 'Time Used(s):',(time()-$st);
}

CryptCrc32 of File:otp-21.2.compiled.zst:877e5c48
Time Used(s):0.235591

文件的结果与核心模块的结果相同,但用时仅比其略少。

通过Digest模块与Compress::Zlib来计算文件的Adler32校验码的Perl代码片段(部分的Digest子模块可能要另行安装)。

-------------------------------
use v5.20;
use IO::File;
use Time::HiRes qw(time);
use Digest::Adler32;

my ($st,$f1)=(time(),'freeoa.log');
my $fh = IO::File->new('freeoa.log');
my $a32 = Digest::Adler32->new;

$a32->addfile($fh);

# get file digest
print "Adler32:", $a32->hexdigest, "\n";

END{
    $fh->close;
    say 'Time Used(s):',(time()-$st);
}

-------------------------------
use v5.20;
use IO::File;
use Compress::Zlib;
use Time::HiRes qw(time);
use constant BUFSIZE=>128;

sub chksum{
    my $fhd = shift;
    binmode($fhd);
    sysseek($fhd,0,0); #rewind
    my ($crc,$buffer)=();
    while($fhd->sysread($buffer,BUFSIZE)){
        #$crc=crc32($buffer,$crc);
        #$crc=Compress::Zlib::crc32($buffer,$crc);
        $crc=adler32($buffer,$crc);
        #$crc=Compress::Zlib::adler32($buffer,$crc);
    }
    return sprintf("%x",$crc);
}

my ($st)=(time());
my $fh = IO::File->new('freeoa.log');
say chksum($fh);

END{
    undef $fh;
    say 'Time Used(s):',(time()-$st);
}