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

    (.doFinal mac out 0)
    out))

(declare make-poly1305)

(defn- verify-poly1305-impl
  [data signature pkey]
  (let [sig (make-poly1305 data pkey)]
    (Arrays/equals sig signature)))

(defprotocol Poly1305Mac

different types.
It comes with default implementation for: string,
bytes, input stream, file, url and uri."
  (make-poly1305 [obj key iv enginefactory] "Calculate poly1305 mac for type."))

(alter-meta! #'make-poly1305 assoc :no-doc true :private true)

(extend-protocol Poly1305Mac
  (Class/forName "[B")
  (make-poly1305 [^bytes data ^bytes key ^bytes iv ^IFn enginefactory]
    (make-poly1305-plain-impl data key iv enginefactory))

  java.lang.String
  (make-poly1305 [^String data ^bytes key ^bytes iv ^IFn enginefactory]
    (make-poly1305-plain-impl (->byte-array data) key iv enginefactory))

  java.io.InputStream
  (make-poly1305 [^java.io.InputStream data ^bytes key ^bytes iv ^IFn enginefactory]
    (make-poly1305-stream-impl data key iv enginefactory))

  java.io.File
  (make-poly1305 [^java.io.File data ^bytes key ^bytes iv ^IFn enginefactory]
    (make-poly1305-stream-impl (io/input-stream data) key iv enginefactory))

  java.net.URL
  (make-poly1305 [^java.net.URL data ^bytes key ^bytes iv ^IFn enginefactory]
    (make-poly1305-stream-impl (io/input-stream data) key iv enginefactory))

  java.net.URI
  (make-poly1305 [^java.net.URI data ^bytes key ^bytes iv ^IFn enginefactory]
    (make-poly1305-stream-impl (io/input-stream data) key iv enginefactory)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; High level interface
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defn poly1305
  "Make poly1305 mac for specified data, using arbitrary
length key and 128 bits iv.
Key can be any type that implements ByteArray protocol."
  [data key ^bytes iv engine]
  {:pre [(= (count iv) 16)]}
  (let [key (->byte-array key)
        ef  (resolve-engine-factory engine)]
    (make-poly1305 data key iv ef)))

(defn poly1305-verify
  "Verify poly1305 mac for specified data and signature."
  [data ^bytes signature pkey ^bytes iv engine]
  {:pre [(= (count iv) 16)]}
  (let [key (->byte-array pkey)
        ef  (resolve-engine-factory engine)]
    (verify-poly1305-impl data signature key iv ef)))

(def ^{:doc "Alias for Poly1305 + AES mac."}
  poly1305-aes #(poly1305 %1 %2 %3 :aes))

(def ^{:doc "Alias for Poly1305 + AES mac verify function."}
  poly1305-aes-verify #(poly1305-verify %1 %2 %3 %4 :aes))

(def ^{:doc "Alias for Poly1305 + Twofish mac."}
  poly1305-twofish #(poly1305 %1 %2 %3 :twofish))

(def ^{:doc "Alias for Poly1305 + Twofish mac verify function."}
  poly1305-twofish-verify #(poly1305-verify %1 %2 %3 %4 :twofish))

(def ^{:doc "Alias for Poly1305 + Serpent mac."}
  poly1305-serpent #(poly1305 %1 %2 %3 :serpent))

(def ^{:doc "Alias for Poly1305 + Serpent mac verify function."}
  poly1305-serpent-verify #(poly1305-verify %1 %2 %3 %4 :serpent))
