Crypt-RIPEMD160
view release on metacpan or search on metacpan
t/03streaming.t view on Meta::CPAN
my @key_offsets = (0, 1, 55, 56, 63, 64, 65, 127, 128, 129, 191, 192, 199, 200);
for my $i (@key_offsets) {
for my $j (@key_offsets) {
next if $j < $i;
next if $j > length($msg) || $i > length($msg);
my $ctx = Crypt::RIPEMD160->new;
$ctx->add(substr($msg, 0, $i));
$ctx->add(substr($msg, $i, $j - $i));
$ctx->add(substr($msg, $j));
my $hex = unpack("H*", $ctx->digest);
is($hex, $expected, "three-way split at $i/$j");
}
}
};
# ========================================
# Padding boundary stress: 55 and 56 bytes
# ========================================
subtest 'padding boundary: 55 bytes in every chunk pattern' => sub {
my $msg = 'P' x 55;
my $expected = reference_hash($msg);
# Feed in chunks of 1..55
for my $chunk_size (1 .. 55) {
my $ctx = Crypt::RIPEMD160->new;
my $offset = 0;
while ($offset < length($msg)) {
my $end = $offset + $chunk_size;
$end = length($msg) if $end > length($msg);
$ctx->add(substr($msg, $offset, $end - $offset));
$offset = $end;
}
my $hex = unpack("H*", $ctx->digest);
is($hex, $expected, "55 bytes in chunks of $chunk_size");
}
};
subtest 'padding boundary: 56 bytes in every chunk pattern' => sub {
my $msg = 'P' x 56;
my $expected = reference_hash($msg);
for my $chunk_size (1 .. 56) {
my $ctx = Crypt::RIPEMD160->new;
my $offset = 0;
while ($offset < length($msg)) {
my $end = $offset + $chunk_size;
$end = length($msg) if $end > length($msg);
$ctx->add(substr($msg, $offset, $end - $offset));
$offset = $end;
}
my $hex = unpack("H*", $ctx->digest);
is($hex, $expected, "56 bytes in chunks of $chunk_size");
}
};
# ========================================
# Multi-argument add() streaming
# ========================================
subtest 'multi-arg add matches sequential add' => sub {
my $msg = 'X' x 200;
my $expected = reference_hash($msg);
# Split into 7 pieces at irregular intervals
my @pieces = map { substr($msg, $_ * 29, 29) } 0..5;
push @pieces, substr($msg, 174); # remaining 26 bytes
# Verify pieces reconstruct the message
is(join('', @pieces), $msg, 'pieces reconstruct message');
# All at once via multi-arg add
my $ctx1 = Crypt::RIPEMD160->new;
$ctx1->add(@pieces);
my $hex1 = unpack("H*", $ctx1->digest);
# Sequential add calls
my $ctx2 = Crypt::RIPEMD160->new;
$ctx2->add($_) for @pieces;
my $hex2 = unpack("H*", $ctx2->digest);
is($hex1, $expected, 'multi-arg add produces correct hash');
is($hex2, $expected, 'sequential add produces correct hash');
};
# ========================================
# MAC streaming consistency
# ========================================
subtest 'MAC streaming: same data different chunk sizes' => sub {
my $key = chr(0x0b) x 20;
my $data = "Hi There" x 10; # 80 bytes, crosses block boundary
# Reference: single add
my $mac_ref = Crypt::RIPEMD160::MAC->new($key);
$mac_ref->add($data);
my $expected = $mac_ref->hexmac;
# Byte-at-a-time
my $mac1 = Crypt::RIPEMD160::MAC->new($key);
$mac1->add(substr($data, $_, 1)) for 0 .. length($data) - 1;
is($mac1->hexmac, $expected, 'MAC byte-at-a-time matches');
# Chunks of 13 (prime, misaligns with block size)
my $mac2 = Crypt::RIPEMD160::MAC->new($key);
my $offset = 0;
while ($offset < length($data)) {
my $end = $offset + 13;
$end = length($data) if $end > length($data);
$mac2->add(substr($data, $offset, $end - $offset));
$offset = $end;
}
is($mac2->hexmac, $expected, 'MAC chunks of 13 matches');
# Split at block boundary (64 bytes)
my $mac3 = Crypt::RIPEMD160::MAC->new($key);
$mac3->add(substr($data, 0, 64));
$mac3->add(substr($data, 64));
is($mac3->hexmac, $expected, 'MAC split at block boundary matches');
};
# ========================================
# Clone mid-stream preserves consistency
# ========================================
subtest 'clone mid-stream then diverge' => sub {
my $prefix = 'A' x 70; # crosses one block boundary
my $suffix_a = 'B' x 50;
my $suffix_b = 'C' x 50;
my $expected_a = reference_hash($prefix . $suffix_a);
my $expected_b = reference_hash($prefix . $suffix_b);
my $ctx = Crypt::RIPEMD160->new;
$ctx->add($prefix);
my $clone = $ctx->clone;
$ctx->add($suffix_a);
$clone->add($suffix_b);
is(unpack("H*", $ctx->digest), $expected_a, 'original path correct');
is(unpack("H*", $clone->digest), $expected_b, 'cloned path correct');
};
subtest 'clone at every offset of a message' => sub {
my $msg = join('', map { chr($_ & 0xFF) } 0..99);
my $expected = reference_hash($msg);
for my $split (0, 1, 31, 32, 33, 55, 56, 63, 64, 65, 99) {
( run in 0.330 second using v1.01-cache-2.11-cpan-140bd7fdf52 )