diff --git a/ec/src/main/kotlin/io/provenance/hdwallet/ec/Curve.kt b/ec/src/main/kotlin/io/provenance/hdwallet/ec/Curve.kt index 9b0e876..424edac 100644 --- a/ec/src/main/kotlin/io/provenance/hdwallet/ec/Curve.kt +++ b/ec/src/main/kotlin/io/provenance/hdwallet/ec/Curve.kt @@ -4,10 +4,14 @@ import io.provenance.hdwallet.ec.bc.toCurve import io.provenance.hdwallet.ec.bc.toCurvePoint import org.bouncycastle.crypto.ec.CustomNamedCurves import org.bouncycastle.crypto.params.ECDomainParameters +import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util import org.bouncycastle.math.ec.ECCurve import org.bouncycastle.math.ec.ECPoint import org.bouncycastle.math.ec.FixedPointCombMultiplier import java.math.BigInteger +import java.security.spec.ECParameterSpec +import org.bouncycastle.jce.spec.ECParameterSpec as BCECParameterSpec +import java.security.spec.EllipticCurve class CurvePoint(val ecPoint: ECPoint) { val x: BigInteger = ecPoint.xCoord.toBigInteger() @@ -18,6 +22,12 @@ class CurvePoint(val ecPoint: ECPoint) { fun mul(n: BigInteger): CurvePoint = ecPoint.multiply(n).toCurvePoint() fun add(n: CurvePoint): CurvePoint = ecPoint.add(n.ecPoint).toCurvePoint() fun normalize(): CurvePoint = ecPoint.normalize().toCurvePoint() + + fun toJavaECPoint(): java.security.spec.ECPoint = + java.security.spec.ECPoint(x, y) + + fun toBCECPoint(curve: ECCurve): ECPoint = + EC5Util.convertPoint(curve, toJavaECPoint()) } data class Curve(val n: BigInteger, val g: CurvePoint, private val ecCurve: ECCurve) { @@ -32,6 +42,12 @@ data class Curve(val n: BigInteger, val g: CurvePoint, private val ecCurve: ECCu return BigInteger(1, encoded.copyOfRange(1, encoded.size)) } + fun toJavaEllipticCurve(): EllipticCurve = + EC5Util.convertCurve(ecCurve, ecDomainParameters.seed) + + fun toBCEllipticCurve(): ECCurve = + EC5Util.convertCurve(toJavaEllipticCurve()) + private fun fpcMul(pk: BigInteger): CurvePoint { val postProcessedPrivateKey = if (pk.bitLength() > n.bitLength()) pk.mod(n) @@ -49,3 +65,9 @@ val secp256r1Curve = Curve.lookup("secp256r1") // Provenance defaults to the secp256k1 EC curve for keys and signatures. val CURVE = secp256k1Curve + +val Curve.ecParameterSpec: ECParameterSpec + get() = ECParameterSpec(toJavaEllipticCurve(), g.toJavaECPoint(), n, ecDomainParameters.h.toInt()) + +val Curve.bcecParameterSpec: BCECParameterSpec + get() = toBCEllipticCurve().let { bcCurve -> BCECParameterSpec(bcCurve, g.toBCECPoint(bcCurve), n, ecDomainParameters.h) } diff --git a/ec/src/main/kotlin/io/provenance/hdwallet/ec/JavaKeys.kt b/ec/src/main/kotlin/io/provenance/hdwallet/ec/JavaKeys.kt index 799ad7f..edece97 100644 --- a/ec/src/main/kotlin/io/provenance/hdwallet/ec/JavaKeys.kt +++ b/ec/src/main/kotlin/io/provenance/hdwallet/ec/JavaKeys.kt @@ -3,7 +3,10 @@ package io.provenance.hdwallet.ec import io.provenance.hdwallet.ec.bc.toCurvePoint import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey +import org.bouncycastle.jce.ECNamedCurveTable import org.bouncycastle.jce.spec.ECParameterSpec +import org.bouncycastle.jce.spec.ECPrivateKeySpec +import java.security.KeyFactory import java.security.PrivateKey as JavaPrivateKey import java.security.PublicKey as JavaPublicKey @@ -18,3 +21,8 @@ fun JavaPrivateKey.toECPrivateKey(): PrivateKey { val bcec = requireNotNull(this as? BCECPrivateKey) { "key type invalid" } return PrivateKey(bcec.d, bcec.parameters.toCurve()) } + +fun PrivateKey.toJavaPrivateKey(): JavaPrivateKey { + val keySpec = ECPrivateKeySpec(key, this.curve.bcecParameterSpec) + return KeyFactory.getInstance("EC").generatePrivate(keySpec) +} diff --git a/hdwallet/build.gradle.kts b/hdwallet/build.gradle.kts index af62bf8..a540511 100644 --- a/hdwallet/build.gradle.kts +++ b/hdwallet/build.gradle.kts @@ -1,4 +1,4 @@ dependencies { listOf(":base58", ":bech32", ":bip32", ":bip39", ":bip44", ":common", ":ec", ":signer") - .map { implementation(project(it)) } + .map { api(project(it)) } }