keygen

abstract suspend fun keygen(): Result<ByteArray>

Generates a new distributed keyshare through three-party MPC.

Creates a 2-of-3 threshold key where any two parties can sign, but no single party knows the complete private key.

Important: Keygen internally performs reconciliation (the after-part) automatically, transitioning the keyshare from "staged" to "current/active" state. However, if the reconciliation step fails due to network interruption or crash, you can retry it manually using reconcileKeyshare without redoing the entire expensive MPC operation.

When to use standalone reconciliation: Only needed if keygen completes but the after-part fails. The keyshare will be in "staged" state and you can complete it later.

Example: Normal Successful Flow (No Manual Reconciliation Needed)

// Keygen automatically reconciles internally - keyshare is ready to use
val keyshare = session.keygen().getOrThrow()

// Get key ID
val keyId = getKeyshareKeyId(keyshare)
.getOrThrow()
.toHexString()

// Derive address and start using immediately
val publicKey = getKeysharePublicKey(keyshare).getOrThrow()
val address = deriveAddressFromPublicKey(publicKey)

// Store and use
secureStorage.save("keyshare_$keyId", keyshare)
println("Wallet created with address: $address")

Example: Recovery Scenario (Manual Reconciliation Needed)

// Keygen completes successfully (internally reconciled)
val keyshare = session.keygen().getOrThrow()

// Normal flow - keyshare is ready to use
val publicKey = getKeysharePublicKey(keyshare).getOrThrow()

// If app crashes before completion, on restart:
// Check storage for any staged keyshares
suspend fun checkForIncompleteOperations(
storageClient: StorageClient<ReconcileStoreDao>
) {
// User provides keyId of their last operation
val keyId = getLastAttemptedKeyId() // from your app state

val dao = storageClient.read(keyId)

if (dao?.stagedKeyshare != null && dao.currentKeyshare == null) {
// Found incomplete reconciliation - retry
println("Retrying reconciliation for $keyId...")
val reconciledKeyshare = session.reconcileKeyshare(keyId).getOrThrow()
println("Reconciliation complete!")
}
}

Example: HD Wallet with Multiple Accounts

// Generate master keyshare (internally reconciled)
val keyshare = session.keygen().getOrThrow()

// Derive multiple accounts using different paths
val accounts = (0..4).map { index ->
val childKey = deriveChildPublicKey(
keyshare = keyshare,
derivationPath = "m/44'/X'/0'/0/$index" // X = your coin type
).getOrThrow()

Account(
index = index,
address = deriveAddressFromPublicKey(childKey),
path = "m/44'/X'/0'/0/$index"
)
}

accounts.forEach { println("Account ${it.index}: ${it.address}") }

Return

Result containing the generated keyshare as ByteArray

See also

for retry scenarios only