Ecdsa recreate pair from secret (#2)

* add possibility to re-create public key from private key for ECDSA alghorithm

* change version

* change version

* add comments, change version of cats-effect

* add comments, change method name

* change comment

* typo
This commit is contained in:
Dima 2018-08-22 11:26:10 +03:00 committed by GitHub
parent d938192ef6
commit 3e0d21d197
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 46 additions and 8 deletions

View File

@ -14,7 +14,7 @@ val scalaV = scalaVersion := "2.12.5"
val commons = Seq( val commons = Seq(
scalaV, scalaV,
version := "0.0.1", version := "0.0.2",
fork in Test := true, fork in Test := true,
parallelExecution in Test := false, parallelExecution in Test := false,
organization := "one.fluence", organization := "one.fluence",
@ -33,13 +33,13 @@ commons
val CodecV = "0.0.3" val CodecV = "0.0.3"
val CatsEffectV = "1.0.0-RC" val CatsEffectV = "1.0.0-RC3"
val SloggingV = "0.6.1" val SloggingV = "0.6.1"
val ScalatestV = "3.0.+" val ScalatestV = "3.0.+"
val bouncyCastle = "org.bouncycastle" % "bcprov-jdk15on" % "1.59" val bouncyCastle = "org.bouncycastle" % "bcprov-jdk15on" % "1.59"
enablePlugins(AutomateHeaderPlugin) enablePlugins(AutomateHeaderPlugin)
@ -158,12 +158,12 @@ lazy val `crypto-jwt` = crossProject(JVMPlatform, JSPlatform)
.settings( .settings(
commons, commons,
libraryDependencies ++= Seq( libraryDependencies ++= Seq(
"one.fluence" %%% "codec-circe" % CodecV, "one.fluence" %%% "codec-circe" % CodecV,
"org.scalatest" %%% "scalatest" % ScalatestV % Test "org.scalatest" %%% "scalatest" % ScalatestV % Test
) )
) )
.jsSettings( .jsSettings(
fork in Test := false, fork in Test := false,
scalaJSModuleKind := ModuleKind.CommonJSModule scalaJSModuleKind := ModuleKind.CommonJSModule
) )
.enablePlugins(AutomateHeaderPlugin) .enablePlugins(AutomateHeaderPlugin)

View File

@ -23,6 +23,7 @@ import java.security.interfaces.ECPrivateKey
import cats.Monad import cats.Monad
import cats.data.EitherT import cats.data.EitherT
import fluence.crypto.KeyPair.Secret
import fluence.crypto.{KeyPair, _} import fluence.crypto.{KeyPair, _}
import fluence.crypto.hash.JdkCryptoHasher import fluence.crypto.hash.JdkCryptoHasher
import fluence.crypto.signature.{SignAlgo, SignatureChecker, Signer} import fluence.crypto.signature.{SignAlgo, SignatureChecker, Signer}
@ -72,6 +73,31 @@ class Ecdsa(curveType: String, scheme: String, hasher: Option[Crypto.Hasher[Arra
} yield keyPair } yield keyPair
} }
/**
* Restores pair of keys from the known secret key.
* The public key will be the same each method call with the same secret key.
* @param sk secret key
* @return key pair
*/
def restorePairFromSecret[F[_]: Monad](sk: Secret): EitherT[F, CryptoError, KeyPair] =
for {
ecSpec EitherT.fromOption(
Option(ECNamedCurveTable.getParameterSpec(curveType)),
CryptoError("Parameter spec for the curve is not available.")
)
keyPair nonFatalHandling {
val hex = sk.value.toHex
val d = new BigInteger(hex, HEXradix)
// to re-create public key from private we need to multiply known from curve point G with D (private key)
// result will be point Q (public key)
// https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm
val g = ecSpec.getG
val q = g.multiply(d)
val pk = ByteVector(q.getEncoded(true))
KeyPair.fromByteVectors(pk, sk.value)
}("Could not generate KeyPair from private key. Unexpected.")
} yield keyPair
def sign[F[_]: Monad]( def sign[F[_]: Monad](
keyPair: KeyPair, keyPair: KeyPair,
message: ByteVector message: ByteVector

View File

@ -18,6 +18,7 @@
package fluence.crypto package fluence.crypto
import java.io.File import java.io.File
import java.math.BigInteger
import cats.data.EitherT import cats.data.EitherT
import cats.instances.try_._ import cats.instances.try_._
@ -31,7 +32,7 @@ import scala.util.{Random, Try}
class SignatureSpec extends WordSpec with Matchers { class SignatureSpec extends WordSpec with Matchers {
def rndBytes(size: Int) = Random.nextString(10).getBytes def rndBytes(size: Int): Array[Byte] = Random.nextString(10).getBytes
def rndByteVector(size: Int) = ByteVector(rndBytes(size)) def rndByteVector(size: Int) = ByteVector(rndBytes(size))
@ -125,5 +126,16 @@ class SignatureSpec extends WordSpec with Matchers {
//try to store key into previously created file //try to store key into previously created file
storage.storeKeyPair(keys).attempt.unsafeRunSync().isLeft shouldBe true storage.storeKeyPair(keys).attempt.unsafeRunSync().isLeft shouldBe true
} }
"restore key pair from secret key" in {
val algo = Ecdsa.signAlgo
val testKeys = algo.generateKeyPair.unsafe(None)
val ecdsa = Ecdsa.ecdsa_secp256k1_sha256
val newKeys = ecdsa.restorePairFromSecret(testKeys.secretKey).extract
testKeys shouldBe newKeys
}
} }
} }

View File

@ -1 +1 @@
sbt.version = 1.1.4 sbt.version = 1.2.1