package Hashcash;
# use strict;
use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION);
use Exporter;

$VESRION = 1.00;
@ISA = qw(Exporter);
@EXPORT = qw(charge pay check);

use Digest::SHA1 qw(sha1);
use constant RANDOMDEV => "/dev/urandom";
use constant PREFIXLENGTH => 20;


# pay brute-forces SHA1 to find an input that hashes
# to something partially matching a given string. Idea by
# Adam Back.
# This function expects an arbitrary prefix and a bit-string of
# significantly less than 160 bits. Both conditions (being a bit-string
# and much less than 160 bits in length) should be checked by the caller.
#
sub pay {
        my ( $prefix, $bits)  = @_;
        my ($h, $i)  = ("", 0);
        while ($h !~ m/$bits$/){
                $h = unpack "b*", sha1("$prefix" . ++$i);
        }
        return $i;
}

# charge takes a number n and returns
# a pair of strings, a prefix (length defined in 
# PREFIXLENGTH) and a challenge of n bits.
#
sub charge  {
        my ( $n) = shift;
        my ($prefix, $chall);
        my $pat = "H" . PREFIXLENGTH;
        my $rpat = "b" . $n;
        open RAND, RANDOMDEV or die "Couldn't open random device";
        $chall  = unpack $rpat, <RAND>;
		if (length $chall < $n) {
			die "Mist!";
		}
        $prefix = unpack $pat , <RAND>;
        close RAND;
        return ($prefix, $chall);
}

# check takes three parameters, a (prefix,challenge) pair
# and one response to the challenge. It checks if
# prefix . response hashes to something matching challenge.
#
sub check {
        my ( $prefix, $chall, $claim) = @_;
		my $cl = length($chall);
        my $temp = unpack "b*", sha1($prefix . $claim);
        return ($temp =~ m/$chall$/);
}

1;
