#! perl -slw use strict; use Math::Random::MT qw[ rand srand ]; use String::CRC32; use GD; $|++; my %map = ( 255 => sub{ return ( 0, 0, $_[0] * 255 ) }, 510 => sub{ return ( 0, $_[0]*255, 255 ) }, 765 => sub{ return ( 0, 255, (1-$_[0])*255 ) }, 1020 => sub{ return ( $_[0]*255, 255, 0 ) }, 1275 => sub{ return ( 255, (1-$_[0])*255, 0 ) }, 1530 => sub{ return ( 255, 0, $_[0]*255 ) }, 1785 => sub{ return ( 255, $_[0]*255, 255 ) }, ); my @map = sort{ $a <=> $b } keys %map; sub colorRamp1785 { my( $v, $vmin, $vmax ) = @_; $v = $vmax if $v > $vmax; $v = $vmin if $v < $vmin; $v = ( $v - $vmin ) / ( $vmax - $vmin ); ( $v * 1785 ) < $_ and return rgb2n( $map{ $_ }->( $v ) ) for @map; } our $SRAND; srand( $SRAND ) if $SRAND; our $TRIALS ||= 1e3; my $HALF = $TRIALS / 2; our $RANGE ||= $TRIALS /4; our $MAP ||= 'C'; my $colorRamp = $MAP eq 'BW' ? \&colorRampBW : $MAP eq 'C' ? \&colorRamp1020 : $MAP eq 'CE' ? \&colorRamp1785 : die "-MAP= [BW|C|CE]\n"; my @crcChanges = map [ (0) x 32 ], 1 .. 128; my @xorChanges = map [ (0) x 16 ], 1 .. 128; for ( 0 .. $TRIALS ) { printf "\r$_\t" unless $_ % ($TRIALS/10); ## Pick a random message; my $message = pack 'V4', map rand( 2**32 ), 1 .. 4; ## Calculate reference CRC ## my $CRC = crc32( $message ); my $CRC = pack 'V', crc32( $message ); ## XOR-fold the reference my $XOR = substr( $CRC, 0, 4 ) ^ substr( $CRC, 4, 4 ); for my $bit ( 0 .. 127 ) { my $copy = $message; ## toggle this bit in the message vec( $copy, $bit, 1 ) ^= 1; ## Calculate new CRC ## my $newCRC = crc32( $copy ); my $newCRC = pack 'V', crc32( $copy ); ## Isolate the bits that changed my $changed = $CRC ^ $newCRC; ## Accumulate the changes vec( $changed, $_, 1 ) and ++$crcChanges[ $bit ][ $_ ] for 0 .. 31; ## XOR-fold the new md5 my $newXOR = substr( $newCRC, 0, 4 ) ^ substr( $newCRC, 4, 4 ); ## Isolate the changes $changed = $XOR ^ $newXOR; ## And accumulate them vec( $changed, $_, 1 ) and ++$xorChanges[ $bit ][ $_ ] for 0 .. 15; } } print "\n"; my $img = GD::Image->new( 51, 130, 1 ); $img->filledRectangle( 0, 0, 51, 130, rgb2n( (128) x 3 ) ); my @maxmins = ( 2**32, 0 )x 2; for my $inBit ( 0 .. 127 ) { for my $outBit ( 0 .. 31 ) { my $chi = $crcChanges[ $inBit ][ $outBit ] - $HALF; $chi = $chi**2 * ( $chi <=> 0 ); $chi /= $TRIALS; $maxmins[ 0 ] = $chi if $maxmins[ 0 ] > $chi; $maxmins[ 1 ] = $chi if $maxmins[ 1 ] < $chi; $img->setPixel( $outBit+1, $inBit+1, $colorRamp->( $chi, -$RANGE, $RANGE ) ); next if $outBit > 15; $chi = $xorChanges[ $inBit ][ $outBit ] - $HALF; $chi = $chi**2 * ( $chi <=> 0 ); $chi /= $TRIALS; $maxmins[ 2 ] = $chi if $maxmins[ 2 ] > $chi; $maxmins[ 3 ] = $chi if $maxmins[ 3 ] < $chi; $img->setPixel( $outBit+34, $inBit+1, $colorRamp->( $chi, -$RANGE, $RANGE ) ); } } print "$RANGE : @maxmins"; my $fname = "crc32Xor.$MAP.png"; open PNG, '>:raw', $fname or die $!; print PNG $img->png; close PNG; system 1, $fname; sub rgb2n{ unpack 'N', pack 'CCCC', 0, @_ } sub colorRampBW { my( $v, $vmin, $vmax ) = @_; $v = $vmax if $v > $vmax; $v = $vmin if $v < $vmin; $v -= $vmin; $v /= $vmax - $vmin; $v *= 255; return rgb2n( ( $v ) x 3 ); } sub colorRamp1020 { my( $v, $vmin, $vmax ) = @_; my( $r, $g, $b ) = (1) x 3; $v = $vmax if $v > $vmax; $v = $vmin if $v < $vmin; ## $v = $vmax + $vmin - $v; my $dv = $vmax - $vmin; if( $v < ( $vmin + 0.25*$dv ) ) { $r = 0; $g = 4 * ($v - $vmin) / $dv; } elsif( $v < ( $vmin + 0.5 * $dv ) ) { $r = 0; $b = 1 + 4 * ($vmin + 0.25 * $dv - $v) / $dv; } elsif( $v < ( $vmin + 0.75 * $dv ) ) { $r = 4 * ($v - $vmin - 0.5 * $dv) / $dv; $b = 0; } else { $g = 1 + 4 * ($vmin + 0.75 * $dv - $v) / $dv; $b = 0; } return rgb2n( map int( $_ * 255), $r, $g, $b ); }