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

View File

@ -23,6 +23,7 @@ import java.security.interfaces.ECPrivateKey
import cats.Monad
import cats.data.EitherT
import fluence.crypto.KeyPair.Secret
import fluence.crypto.{KeyPair, _}
import fluence.crypto.hash.JdkCryptoHasher
import fluence.crypto.signature.{SignAlgo, SignatureChecker, Signer}
@ -72,6 +73,31 @@ class Ecdsa(curveType: String, scheme: String, hasher: Option[Crypto.Hasher[Arra
} 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](
keyPair: KeyPair,
message: ByteVector

View File

@ -18,6 +18,7 @@
package fluence.crypto
import java.io.File
import java.math.BigInteger
import cats.data.EitherT
import cats.instances.try_._
@ -31,7 +32,7 @@ import scala.util.{Random, Try}
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))
@ -125,5 +126,16 @@ class SignatureSpec extends WordSpec with Matchers {
//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 = 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