Now that the lower-level plumbing is in place, we can look at an example of making a C HMAC function callable from Clojurescript. It involves three parts: First, how to wrap Emscripten-compiled functions in something callable from Javascript; second, how to properly handle the heap; and, third, how to wrap the Javascript function in something more Clojurescript friendly.

(def type->string {:pointer "number" :byte "number" :int "number" :long ["number" "number"] :void nil}) (defn cwrap [fn-name ret-type signatures] (.cwrap js/Module fn-name (type->string ret-type) (clj->js (flatten (map type->string signatures)))))))

Above is nothing more than a simple wrapper for Module.cwrap(name, ret_type, arg_types), the mechanism for making functions callable from Javascript. We elected to make a map for translating data-types into the Emscripten representation, just because it is more explicit and easier for comparison against, say, a C header file. You'll notice that "long" is a vector. This is because Emscripten represents 64-bit integers as two numbers, since, 253 is the largest representable integer in Javascript.

(def emscripten-heap (.-HEAPU8 js/Module)) (defn heap-subarray [address sz] (.subarray emscripten-heap address (+ address sz))) (defn array-clone [a] (doto (js/Uint8Array. (.-length a)) (.set a))) (defn heap->uint8array [address sz] (array-clone (heap-subarray address sz))) (defn uint8array->heap! [uint8-buffer] (let [n (.-length uint8-buffer) buffer (malloc! n)] (.set (heap-subarray buffer n) uint8-buffer) buffer))

Manipulating data inside Emscripten requires copying data in and out of its own heap. We used the above methods for bringing Uint8Array back and forth.

For data being passed into the heap, the method is as follows: After malloc'ing space, a slice of the whole HEAPU8 is set.

In order to take data out of Emscripten, data is copied out of the heap, back into a regular Uint8Array, by representing the "memory address" and range as a slice of HEAPU8, and copying it into a new buffer. The cloned array is returned, and the allocation of Emscripten heap is free'd upon returning.

Our goal was to make sure this copying back and forth was negligible with respect to the amount of work being done in Emscripten-space.

(def skein-block-bytes 128) (def hmac-init (let [hmac-impl (cwrap "skein_hmac_init" :void [:pointer :pointer :int])] (fn [key] (with-heap [context (malloc! context-bytes) key-heap (uint8array->heap! key)] (hmac-impl context key-heap (.-length key)) (heap->uint8array context context-bytes))))) (def hash-update (let [hash-impl (cwrap "skein_hash_update" :void [:pointer :pointer :int])] (fn [context message] (with-heap [context-heap (uint8array->heap! context) message-heap (uint8array->heap! message)] (hash-impl context-heap message-heap (.-length message)) (.set context (heap-subarray context-heap context-bytes)))))) (def hash-final (let [hash-impl (cwrap "skein_hash_final" :void [:pointer :pointer])] (fn [context] (with-heap [context (uint8array->heap! context) output (malloc! skein-block-bytes)] (hash-impl context output) (heap->uint8array output skein-block-bytes)))))

And, now, the payoff: We can generate the HMAC for a given message! About time, if you ask me.