Perl-only CRC32 function (without C code)

This post was written by eli on May 19, 2011
Posted Under: perl,Software

It may look like a stupid idea, since the CRC32 has been implemented in some Perl modules which can be downloaded from CPAN. But all functions I found involve an XS part, which essentially means that a compilation of C code has to take place during the installation.

In other words, these modules can’t be just attached to a bundle of Perl code, but they have to be installed on a machine where it’s permitted. Or at least, compilation capabilities are necessary. Which can turn into a mess if the target is a Windows-running computer barely having Perl installed.

So I adapted one of the implementations of the mostly used CRC32 calculation, and wrote it in pure Perl. It’s really not the efficient way to obtain a CRC, and I wouldn’t try it on long sequences. Its advantage is also its disadvantage: It’s all in Perl.

Before giving the function away, I’d just point out that if one tries the following snippet

#!/usr/bin/perl

use warnings;
use strict;
require String::CRC32;
require Digest::CRC;

my $str = "This is just any string.";

my $refcrc = String::CRC32::crc32($str);
my $refcrc2 = Digest::CRC::crc32($str);
my $mycrc = mycrc32($str);

then $refcrc, $refcrc2 and $mycrc will have the same value (the last of which is calculated by the function at the end of this post).

And if we’re at it, I’d also point out that for any string $str, the following code

my $append = mycrc32($str) ^ 0xffffffff;
my $res = mycrc32($str.pack("V", $append));

yields a CRC in $res which equals Oxffffffff. This is a well-known trick with CRCs: Append the CRC to the string for which it was calculated, and get a fixed value. And by they way, the CRC is done in Little Endian setting, so the parallel Linux kernel operation would be crc32_le(~0, string, len), only that crc32_le returns the value XORed by Oxffffffff (or is it the Perl version being upside down? I don’t know). Also note that the initial value of the CRC is set to ~0, which is effectively Oxffffffff again.

OK, time to show the function. It’s released to the public domain (Creative Commons’ CC0, if you like), so feel free to make any use of it.

sub mycrc32 {
 my ($input, $init_value, $polynomial) = @_;

 $init_value = 0 unless (defined $init_value);
 $polynomial = 0xedb88320 unless (defined $polynomial);

 my @lookup_table;

 for (my $i=0; $i<256; $i++) {
   my $x = $i;
   for (my $j=0; $j<8; $j++) {
     if ($x & 1) {
       $x = ($x >> 1) ^ $polynomial;
     } else {
       $x = $x >> 1;
     }
   }
   push @lookup_table, $x;
 }

 my $crc = $init_value ^ 0xffffffff;

 foreach my $x (unpack ('C*', $input)) {
   $crc = (($crc >> 8) & 0xffffff) ^ $lookup_table[ ($crc ^ $x) & 0xff ];
 }

 $crc = $crc ^ 0xffffffff;

 return $crc;
}

Reader Comments

Thanks!!!

#1 
Written By denis on May 2nd, 2013 @ 14:22

Works perfectly, thank you.

#2 
Written By John on May 26th, 2016 @ 20:37

Thank you, this works perfectly!

#3 
Written By siaip on October 27th, 2016 @ 04:58

Works great, very concise – thanks!

#4 
Written By Chris on August 25th, 2017 @ 20:27

Thanks. Could you add a crc64 version please? :)

#5 
Written By Florian on March 30th, 2020 @ 19:16

Add a Comment

required, use real name
required, will not be published
optional, your blog address