1 ! Copyright (C) 2009 Diego Martinelli.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors calendar checksums checksums.openssl classes.tuple
4 formatting fry io.encodings.ascii io.encodings.string kernel math
5 math.functions math.parser math.ranges present random sequences
9 ! Hashcash implementation
10 ! Reference materials listed below:
13 ! http://en.wikipedia.org/wiki/Hashcash
14 ! http://www.ibm.com/developerworks/linux/library/l-hashcash.html?ca=dgr-lnxw01HashCash
16 ! And the reference implementation (in python):
17 ! http://www.gnosis.cx/download/gnosis/util/hashcash.py
21 ! Return a string with today's date in the form YYMMDD
23 now "%y%m%d" strftime ;
25 ! Random salt is formed by ascii characters
27 : available-chars ( -- seq )
28 33 126 [a,b] [ CHAR: : = ] reject ;
32 ! Generate a 'length' long random salt
33 : salt ( length -- salted )
34 available-chars '[ _ random ] "" replicate-as ;
36 TUPLE: hashcash version bits date resource ext salt suffix ;
38 : <hashcash> ( -- tuple )
46 tuple-slots [ present ] map ":" join ;
50 : sha1-checksum ( str -- bytes )
51 ascii encode openssl-sha1 checksum-bytes ; inline
53 : set-suffix ( tuple guess -- tuple )
56 : get-bits ( bytes -- str )
57 [ >bin 8 CHAR: 0 pad-head ] { } map-as concat ;
59 : checksummed-bits ( tuple -- relevant-bits )
60 dup string>> sha1-checksum
61 swap bits>> 8 / ceiling head get-bits ;
63 : all-char-zero? ( seq -- ? )
64 [ CHAR: 0 = ] all? ; inline
66 : valid-guess? ( checksum tuple -- ? )
67 bits>> head all-char-zero? ;
69 : (mint) ( tuple counter -- tuple )
70 2dup set-suffix checksummed-bits pick
71 valid-guess? [ drop ] [ 1 + (mint) ] if ;
75 : mint* ( tuple -- stamp )
78 : mint ( resource -- stamp )
83 ! One might wanna add check based on the date,
84 ! passing a 'good-until' duration param
85 : check-stamp ( stamp -- ? )
86 dup ":" split [ sha1-checksum get-bits ] dip
87 second string>number head all-char-zero? ;