source: trunk/abcl/tools/digest.lisp @ 13329

Last change on this file since 13329 was 13329, checked in by Mark Evenson, 10 years ago

Fast SHA-{1,256,512} cryptographic hashes for files.

Includes the start of a benchmark that seems to show that using NIO
direcly without involving Lisp streams works a couple orders of
magnitude faster. A definite point of optimization would be to have a
java.nio.ByteBuffer? backed Stream that could be used as source and/or
a sync for fast io via FileChannel?.

File size: 2.5 KB
Line 
1(defvar *digest-types* 
2  '((:sha-1 . "SHA-1")
3    (:sha-256 . "SHA-256")
4    (:sha-512 . "SHA-512")))
5
6(defconstant +byte-buffer-rewind+ 
7  (jmethod "java.nio.ByteBuffer" "rewind"))
8(defconstant +byte-buffer-get+ 
9  (jmethod "java.nio.ByteBuffer" "get" "[B" "int" "int"))
10(defconstant +digest-update+ 
11  (jmethod "java.security.MessageDigest" "update" "[B" "int" "int"))
12
13;;;  needs ABCL svn > r13328 and is probably not faster than the NIO version
14
15(defun digest-file-1 (path &key (digest :sha-256))
16 (let* ((digest-type (cdr (assoc digest *digest-types*)))
17        (digest (jstatic "getInstance" "java.security.MessageDigest" digest-type))
18        (buffer (make-array 8192 :element-type '(unsigned-byte 8))))
19   (with-open-file (input path :element-type '(unsigned-byte 8))
20     (loop :for bytes = (read-sequence buffer input)
21        :while (plusp bytes)
22        :do 
23        (jcall-raw "update" digest 
24                   (jnew-array-from-array "byte" buffer) 0 bytes))
25     (jcall "digest" digest))))
26
27(defun digest-file (path &key (digest :sha-256))
28 (let* ((digest-type (cdr (assoc digest *digest-types*)))
29        (digest (jstatic "getInstance" "java.security.MessageDigest" digest-type))
30        (namestring (if (pathnamep path) (namestring path) path))
31        (file-input-stream (jnew "java.io.FileInputStream" namestring))
32        (channel (jcall "getChannel" file-input-stream))
33        (length 8192)
34        (buffer (jstatic "allocateDirect" "java.nio.ByteBuffer" length))
35        (array (jnew-array "byte" length)))
36   (do ((read (jcall "read" channel buffer)
37              (jcall "read" channel buffer)))
38       ((not (> read 0)))
39     (jcall +byte-buffer-rewind+ buffer)
40     (jcall +byte-buffer-get+ buffer array 0 read)
41     (jcall +byte-buffer-rewind+ buffer)
42     (jcall +digest-update+ digest array 0 read))
43   (jcall "digest" digest)))
44
45(defun ascii-digest (digest)
46  (format nil "~{~X~}"
47          (mapcar (lambda (b) (if (< b 0) (+ 256 b) b))
48                  (java::list-from-jarray digest))))
49
50(defun benchmark (directory)
51    (let (results start-1 end-1 start-2 end-2)
52      (dolist (entry (directory directory))
53        (setf start-1 (get-internal-run-time))
54        (digest-file-1 entry)
55        (setf end-1 (get-internal-run-time))
56        (setf start-2 (get-internal-run-time))
57        (digest-file entry)
58        (setf end-2 (get-internal-run-time))
59        (let ((result (list entry (- end-1 start-1) (- end-2 start-2))))
60          (format t "~&~A" result)
61          (push result results)))
62      results))
63   
64       
65
66
67   
68
Note: See TracBrowser for help on using the repository browser.