     (.doFinal mac out 0)
     out))
 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Low level interface
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
 (declare make-poly1305)
 
-(defn- verify-poly1305-impl
-  [data signature pkey]
-  (let [sig (make-poly1305 data pkey)]
+(defn verify-poly1305-impl
+  "Generic implementation of verify."
+  [data ^bytes signature ^bytes pkey ^bytes iv ^IFn enginefactory]
+  (let [sig (make-poly1305 data pkey iv enginefactory)]
     (Arrays/equals sig signature)))
 
 (defprotocol Poly1305Mac

    out))

(defn- make-poly1305-stream-impl
  [stream pkey]
  (let [bkey (key->bytes pkey)
        iv   (key->iv pkey)
        mac  (Poly1305. (AESFastEngine.))
        out  (byte-array 16)
        kp   (KeyParameter. bkey)
        pwi  (ParametersWithIV. kp iv)
        bfr  (byte-array 5120)]
    (.init mac pwi)

           org.bouncycastle.crypto.params.KeyParameter
           org.bouncycastle.crypto.params.ParametersWithIV
           org.bouncycastle.crypto.engines.AESFastEngine
           org.bouncycastle.crypto.engines.SerpentEngine
           org.bouncycastle.crypto.engines.TwofishEngine
           clojure.lang.IFn
           clojure.lang.Keyword
           buddy.Arrays)
  (:require [buddy.core.hash :refer [sha3-256]]
            [buddy.core.codecs :refer :all]
            [buddy.core.keys :refer [make-random-bytes]]
            [clojure.java.io :as io]))

(def ^{:doc "Default engine factories."
       :dynamic true}
  *available-engines* {:aes     #(AESFastEngine.)
                       :serpent #(SerpentEngine.)
                       :twofish #(TwofishEngine.)})

(defn- resolve-engine-factory
  "Given dynamic type engine, try resolve it to
valid engine factory. By default accepts keywords
and functions."
  [engine]
  (cond
   (instance? Keyword engine) (engine *available-engines*)
   (instance? IFn engine) engine))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Internal implementations
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defn- key->poly1305key
  "Noramalizes any length byte array key to poly1305
formatted byte array key.
It uses sha3 (256 bit) for normalize the size to 32
bytes and poly1305 algorithm for transform it."
  [^bytes key]
  (let [bkey (sha3-256 key)]
    (Poly1305KeyGenerator/clamp bkey)
    bkey))

(defn- make-poly1305-plain-impl
  [^bytes data ^bytes pkey ^bytes iv ^IFn enginefactory]
  (let [mac (Poly1305. (enginefactory))
        out (byte-array 16)
        kp  (KeyParameter. (key->poly1305key pkey))
        pwi (ParametersWithIV. kp iv)]
    (doto mac
      (.init pwi)
      (.update data 0 (count data))
