From f7557a1d757c8f0d3c7d55edbdb73da24e704916 Mon Sep 17 00:00:00 2001 From: Dima Date: Wed, 3 Jul 2019 12:44:27 +0300 Subject: [PATCH] specs refactoring, move cross-platform specs to the shared subproject (#9) --- build.sbt | 2 +- .../crypto/{ed25519 => eddsa}/Ed25519.scala | 2 +- .../scala/fluence/crypto/JSHashSpec.scala | 64 ------- .../scala/fluence/crypto/Ed25519Spec.scala | 174 ------------------ .../{EcdsaSpec.scala => JvmEcdsaSpec.scala} | 59 +----- .../scala/fluence/crypto/JvmEd25519Spec.scala | 73 ++++++++ .../scala/fluence/crypto/EcdsaSpec.scala} | 20 +- .../scala/fluence/crypto/Ed25519Spec.scala | 23 ++- .../test/scala/fluence/crypto/HashSpec.scala} | 10 +- 9 files changed, 110 insertions(+), 317 deletions(-) rename hashsign/js/src/main/scala/fluence/crypto/{ed25519 => eddsa}/Ed25519.scala (99%) delete mode 100644 hashsign/js/src/test/scala/fluence/crypto/JSHashSpec.scala delete mode 100644 hashsign/jvm/src/test/scala/fluence/crypto/Ed25519Spec.scala rename hashsign/jvm/src/test/scala/fluence/crypto/{EcdsaSpec.scala => JvmEcdsaSpec.scala} (58%) create mode 100644 hashsign/jvm/src/test/scala/fluence/crypto/JvmEd25519Spec.scala rename hashsign/{js/src/test/scala/fluence/crypto/EllipticSpec.scala => src/test/scala/fluence/crypto/EcdsaSpec.scala} (89%) rename hashsign/{js => }/src/test/scala/fluence/crypto/Ed25519Spec.scala (89%) rename hashsign/{jvm/src/test/scala/fluence/crypto/JvmHashSpec.scala => src/test/scala/fluence/crypto/HashSpec.scala} (88%) diff --git a/build.sbt b/build.sbt index 1f06352..50ed7c1 100644 --- a/build.sbt +++ b/build.sbt @@ -14,7 +14,7 @@ val scalaV = scalaVersion := "2.12.8" val commons = Seq( scalaV, - version := "0.0.7", + version := "0.0.8", fork in Test := true, parallelExecution in Test := false, organization := "one.fluence", diff --git a/hashsign/js/src/main/scala/fluence/crypto/ed25519/Ed25519.scala b/hashsign/js/src/main/scala/fluence/crypto/eddsa/Ed25519.scala similarity index 99% rename from hashsign/js/src/main/scala/fluence/crypto/ed25519/Ed25519.scala rename to hashsign/js/src/main/scala/fluence/crypto/eddsa/Ed25519.scala index e1ca955..16edbe2 100644 --- a/hashsign/js/src/main/scala/fluence/crypto/ed25519/Ed25519.scala +++ b/hashsign/js/src/main/scala/fluence/crypto/eddsa/Ed25519.scala @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package fluence.crypto.ed25519 +package fluence.crypto.eddsa import cats.Monad import cats.data.EitherT diff --git a/hashsign/js/src/test/scala/fluence/crypto/JSHashSpec.scala b/hashsign/js/src/test/scala/fluence/crypto/JSHashSpec.scala deleted file mode 100644 index 98be79a..0000000 --- a/hashsign/js/src/test/scala/fluence/crypto/JSHashSpec.scala +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2017 Fluence Labs Limited - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package fluence.crypto - -import fluence.crypto.facade.ecdsa.{SHA1, SHA256} -import org.scalatest.{Matchers, WordSpec} -import scodec.bits.{Bases, ByteVector} - -import scala.scalajs.js.JSConverters._ -import scala.scalajs.js.typedarray.Uint8Array - -class JSHashSpec extends WordSpec with Matchers { - "js hasher" should { - //test values get from third-party hash services - "work with sha256" in { - val str = "sha256Tester" - val sha256TesterHex = "513c17f8cf6ba96ce412cc2ae82f68821e9a2c6ae7a2fb1f5e46d08c387c8e65" - - val hasher = new SHA256() - hasher.update(new Uint8Array(str.getBytes().toJSArray)) - val hex = hasher.digest("hex") - hex shouldBe sha256TesterHex - } - - "work with sha1" in { - val str = "sha1Tester" - val sha1TesterHex = "879db20eabcecea7d4736a8bae5bc64564b76b2f" - - val hasher = new SHA1() - hasher.update(new Uint8Array(str.getBytes().toJSArray)) - val hex = hasher.digest("hex") - hex shouldBe sha1TesterHex - } - - "check unsigned array with sha1" in { - - val arr = Array[Byte](3, -9, -31, 48, 10, 125, 51, -39, -20, -125, 123, 61, -36, 49, 76, 90, -16, 54, -61, 62, 50, - -116, -37, -88, -125, -32, -105, 120, 118, 13, -37, 33, -36) - - val base64Check = "9keNwsj08vKTlwIpHAEYvsfpdP4=" - - val hasher = new SHA1() - hasher.update(new Uint8Array(arr.toJSArray)) - val hex = hasher.digest("hex") - - ByteVector.fromValidHex(hex, Bases.Alphabets.HexLowercase).toBase64 shouldBe base64Check - } - } -} diff --git a/hashsign/jvm/src/test/scala/fluence/crypto/Ed25519Spec.scala b/hashsign/jvm/src/test/scala/fluence/crypto/Ed25519Spec.scala deleted file mode 100644 index 9e0a422..0000000 --- a/hashsign/jvm/src/test/scala/fluence/crypto/Ed25519Spec.scala +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (C) 2017 Fluence Labs Limited - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package fluence.crypto - -import java.io.File - -import cats.data.EitherT -import cats.instances.try_._ -import fluence.crypto.eddsa.Ed25519 -import fluence.crypto.keystore.FileKeyStorage -import fluence.crypto.signature.Signature -import org.scalatest.{Matchers, WordSpec} -import scodec.bits.ByteVector - -import scala.util.{Random, Try} - -class Ed25519Spec extends WordSpec with Matchers { - - def rndBytes(size: Int): Array[Byte] = Random.nextString(10).getBytes - - def rndByteVector(size: Int) = ByteVector(rndBytes(size)) - - private implicit class TryEitherTExtractor[A <: Throwable, B](et: EitherT[Try, A, B]) { - - def extract: B = - et.value.map { - case Left(e) ⇒ fail(e) // for making test fail message more describable - case Right(v) ⇒ v - }.get - - def isOk: Boolean = et.value.fold(_ ⇒ false, _.isRight) - } - - "ed25519 algorithm" should { - "correct sign and verify data" in { - val algorithm = Ed25519.ed25519Init(32) - - val keys = algorithm.generateKeyPair.unsafe(None) - val pubKey = keys.publicKey - val data = rndByteVector(10) - val sign = algorithm.sign[Try](keys, data).extract - - algorithm.verify[Try](pubKey, sign, data).isOk shouldBe true - - val randomData = rndByteVector(10) - val randomSign = algorithm.sign(keys, randomData).extract - - algorithm.verify(pubKey, randomSign, data).isOk shouldBe false - - algorithm.verify(pubKey, sign, randomData).isOk shouldBe false - } - - "correctly work with signer and checker" in { - val algo = Ed25519.signAlgo - val keys = algo.generateKeyPair.unsafe(None) - val signer = algo.signer(keys) - val checker = algo.checker(keys.publicKey) - - val data = rndByteVector(10) - val sign = signer.sign(data).extract - - checker.check(sign, data).isOk shouldBe true - - val randomSign = signer.sign(rndByteVector(10)).extract - checker.check(randomSign, data).isOk shouldBe false - } - - "throw an errors on invalid data" in { - val algo = Ed25519.signAlgo - val keys = algo.generateKeyPair.unsafe(None) - val signer = algo.signer(keys) - val checker = algo.checker(keys.publicKey) - val data = rndByteVector(10) - - val sign = signer.sign(data).extract - - the[CryptoError] thrownBy { - checker.check(Signature(rndByteVector(10)), data).value.flatMap(_.toTry).get - } - val invalidChecker = algo.checker(KeyPair.fromByteVectors(rndByteVector(10), rndByteVector(10)).publicKey) - the[CryptoError] thrownBy { - invalidChecker - .check(sign, data) - .value - .flatMap(_.toTry) - .get - } - } - - "store and read key from file" in { - val algo = Ed25519.signAlgo - val keys = algo.generateKeyPair.unsafe(None) - - val keyFile = File.createTempFile("test", "") - if (keyFile.exists()) keyFile.delete() - val storage = new FileKeyStorage(keyFile) - - storage.storeKeyPair(keys).unsafeRunSync() - - val keysReadE = storage.readKeyPair - val keysRead = keysReadE.unsafeRunSync() - - val signer = algo.signer(keys) - val data = rndByteVector(10) - val sign = signer.sign(data).extract - - algo.checker(keys.publicKey).check(sign, data).isOk shouldBe true - algo.checker(keysRead.publicKey).check(sign, data).isOk shouldBe true - - //try to store key into previously created file - storage.storeKeyPair(keys).attempt.unsafeRunSync().isLeft shouldBe true - } - - "restore key pair from secret key" in { - val algo = Ed25519.signAlgo - val testKeys = algo.generateKeyPair.unsafe(None) - - val ed25519 = Ed25519.ed25519 - - val newKeys = ed25519.restorePairFromSecret(testKeys.secretKey).extract - - testKeys shouldBe newKeys - } - - "work with tendermint keys" in { - /* - { - "address": "C08269A8AACD53C3488F16F285821DAC77CF5DEF", - "pub_key": { - "type": "tendermint/PubKeyEd25519", - "value": "FWB5lXZ/TT2132+jXp/8aQzNwISwp9uuFz4z0TXDdxY=" - }, - "priv_key": { - "type": "tendermint/PrivKeyEd25519", - "value": "P6jw9q/Rytdxpv5Wxs1aYA8w82uS0x3CpmS9+GpaMGIVYHmVdn9NPbXfb6Nen/xpDM3AhLCn264XPjPRNcN3Fg==" - } - } - */ - - val privKeyBase64 = "P6jw9q/Rytdxpv5Wxs1aYA8w82uS0x3CpmS9+GpaMGIVYHmVdn9NPbXfb6Nen/xpDM3AhLCn264XPjPRNcN3Fg==" - val pubKeyBase64 = "FWB5lXZ/TT2132+jXp/8aQzNwISwp9uuFz4z0TXDdxY=" - - val privKey = ByteVector.fromBase64Descriptive(privKeyBase64).right.get - val pubKey = ByteVector.fromBase64Descriptive(pubKeyBase64).right.get - - val restored = Ed25519.ed25519 - .restorePairFromSecret[Try](KeyPair.Secret(privKey.dropRight(32))) - .value - .get - .right - .get - .publicKey - .bytes - - restored shouldBe pubKey.toArray - restored shouldBe privKey.drop(32).toArray - } - } -} diff --git a/hashsign/jvm/src/test/scala/fluence/crypto/EcdsaSpec.scala b/hashsign/jvm/src/test/scala/fluence/crypto/JvmEcdsaSpec.scala similarity index 58% rename from hashsign/jvm/src/test/scala/fluence/crypto/EcdsaSpec.scala rename to hashsign/jvm/src/test/scala/fluence/crypto/JvmEcdsaSpec.scala index e8cdd93..00d93bd 100644 --- a/hashsign/jvm/src/test/scala/fluence/crypto/EcdsaSpec.scala +++ b/hashsign/jvm/src/test/scala/fluence/crypto/JvmEcdsaSpec.scala @@ -29,7 +29,7 @@ import scodec.bits.ByteVector import scala.util.{Random, Try} -class EcdsaSpec extends WordSpec with Matchers { +class JvmEcdsaSpec extends WordSpec with Matchers { def rndBytes(size: Int): Array[Byte] = Random.nextString(10).getBytes @@ -46,62 +46,7 @@ class EcdsaSpec extends WordSpec with Matchers { def isOk: Boolean = et.value.fold(_ ⇒ false, _.isRight) } - "ecdsa algorithm" should { - "correct sign and verify data" in { - val algorithm = Ecdsa.ecdsa_secp256k1_sha256 - - val keys = algorithm.generateKeyPair.unsafe(None) - val pubKey = keys.publicKey - val data = rndByteVector(10) - val sign = algorithm.sign[Try](keys, data).extract - - algorithm.verify[Try](pubKey, sign, data).isOk shouldBe true - - val randomData = rndByteVector(10) - val randomSign = algorithm.sign(keys, randomData).extract - - algorithm.verify(pubKey, randomSign, data).isOk shouldBe false - - algorithm.verify(pubKey, sign, randomData).isOk shouldBe false - } - - "correctly work with signer and checker" in { - val algo = Ecdsa.signAlgo - val keys = algo.generateKeyPair.unsafe(None) - val signer = algo.signer(keys) - val checker = algo.checker(keys.publicKey) - - val data = rndByteVector(10) - val sign = signer.sign(data).extract - - checker.check(sign, data).isOk shouldBe true - - val randomSign = signer.sign(rndByteVector(10)).extract - checker.check(randomSign, data).isOk shouldBe false - } - - "throw an errors on invalid data" in { - val algo = Ecdsa.signAlgo - val keys = algo.generateKeyPair.unsafe(None) - val signer = algo.signer(keys) - val checker = algo.checker(keys.publicKey) - val data = rndByteVector(10) - - val sign = signer.sign(data).extract - - the[CryptoError] thrownBy { - checker.check(Signature(rndByteVector(10)), data).value.flatMap(_.toTry).get - } - val invalidChecker = algo.checker(KeyPair.fromByteVectors(rndByteVector(10), rndByteVector(10)).publicKey) - the[CryptoError] thrownBy { - invalidChecker - .check(sign, data) - .value - .flatMap(_.toTry) - .get - } - } - + "jvm ecdsa algorithm" should { "store and read key from file" in { val algo = Ecdsa.signAlgo val keys = algo.generateKeyPair.unsafe(None) diff --git a/hashsign/jvm/src/test/scala/fluence/crypto/JvmEd25519Spec.scala b/hashsign/jvm/src/test/scala/fluence/crypto/JvmEd25519Spec.scala new file mode 100644 index 0000000..2f69247 --- /dev/null +++ b/hashsign/jvm/src/test/scala/fluence/crypto/JvmEd25519Spec.scala @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2017 Fluence Labs Limited + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package fluence.crypto + +import java.io.File + +import cats.data.EitherT +import cats.instances.try_._ +import fluence.crypto.eddsa.Ed25519 +import fluence.crypto.keystore.FileKeyStorage +import org.scalatest.{Matchers, WordSpec} +import scodec.bits.ByteVector + +import scala.util.{Random, Try} + +class JvmEd25519Spec extends WordSpec with Matchers { + + def rndBytes(size: Int): Array[Byte] = Random.nextString(10).getBytes + + def rndByteVector(size: Int) = ByteVector(rndBytes(size)) + + private implicit class TryEitherTExtractor[A <: Throwable, B](et: EitherT[Try, A, B]) { + + def extract: B = + et.value.map { + case Left(e) ⇒ fail(e) // for making test fail message more describable + case Right(v) ⇒ v + }.get + + def isOk: Boolean = et.value.fold(_ ⇒ false, _.isRight) + } + + "ed25519 algorithm" should { + "store and read key from file" in { + val algo = Ed25519.signAlgo + val keys = algo.generateKeyPair.unsafe(None) + + val keyFile = File.createTempFile("test", "") + if (keyFile.exists()) keyFile.delete() + val storage = new FileKeyStorage(keyFile) + + storage.storeKeyPair(keys).unsafeRunSync() + + val keysReadE = storage.readKeyPair + val keysRead = keysReadE.unsafeRunSync() + + val signer = algo.signer(keys) + val data = rndByteVector(10) + val sign = signer.sign(data).extract + + algo.checker(keys.publicKey).check(sign, data).isOk shouldBe true + algo.checker(keysRead.publicKey).check(sign, data).isOk shouldBe true + + //try to store key into previously created file + storage.storeKeyPair(keys).attempt.unsafeRunSync().isLeft shouldBe true + } + } +} diff --git a/hashsign/js/src/test/scala/fluence/crypto/EllipticSpec.scala b/hashsign/src/test/scala/fluence/crypto/EcdsaSpec.scala similarity index 89% rename from hashsign/js/src/test/scala/fluence/crypto/EllipticSpec.scala rename to hashsign/src/test/scala/fluence/crypto/EcdsaSpec.scala index e38c9e7..9725f20 100644 --- a/hashsign/js/src/test/scala/fluence/crypto/EllipticSpec.scala +++ b/hashsign/src/test/scala/fluence/crypto/EcdsaSpec.scala @@ -17,6 +17,8 @@ package fluence.crypto +import java.io.File + import cats.data.EitherT import cats.instances.try_._ import fluence.crypto.ecdsa.Ecdsa @@ -26,7 +28,7 @@ import scodec.bits.ByteVector import scala.util.{Random, Try} -class EllipticSpec extends WordSpec with Matchers { +class EcdsaSpec extends WordSpec with Matchers { def rndBytes(size: Int): Array[Byte] = Random.nextString(10).getBytes @@ -86,13 +88,17 @@ class EllipticSpec extends WordSpec with Matchers { val sign = signer.sign(data).extract - the[CryptoError] thrownBy checker.check(Signature(rndByteVector(10)), data).value.flatMap(_.toTry).get + the[CryptoError] thrownBy { + checker.check(Signature(rndByteVector(10)), data).value.flatMap(_.toTry).get + } val invalidChecker = algo.checker(KeyPair.fromByteVectors(rndByteVector(10), rndByteVector(10)).publicKey) - the[CryptoError] thrownBy invalidChecker - .check(sign, data) - .value - .flatMap(_.toTry) - .get + the[CryptoError] thrownBy { + invalidChecker + .check(sign, data) + .value + .flatMap(_.toTry) + .get + } } } } diff --git a/hashsign/js/src/test/scala/fluence/crypto/Ed25519Spec.scala b/hashsign/src/test/scala/fluence/crypto/Ed25519Spec.scala similarity index 89% rename from hashsign/js/src/test/scala/fluence/crypto/Ed25519Spec.scala rename to hashsign/src/test/scala/fluence/crypto/Ed25519Spec.scala index 3a42374..ce4f2a6 100644 --- a/hashsign/js/src/test/scala/fluence/crypto/Ed25519Spec.scala +++ b/hashsign/src/test/scala/fluence/crypto/Ed25519Spec.scala @@ -17,16 +17,19 @@ package fluence.crypto +import java.io.File + import cats.data.EitherT +import cats.instances.try_._ +import fluence.crypto.eddsa.Ed25519 import fluence.crypto.signature.Signature import org.scalatest.{Matchers, WordSpec} import scodec.bits.ByteVector -import cats.instances.try_._ -import fluence.crypto.ed25519.Ed25519 import scala.util.{Random, Try} class Ed25519Spec extends WordSpec with Matchers { + def rndBytes(size: Int): Array[Byte] = Random.nextString(10).getBytes def rndByteVector(size: Int) = ByteVector(rndBytes(size)) @@ -85,13 +88,17 @@ class Ed25519Spec extends WordSpec with Matchers { val sign = signer.sign(data).extract - the[CryptoError] thrownBy checker.check(Signature(rndByteVector(10)), data).value.flatMap(_.toTry).get + the[CryptoError] thrownBy { + checker.check(Signature(rndByteVector(10)), data).value.flatMap(_.toTry).get + } val invalidChecker = algo.checker(KeyPair.fromByteVectors(rndByteVector(10), rndByteVector(10)).publicKey) - the[CryptoError] thrownBy invalidChecker - .check(sign, data) - .value - .flatMap(_.toTry) - .get + the[CryptoError] thrownBy { + invalidChecker + .check(sign, data) + .value + .flatMap(_.toTry) + .get + } } } } diff --git a/hashsign/jvm/src/test/scala/fluence/crypto/JvmHashSpec.scala b/hashsign/src/test/scala/fluence/crypto/HashSpec.scala similarity index 88% rename from hashsign/jvm/src/test/scala/fluence/crypto/JvmHashSpec.scala rename to hashsign/src/test/scala/fluence/crypto/HashSpec.scala index 2a6f802..9796f31 100644 --- a/hashsign/jvm/src/test/scala/fluence/crypto/JvmHashSpec.scala +++ b/hashsign/src/test/scala/fluence/crypto/HashSpec.scala @@ -17,18 +17,18 @@ package fluence.crypto -import fluence.crypto.hash.JdkCryptoHasher +import fluence.crypto.hash.CryptoHashers import org.scalatest.{Matchers, WordSpec} import scodec.bits.ByteVector -class JvmHashSpec extends WordSpec with Matchers { +class HashSpec extends WordSpec with Matchers { "jvm hasher" should { //test values get from third-party hash services "work with sha256" in { val str = "sha256Tester" val sha256TesterHex = "513c17f8cf6ba96ce412cc2ae82f68821e9a2c6ae7a2fb1f5e46d08c387c8e65" - val hasher = JdkCryptoHasher.Sha256 + val hasher = CryptoHashers.Sha256 ByteVector(hasher.unsafe(str.getBytes())).toHex shouldBe sha256TesterHex } @@ -36,7 +36,7 @@ class JvmHashSpec extends WordSpec with Matchers { val str = "sha1Tester" val sha1TesterHex = "879db20eabcecea7d4736a8bae5bc64564b76b2f" - val hasher = JdkCryptoHasher.Sha1 + val hasher = CryptoHashers.Sha1 ByteVector(hasher.unsafe(str.getBytes())).toHex shouldBe sha1TesterHex } @@ -47,7 +47,7 @@ class JvmHashSpec extends WordSpec with Matchers { val base64Check = "9keNwsj08vKTlwIpHAEYvsfpdP4=" - val hasher = JdkCryptoHasher.Sha1 + val hasher = CryptoHashers.Sha1 ByteVector(hasher.unsafe(arr)).toBase64 shouldBe base64Check }