Created
February 17, 2014 03:27
-
-
Save favila/9044218 to your computer and use it in GitHub Desktop.
Generate version 5 (sha1-based) uuids in clojure.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns breeze.util.uuid | |
"Utilities for generating version 5 (SHA-1 hashing) uuids. | |
This implementation should conform to RFC 4122, section 4.3. | |
Includes shortcuts for generating uuids for breeze rule hashes." | |
(import java.security.MessageDigest | |
java.util.UUID | |
java.nio.ByteBuffer | |
java.nio.charset.StandardCharsets)) | |
(def rule-namespace-uuid | |
"Namespace uuid for breeze rule-entity hashes." | |
#uuid "be6e7e44-d49f-4eab-a12c-04d6f1608384") | |
;; The following namespace uuids are from RFC 4122 Appendix C. | |
(def dns-namespace-uuid #uuid "6ba7b810-9dad-11d1-80b4-00c04fd430c8") | |
(def url-namespace-uuid #uuid "6ba7b811-9dad-11d1-80b4-00c04fd430c8") | |
(def oid-namespace-uuid #uuid "6ba7b812-9dad-11d1-80b4-00c04fd430c8") | |
(def x500-namespace-uuid #uuid "6ba7b814-9dad-11d1-80b4-00c04fd430c8") | |
(defn messagedigest-sha1 [] (MessageDigest/getInstance "SHA-1")) | |
(defn putUUID [^ByteBuffer bb ^UUID uuid] | |
(doto bb | |
(.putLong (.getMostSignificantBits uuid)) | |
(.putLong (.getLeastSignificantBits uuid)))) | |
(defprotocol Bytes | |
(as-bytes [o] o)) | |
(extend-protocol Bytes | |
(Class/forName "[B") ;; primitive byte array | |
(as-bytes [o] o) | |
java.nio.ByteBuffer | |
(as-bytes [o] (.array o)) | |
java.util.UUID | |
(as-bytes [o] (-> (ByteBuffer/wrap (byte-array 16)) | |
(putUUID o) | |
(.array))) | |
java.lang.String | |
(as-bytes [o] (.getBytes o StandardCharsets/UTF_8))) | |
(def rule-namespace-uuid-bytes (as-bytes rule-namespace-uuid)) | |
(defn sha1-bytes [namespace-uuid name] | |
(let [md (messagedigest-sha1)] | |
(.update md (as-bytes namespace-uuid)) | |
(.digest md (as-bytes name)))) | |
(defn sha1->v5uuid | |
"Return a version 5 (name-based) uuid from sha1 hash byte-array. | |
The sha1 hash should already have the namespace uuid and the name bytes | |
hashed into it. The uuid will use 122 bits of entropy from the sha1 hash." | |
[^bytes sha1] | |
(let [bb (ByteBuffer/wrap sha1 0 16) | |
;; set bits 12-15 to 5 (version number for sha1 name-based uuid) | |
msb (-> (.getLong bb) | |
(bit-and-not 0xa000) | |
(bit-or 0x5000)) | |
;; set highest 2 bits to 0b10 (variant bits for RFC 4122 UUID) | |
lsb (-> (.getLong bb) | |
(bit-and-not 0x4000000000000000) | |
(bit-or Long/MIN_VALUE))] | |
(UUID. msb lsb))) | |
(defn sha1-name-uuid | |
"Return a sha1 name-based uuid (version 5) from a namespace uuid and a name. | |
Either argument can be anything coercible to byte-arrays" | |
[namespace-uuid name] | |
(sha1->v5uuid (sha1-bytes namespace-uuid name))) | |
(defn rule-uuid | |
"Return a uuid for an *unhashed* breeze rule-entity canonical string | |
representation." | |
[canonical-rule-str] | |
(sha1-name-uuid rule-namespace-uuid-bytes canonical-rule-str)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment