    (instance? IFn engine) (engine)
    (instance? BlockCipher engine) engine))
 
-(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."
+(defn- key->polykey
+  "Noramalizes 32 bytes array key to poly1305
+  formatted byte array key."
   [^bytes key]
-  (let [^bytes bkey (sha3-256 key)]
-    (Poly1305KeyGenerator/clamp bkey)
-    bkey))
+  {:pre [(= (count key) 32)]}
+  (let [key (clone-byte-array key)]
+    (Poly1305KeyGenerator/clamp key)
+    key))
 
 (defn poly1305-engine
-  "Create a hmac engine."
-  ([key iv] (poly1305-engine key iv :aes))
-  ([key iv alg]
-   (let [engine (resolve-engine alg)
-         mac    (Poly1305. engine)
-         kp     (KeyParameter. (key->poly1305key key))]
-     (.init mac (ParametersWithIV. kp iv))
-     (reify
-       proto/IMac
-       (update [_ input offset length]
-         (.update mac input offset length))
-       (end [_]
-         (let [buffer (byte-array (.getMacSize mac))]
-           (.doFinal mac buffer 0)
-           buffer))))))
+  "Create a poly1305 mac engine."
+  [^bytes key ^bytes iv ^Keyword alg]
+  {:pre [(= (count iv) 16)
+         (= (count key) 32)]}
+  (let [engine (resolve-engine alg)
+        mac    (Poly1305. engine)
+        kp     (KeyParameter. (key->polykey key))]
+    (.init mac (ParametersWithIV. kp iv))
+    (reify
+      proto/IMac
+      (update [_ input offset length]
+        (.update mac input offset length))
+      (end [_]
+        (let [buffer (byte-array (.getMacSize mac))]
+          (.doFinal mac buffer 0)
+          buffer)))))
+
+(defprotocol IPoly1305Mac
+  (^:private hash* [data key alg] "Generate the poly1305 digest for provided data.")
+  (^:private verify* [data signature key alg] "Virify the poly1305 digest for provided data."))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Internal implementations
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(defn- make-poly1305-plain-impl
-  "Calculate the poly1305 message authentication code
-  for byte array objects."
-  [^bytes input ^bytes key ^bytes iv ^Keyword alg]
-  (let [engine (poly1305-engine key iv alg)]
-    (proto/update! engine input)
-    (proto/end! engine)))
-
-(defn- make-poly1305-stream-impl
+(defn- hash-plain-data
+  "Calculate the message authentication code
+  for byte array objects using poly1305 algorithm."
+  ([^bytes input ^bytes key ^Keyword alg]
+   (let [iv (nonce/random-nonce 16)]
+     (hash-plain-data input key iv alg)))
+  ([^bytes input ^bytes key ^bytes iv ^Keyword alg]
+   (let [key (hash/sha256 key) ;; Normalizes an arbitrary length key to 32 bytes.
+         engine (poly1305-engine key iv alg)]
+     (proto/update! engine input)
+     (let [result (proto/end! engine)]
+       (concat-byte-arrays result iv)))))
+
+(defn- hash-stream-data
   "Calculate the poly1305 message authentication code
   for file like objects in most memory efficient way."
-  [^java.io.InputStream input ^bytes key ^bytes iv ^Keyword alg]
-  (let [engine (poly1305-engine key iv alg)
-        buffer (byte-array 5120)]
-    (loop []
-      (let [readed (.read input buffer 0 5120)]
-        (when-not (= readed -1)
-          (proto/update! engine buffer 0 readed)
-          (recur))))
-    (proto/end! engine)))
+  ([^java.io.InputStream input ^bytes key ^Keyword alg]
+   (let [iv (nonce/random-nonce 16)]
+     (hash-stream-data input key iv alg)))
+  ([^java.io.InputStream input ^bytes key ^bytes iv ^Keyword alg]
+   (let [key (hash/sha256 key) ;; Normalizes an arbitrary length key to 32 bytes.
+         engine (poly1305-engine key iv alg)
+         buffer (byte-array 5120)]
+     (loop []
+       (let [readed (.read input buffer 0 5120)]
+         (when-not (= readed -1)
+           (proto/update! engine buffer 0 readed)
+           (recur))))
+     (let [result (proto/end! engine)]
+       (concat-byte-arrays result iv)))))
+
+(defn- verify-plain-data
+  "Generic implementation of verify proces of
+  poly1305 mac digest."
+  [^bytes input ^bytes signature ^bytes key ^Keyword alg]
+  (let [outputsize poly1305-output-size
+        iv (codecs/clone-byte-array signature outputsize (count signature))
+        sig (hash-plain-data input key iv alg)]
+    (codecs/equals? sig signature)))
+
+(defn- verify-stream-data
+  "Generic implementation of verify proces of
+  poly1305 mac digest."
+  [^bytes input ^bytes signature ^bytes key ^Keyword alg]
+  (let [outputsize poly1305-output-size
+        iv (clone-byte-array signature outputsize (count signature))
+        sig (hash-stream-data input key iv alg)]
+    (codecs/equals? sig signature)))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Low level interface
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(declare make-poly1305)
-
-(defn verify-poly1305-impl
-  "Generic implementation of verify."
-  [input ^bytes signature ^bytes pkey ^bytes iv ^Keyword alg]
-  (let [sig (make-poly1305 input pkey iv alg)]
-    (Arrays/equals sig signature)))
-
-(defprotocol Poly1305Mac
-  "Protocol that defines a low level interface
-  to poly 1305 algorithm and allows extend it for
-  different types.
-  It comes with default implementation for: string,
-  bytes, input stream, file, url and uri."
-  (make-poly1305 [obj key iv alg] "Calculate poly1305 mac for type."))
-
-(alter-meta! #'make-poly1305 assoc :no-doc true :private true)
-
-(extend-protocol Poly1305Mac
+(extend-protocol IPoly1305Mac
   (Class/forName "[B")
-  (make-poly1305 [^bytes input ^bytes key ^bytes iv ^Keyword alg]
-    (make-poly1305-plain-impl input key iv alg))
+  (hash* [^bytes input ^bytes key ^Keyword alg]
+    (hash-plain-data input key alg))
+  (verify* [^bytes input ^bytes signature ^String key ^Keyword alg]
+    (verify-plain-data input signature key alg))
 
   java.lang.String
-  (make-poly1305 [^String input ^bytes key ^bytes iv ^Keyword alg]
-    (make-poly1305-plain-impl (->byte-array input) key iv alg))
+  (hash* [^String input ^bytes key ^Keyword alg]
+    (hash-plain-data (->byte-array input) key alg))
+  (verify* [^String input ^bytes signature ^String key ^Keyword alg]
+    (verify-plain-data (->byte-array input) signature key alg))
 
   java.io.InputStream
-  (make-poly1305 [^java.io.InputStream input ^bytes key ^bytes iv ^Keyword alg]
-    (make-poly1305-stream-impl input key iv alg))
+  (hash* [^java.io.InputStream input ^bytes key ^Keyword alg]
+    (hash-stream-data input key alg))
+  (verify* [^java.io.File input ^bytes signature ^String key ^Keyword alg]
+    (verify-stream-data (io/input-stream input) signature key alg))
 
   java.io.File
-  (make-poly1305 [^java.io.File input ^bytes key ^bytes iv ^Keyword alg]
-    (make-poly1305-stream-impl (io/input-stream input) key iv alg))
+  (hash* [^java.io.File input ^bytes key ^Keyword alg]
+    (hash-stream-data (io/input-stream input) key alg))
+  (verify* [^java.io.File input ^bytes signature ^String key ^Keyword alg]
+    (verify-stream-data (io/input-stream input) signature key alg))
 
   java.net.URL
-  (make-poly1305 [^java.net.URL input ^bytes key ^bytes iv ^Keyword alg]
-    (make-poly1305-stream-impl (io/input-stream input) key iv alg))
+  (hash* [^java.net.URL input ^bytes key ^Keyword alg]
+    (hash-stream-data (io/input-stream input) key alg))
+  (verify* [^java.net.URL input ^bytes signature ^String key ^Keyword alg]
+    (verify-stream-data (io/input-stream input) signature key alg))
 
   java.net.URI
-  (make-poly1305 [^java.net.URI input ^bytes key ^bytes iv ^Keyword alg]
-    (make-poly1305-stream-impl (io/input-stream input) key iv alg)))
+  (hash* [^java.net.URI input ^bytes key ^Keyword alg]
+    (hash-stream-data (io/input-stream input) key alg))
+  (verify* [^java.net.URI input ^bytes signature ^String key ^Keyword alg]
+    (verify-stream-data (io/input-stream input) signature key alg)))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; 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."
-  [input key ^bytes iv ^Keyword alg]
-  {:pre [(= (count iv) 16)]}
-  (let [key (->byte-array key)]
-    (make-poly1305 input key iv alg)))
+(defn hash
+  "Generate poly1305 digest for arbitrary
+  input data, a secret key and crypto algorithm.
+
+  If algorithm is not supplied, aes will be used
+  as default value."
+  ([input key] (hash input key :aes))
+  ([input key alg]
+   (hash* input key alg)))
 
 (defn verify
   "Verify poly1305 mac for specified data and signature."
-  [input ^bytes signature pkey ^bytes iv ^Keyword alg]
-  {:pre [(= (count iv) 16)]}
-  (let [key (->byte-array pkey)]
-    (verify-poly1305-impl input signature key iv alg)))
+  [input ^bytes signature key ^Keyword alg]
+  (verify* input signature key alg))
+
+(def ^{:doc "Deprecated alias for `hash` function.`"
+       :deprecated true}
+  poly1305 hash)

           org.bouncycastle.crypto.engines.TwofishEngine
           org.bouncycastle.crypto.BlockCipher
           clojure.lang.IFn
           clojure.lang.Keyword
           buddy.Arrays))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Low level hmac engine.

  Poly1305-AES offers also cipher replaceability. If anything does
  go wrong with AES, it can be substituted with identical security
  guarantee."
  (:refer-clojure :exclude [hash])
  (:require [buddy.core.hash :as hash]
            [buddy.core.nonce :as nonce]
            [buddy.core.mac.proto :as proto]
            [buddy.core.codecs :as codecs :refer :all]
            [clojure.java.io :as io])
  (:import org.bouncycastle.crypto.generators.Poly1305KeyGenerator
           org.bouncycastle.crypto.macs.Poly1305
