From a7576f548bda7452c46cdaea6fa75216f92e3a8d Mon Sep 17 00:00:00 2001 From: Dmitry Kurinskiy Date: Sat, 10 Mar 2018 15:50:45 +0100 Subject: [PATCH] Functor and Contravariant typeclasses for CryptoHasher (#80) --- .../fluence/crypto/hash/JsCryptoHasher.scala | 25 ++++-------- .../fluence/crypto/hash/CryptoHasher.scala | 40 +++++++++++++++++++ 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/js/src/main/scala/fluence/crypto/hash/JsCryptoHasher.scala b/js/src/main/scala/fluence/crypto/hash/JsCryptoHasher.scala index 7a8d880..c7f95e6 100644 --- a/js/src/main/scala/fluence/crypto/hash/JsCryptoHasher.scala +++ b/js/src/main/scala/fluence/crypto/hash/JsCryptoHasher.scala @@ -24,26 +24,17 @@ import scala.scalajs.js.JSConverters._ object JsCryptoHasher { - lazy val Sha256: CryptoHasher.Bytes = new CryptoHasher[Array[Byte], Array[Byte]] { - override def hash(msg1: Array[Byte]): Array[Byte] = { + lazy val Sha256: CryptoHasher.Bytes = + CryptoHasher.buildM[Array[Byte], Array[Byte]]{ msg ⇒ val sha256 = new SHA256() - sha256.update(msg1.toJSArray) + sha256.update(msg.toJSArray) ByteVector.fromValidHex(sha256.digest("hex")).toArray - } - override def hash(msg1: Array[Byte], msg2: Array[Byte]*): Array[Byte] = { - hash(msg1 ++ msg2.flatten) - } - } + }(_ ++ _) - lazy val Sha1: CryptoHasher.Bytes = new CryptoHasher[Array[Byte], Array[Byte]] { - override def hash(msg1: Array[Byte]): Array[Byte] = { + lazy val Sha1: CryptoHasher.Bytes = + CryptoHasher.buildM[Array[Byte], Array[Byte]]{ msg ⇒ val sha1 = new SHA1() - sha1.update(msg1.toJSArray) + sha1.update(msg.toJSArray) ByteVector.fromValidHex(sha1.digest("hex")).toArray - } - override def hash(msg1: Array[Byte], msg2: Array[Byte]*): Array[Byte] = { - hash(msg1 ++ msg2.flatten) - } - - } + }(_ ++ _) } diff --git a/src/main/scala/fluence/crypto/hash/CryptoHasher.scala b/src/main/scala/fluence/crypto/hash/CryptoHasher.scala index 8e0eac9..75ea307 100644 --- a/src/main/scala/fluence/crypto/hash/CryptoHasher.scala +++ b/src/main/scala/fluence/crypto/hash/CryptoHasher.scala @@ -17,20 +17,60 @@ package fluence.crypto.hash +import cats.kernel.Semigroup +import cats.{ Contravariant, Functor, Monoid, Traverse } + +import scala.language.{ higherKinds, reflectiveCalls } + /** * TODO add F[_] effect * Base interface for hashing. + * * @tparam M type of message for hashing * @tparam H type of hashed message */ trait CryptoHasher[M, H] { + self ⇒ def hash(msg: M): H def hash(msg1: M, msgN: M*): H + def hashM[F[_] : Traverse](ms: F[M])(implicit M: Monoid[M]): H = + hash(Traverse[F].fold(ms)) + + final def map[B](f: H ⇒ B): CryptoHasher[M, B] = new CryptoHasher[M, B] { + override def hash(msg: M): B = f(self.hash(msg)) + + override def hash(msg1: M, msgN: M*): B = f(self.hash(msg1, msgN: _*)) + } + + final def contramap[N](f: N ⇒ M): CryptoHasher[N, H] = new CryptoHasher[N, H] { + override def hash(msg: N): H = self.hash(f(msg)) + + override def hash(msg1: N, msgN: N*): H = self.hash(f(msg1), msgN.map(f): _*) + } + } object CryptoHasher { type Bytes = CryptoHasher[Array[Byte], Array[Byte]] + + def buildM[M : Semigroup, H](h: M ⇒ H): CryptoHasher[M, H] = new CryptoHasher[M, H] { + override def hash(msg: M): H = h(msg) + + override def hash(msg1: M, msgN: M*): H = h(msgN.foldLeft(msg1)(Semigroup[M].combine)) + } + + implicit def cryptoHasherFunctor[M]: Functor[({ type λ[α] = CryptoHasher[M, α] })#λ] = + new Functor[({ type λ[α] = CryptoHasher[M, α] })#λ] { + override def map[A, B](fa: CryptoHasher[M, A])(f: A ⇒ B): CryptoHasher[M, B] = + fa.map(f) + } + + implicit def cryptoHasherContravariant[H]: Contravariant[({ type λ[α] = CryptoHasher[α, H] })#λ] = + new Contravariant[({ type λ[α] = CryptoHasher[α, H] })#λ] { + override def contramap[A, B](fa: CryptoHasher[A, H])(f: B ⇒ A): CryptoHasher[B, H] = + fa.contramap(f) + } }