Skip to content

Commit 5f2fcdc

Browse files
committed
DKG, distributed public key restore
1 parent 7f4b681 commit 5f2fcdc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+850
-113
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package org.exploit.keeper.api
2+
3+
import org.eclipse.jetty.http.HttpMethod
4+
import org.exploit.jettyx.annotation.HttpRequest
5+
import org.exploit.jettyx.annotation.Query
6+
import org.exploit.keeper.constant.CurveName
7+
import org.exploit.keeper.model.keygen.ShamirShareDto
8+
import java.util.concurrent.CompletableFuture
9+
10+
interface KeyGenApi {
11+
@HttpRequest(path = "/v1/keygen/init", method = HttpMethod.POST)
12+
fun init(@Query("keyId") keyId: String, @Query("curve") curve: CurveName, @Query("overwrite") overwrite: Boolean): CompletableFuture<Void>
13+
14+
@HttpRequest(path = "/v1/keygen/share", method = HttpMethod.GET)
15+
fun share(@Query("keyId") keyId: String): CompletableFuture<ShamirShareDto>
16+
17+
@HttpRequest(path = "/v1/keygen/collect", method = HttpMethod.POST)
18+
fun collect(@Query("keyId") keyId: String): CompletableFuture<Void>
19+
20+
@HttpRequest(path = "/v1/keygen/compute", method = HttpMethod.POST)
21+
fun compute(@Query("keyId") keyId: String): CompletableFuture<Void>
22+
23+
@HttpRequest(path = "/v1/keygen/abort", method = HttpMethod.POST)
24+
fun abort(@Query("keyId") keyId: String): CompletableFuture<Void>
25+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package org.exploit.keeper.api
2+
3+
import org.eclipse.jetty.http.HttpMethod
4+
import org.exploit.jettyx.annotation.HttpRequest
5+
import org.exploit.jettyx.annotation.Path
6+
import org.exploit.keeper.model.PublicKeyDto
7+
import java.util.concurrent.CompletableFuture
8+
9+
interface PublicKeyApi {
10+
@HttpRequest(method = HttpMethod.GET, path = "/v1/publicKey/{keyId}")
11+
fun getPublicKeyShare(@Path("keyId") keyId: String): CompletableFuture<PublicKeyDto>
12+
}

src/main/kotlin/org/exploit/keeper/api/client/BitKeeperClient.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ import org.exploit.crypto.Hash
44
import org.exploit.crypto.curve.Ed25519Provider
55
import org.exploit.crypto.key.ed25519.Ed25519PublicKey
66
import org.exploit.jettyx.Jettyx
7-
import org.exploit.keeper.api.CentralApi
8-
import org.exploit.keeper.api.FrostApi
9-
import org.exploit.keeper.api.GG20Api
7+
import org.exploit.keeper.api.*
108
import org.exploit.keeper.api.auth.KeeperAuthenticator
119
import org.exploit.keeper.extension.decodeBase64
1210
import org.exploit.keeper.extension.toSchnorrSignature
@@ -25,6 +23,14 @@ class BitKeeperClient(val peerId: Int, private val publicKey: Ed25519PublicKey,
2523
jettyx.newApiClient(url, auth).create(CentralApi::class.java)
2624
}
2725

26+
val keyGen: KeyGenApi by lazy {
27+
jettyx.newApiClient(url, auth).create(KeyGenApi::class.java)
28+
}
29+
30+
val public: PublicKeyApi by lazy {
31+
jettyx.newApiClient(url, auth).create(PublicKeyApi::class.java)
32+
}
33+
2834
fun verifySignature(signature: String, path: String, timestamp: Long): Boolean {
2935
try {
3036
if (System.currentTimeMillis() - timestamp > 30 * 1000)
Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
package org.exploit.keeper.constant
22

3-
enum class CurveName {
4-
SECP256K1,
5-
ED25519
3+
enum class CurveName(val id: Int) {
4+
SECP256K1(0x0),
5+
ED25519(0x1);
6+
7+
companion object {
8+
fun fromId(id: Int): CurveName {
9+
return entries.find { it.id == id } ?: throw IllegalArgumentException("Unknown curve ID: $id")
10+
}
11+
}
612
}

src/main/kotlin/org/exploit/keeper/constant/KeeperCurve.kt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,34 +13,34 @@ sealed class KeeperCurve<P : PointOps<P>>(
1313
val params: EllipticCurveParams<P>,
1414
val opsClass: KClass<P>
1515
) {
16-
data object SECP256K1 : KeeperCurve<ECPointOps>(
17-
ECCurveParams(SECNamedCurves.getByName("secp256k1")),
18-
ECPointOps::class
19-
) {
16+
data object SECP256K1 : KeeperCurve<ECPointOps>(ECCurveParams(SECNamedCurves.getByName("secp256k1")), ECPointOps::class) {
17+
override fun keySize(): Int = 32
18+
2019
override fun createPointOps(bytes: ByteArray): ECPointOps =
2120
ECPointOps((params as ECCurveParams).x9ECParameters.curve.decodePoint(bytes))
2221

2322
override val name: CurveName = CurveName.SECP256K1
2423
}
2524

26-
data object ED25519: KeeperCurve<Ed25519PointOps>(
27-
Ed25519CurveParams(),
28-
Ed25519PointOps::class
29-
) {
25+
data object ED25519: KeeperCurve<Ed25519PointOps>(Ed25519CurveParams(), Ed25519PointOps::class) {
26+
override fun keySize(): Int = 32
27+
3028
override fun createPointOps(bytes: ByteArray): Ed25519PointOps =
3129
Ed25519PointOps(bytes)
3230

3331
override val name: CurveName = CurveName.ED25519
3432
}
3533

34+
abstract fun keySize(): Int
35+
3636
abstract fun createPointOps(bytes: ByteArray): P
3737

3838
abstract val name: CurveName
3939

4040
companion object {
4141
private val _values = listOf(SECP256K1, ED25519)
4242

43-
fun fromName(name: CurveName): KeeperCurve<*> =
43+
fun <P: PointOps<P>> fromName(name: CurveName): KeeperCurve<*> =
4444
_values.firstOrNull { it.name == name}
4545
?: throw IllegalArgumentException("Unknown KeeperCurve name: $name")
4646
}

src/main/kotlin/org/exploit/keeper/controller/core/CentralController.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import jakarta.ws.rs.QueryParam
77
import jakarta.ws.rs.container.ContainerRequestContext
88
import org.exploit.keeper.constant.Permission
99
import org.exploit.keeper.exception.SealedException
10+
import org.exploit.keeper.extension.toUni
1011
import org.exploit.keeper.model.PublicKeyDto
1112
import org.exploit.keeper.service.auth.policy.MachinePolicyChecker
1213
import org.exploit.keeper.service.core.KeeperSealService
@@ -32,6 +33,6 @@ class CentralController(
3233

3334
policyChecker.ensureHasPermission(ctx, Permission.keyGetPublicKey(keyId))
3435

35-
return pub.getPublicKey(keyId)
36+
return pub.getPublicKey(keyId).toUni()
3637
}
3738
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.exploit.keeper.controller.key
2+
3+
import jakarta.ws.rs.GET
4+
import jakarta.ws.rs.Path
5+
import org.exploit.keeper.extension.toBase64
6+
import org.exploit.keeper.model.PublicKeyDto
7+
import org.exploit.keeper.service.pub.share.PublicKeyShareCalculator
8+
9+
@Path("/v1/publicKey")
10+
class PublicKeyController(private val pubShare: PublicKeyShareCalculator) {
11+
@GET
12+
@Path("/{keyId}")
13+
fun getPublicKey(keyId: String): PublicKeyDto =
14+
PublicKeyDto(pubShare.pubKeyShare(keyId).share.encode(true).toBase64())
15+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.exploit.keeper.controller.keygen
2+
3+
import io.smallrye.mutiny.Uni
4+
import jakarta.ws.rs.POST
5+
import jakarta.ws.rs.Path
6+
import org.exploit.keeper.constant.KeeperCurve
7+
import org.exploit.keeper.model.request.Generate
8+
import org.exploit.keeper.service.keygen.starter.DKGenerator
9+
10+
@Path("/v1/keeper/dkg")
11+
class KeyGenController(private val dkg: DKGenerator) {
12+
@POST
13+
@Path("/generate")
14+
fun generate(body: Generate): Uni<Void> {
15+
return dkg.generateKey(
16+
keyId = body.keyId,
17+
curve = KeeperCurve.fromName(body.curve),
18+
overwrite = body.overwrite
19+
)
20+
}
21+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package org.exploit.keeper.controller.keygen
2+
3+
import io.smallrye.mutiny.Uni
4+
import jakarta.ws.rs.*
5+
import org.exploit.keeper.api.auth.KeeperAuthenticator
6+
import org.exploit.keeper.constant.CurveName
7+
import org.exploit.keeper.constant.KeeperCurve
8+
import org.exploit.keeper.extension.toUni
9+
import org.exploit.keeper.model.keygen.ShamirShareDto
10+
import org.exploit.keeper.service.keygen.DistributedKeyCollector
11+
import org.exploit.keeper.service.keygen.DistributedKeyGen
12+
13+
@Path("/v1/keygen")
14+
class SystemKeyGenController(
15+
private val generator: DistributedKeyGen,
16+
private val collector: DistributedKeyCollector
17+
) {
18+
@POST
19+
@Path("/init")
20+
fun init(
21+
@QueryParam("keyId") keyId: String,
22+
@QueryParam("curve") curve: CurveName,
23+
@QueryParam("overwrite") overwrite: Boolean
24+
) {
25+
generator.init(keyId, KeeperCurve.fromName(curve), overwrite)
26+
}
27+
28+
@POST
29+
@Path("/collect")
30+
fun collect(@QueryParam("keyId") keyId: String): Uni<Void> =
31+
collector.collect(keyId).toUni()
32+
33+
@POST
34+
@Path("/compute")
35+
fun compute(@QueryParam("keyId") keyId: String) {
36+
generator.compute(keyId)
37+
}
38+
39+
@POST
40+
@Path("/abort")
41+
fun abort(@QueryParam("keyId") sessionId: String) {
42+
generator.abort(sessionId)
43+
}
44+
45+
@GET
46+
@Path("/share")
47+
fun share(
48+
@QueryParam("keyId") keyId: String,
49+
@HeaderParam(KeeperAuthenticator.HEADER_INSTANCE_ID) peerId: Int
50+
): ShamirShareDto =
51+
generator.share(peerId, keyId)
52+
}

src/main/kotlin/org/exploit/keeper/controller/signature/FrostController.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,12 @@ class FrostController(
2424
@POST
2525
@Path("/init")
2626
fun init(body: InitSession) {
27-
sessionFactory.createSession(body.sessionId, body.keyId, body.operations.unwrap(), body.participants,
27+
sessionFactory.createSession(
28+
body.sessionId,
29+
body.keyId,
30+
body.operations.unwrap(),
31+
body.publicKey,
32+
body.participants,
2833
KeeperCurve.fromName(body.curve))
2934
}
3035

0 commit comments

Comments
 (0)