Skip to content

Instantly share code, notes, and snippets.

@pthatcher
Created February 23, 2010 02:43
Show Gist options
  • Save pthatcher/311790 to your computer and use it in GitHub Desktop.
Save pthatcher/311790 to your computer and use it in GitHub Desktop.
;; the goal is to hash a seq of bytes, like ["ABC", "XYZ"].
;; Ultimately, you'd probably get the seq from a FileReader.
;;
;; the java libraries are, of course, mutable, with a
;; MessageDigest object on which you call .update(bytes)
;; until you are done, when you call .digest().
;; I typically implement the loop using reduce,
;; but using reduce for mutating feels a little dirty.
;; So, I thought I would try cells.
;;
;; I like the result, and I ended up generalizing it
;; a bit with an "Updateable" protocol. That might be
;; handy in other "update, update, update, finish" scenarios.
;;
;; By the way, so far defprotocol/deftype seem pretty awesome.
(import [java.security MessageDigest])
(def *sha1* "SHA-1")
(def *abc* (.getBytes "ABC"))
(def *abc-sha1* "3c1bdbb26f358bab27f267924aa2c9a3fcfdb8")
(defn start-message-digest [type]
(MessageDigest/getInstance type))
(defn update-message-digest [#^MessageDigest md bytes]
(.update md (as-bytes bytes))
md)
(defn as-hex [bytes]
(apply str (for [byte bytes] (format "%x" byte))))
(defn hash-simple [type bytes-seq]
(as-hex (.digest (reduce update-message-digest (start-message-digest type) bytes-seq))))
(assert (= *abc-sha1* (hash-simple *sha1* [*abc*])))
(extend-class java.security.MessageDigest$Delegate
Editable
(transient-of [message-digest _]
message-digest)
Transient
(value-of [message-digest]
(.digest message-digest)))
(defn hash-cell [type bytes-seq]
(let [mdc (cell (start-sha1))]
(doseq [bytes bytes-seq]
(>> update-message-digest mdc bytes))
(as-hex @mdc)))
(assert (= *abc-sha1* (hash-cell *sha1* [*abc*])))
(defprotocol Updateable
(update [updatable val]))
(extend-class java.security.MessageDigest$Delegate
Updateable
(update [md bytes]
(.update md bytes)
md))
(defn update-with-seq [updateable vals]
(doseq [val vals]
(update updateable val))
updateable)
(defn update-cell [c s]
(>> update-with-seq c s)
c)
(defn hash-cell-updateable [type bytes-seq]
(let [mdc (cell (start-message-digest type))]
; do stuff in other thread at the same time and always see safe snapshots
(as-hex (deref (update-cell mdc bytes-seq)))))
(assert (= *abc-sha1* (hash-cell-updateable *sha1* [*abc*])))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment