Skip to content

Commit

Permalink
js EdHDKey + external
Browse files Browse the repository at this point in the history
  • Loading branch information
curtis-h committed Apr 18, 2024
1 parent 4eb0600 commit de2a13b
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 11 deletions.
@@ -1,19 +1,13 @@
package io.iohk.atala.prism.apollo.derivation

import com.ionspin.kotlin.bignum.integer.BigInteger
import com.ionspin.kotlin.bignum.integer.toBigInteger
import ed25519_bip32.XPrvWrapper
import io.iohk.atala.prism.apollo.utils.ECConfig
import kotlin.js.ExperimentalJsExport
import kotlin.js.JsExport
import kotlin.js.JsName


/**
* Represents and HDKey with its derive methods
*/
@OptIn(ExperimentalJsExport::class)
@JsExport
class EdHDKey(
val privateKey: ByteArray,
val chainCode: ByteArray,
Expand All @@ -22,15 +16,11 @@ class EdHDKey(
val index: BigIntegerWrapper = BigIntegerWrapper(0)
) {
/**
* Constructs a new EdHDKey object from a seed, depth, and child index.
* Constructs a new EdHDKey object from a seed
*
* @param seed The seed used to derive the private key and chain code.
* @param depth The depth of the HDKey.
* @param childIndex The child index of the HDKey.
*
* @throws IllegalArgumentException if the seed length is not equal to 64.
*/

fun initFromSeed(seed: ByteArray): EdHDKey {
require(seed.size == 64) {
"Seed expected byte length to be ${ECConfig.PRIVATE_KEY_BYTE_SIZE}"
Expand Down
@@ -0,0 +1,88 @@
package io.iohk.atala.prism.apollo.derivation

import com.ionspin.kotlin.bignum.integer.toBigInteger
import io.iohk.atala.prism.apollo.utils.ECConfig
import io.iohk.atala.prism.apollo.utils.external.ed25519_bip32

/**
* Represents and HDKey with its derive methods
*/
@OptIn(ExperimentalJsExport::class)
@JsExport
class EdHDKey(
val privateKey: ByteArray,
val chainCode: ByteArray,
val publicKey: ByteArray? = null,
val depth: Int = 0,
val index: BigIntegerWrapper = BigIntegerWrapper(0)
) {
/**
* Constructs a new EdHDKey object from a seed
*
* @param seed The seed used to derive the private key and chain code.
* @throws IllegalArgumentException if the seed length is not equal to 64.
*/
fun initFromSeed(seed: ByteArray): EdHDKey {
require(seed.size == 64) {
"Seed expected byte length to be ${ECConfig.PRIVATE_KEY_BYTE_SIZE}"
}

val key = seed.sliceArray(0 until 32)
val chainCode = seed.sliceArray(32 until seed.size)
val wrapper = ed25519_bip32.XPrvWrapper.from_nonextended_noforce(key, chainCode)

return EdHDKey(
privateKey = wrapper.extended_secret_key(),
chainCode = wrapper.chain_code(),
)
}

/**
* Method to derive an HDKey by a path
*
* @param path value used to derive a key
*/
fun derive(path: String): EdHDKey {
if (!path.matches(Regex("^[mM].*"))) {
throw Error("Path must start with \"m\" or \"M\"")
}
if (Regex("^[mM]'?$").matches(path)) {
return this
}
val parts = path.replace(Regex("^[mM]'?/"), "").split("/")
var child = this

for (c in parts) {
val m = Regex("^(\\d+)('?)$").find(c)?.groupValues
if (m == null || m.size != 3) {
throw Error("Invalid child index: $c")
}
val idx = m[1].toBigInteger()
if (idx >= HDKey.HARDENED_OFFSET) {
throw Error("Invalid index")
}
val finalIdx = if (m[2] == "'") idx + HDKey.HARDENED_OFFSET else idx

child = child.deriveChild(BigIntegerWrapper(finalIdx))
}

return child
}

/**
* Method to derive an HDKey child by index
*
* @param index value used to derive a key
*/
fun deriveChild(wrappedIndex: BigIntegerWrapper): EdHDKey {
val wrapper = ed25519_bip32.XPrvWrapper.from_extended_and_chaincode(privateKey, chainCode)
val derived = wrapper.derive(wrappedIndex.value.uintValue())

return EdHDKey(
privateKey = derived.extended_secret_key(),
chainCode = derived.chain_code(),
depth = depth + 1,
index = wrappedIndex
)
}
}
@@ -0,0 +1,22 @@
package io.iohk.atala.prism.apollo.utils.external

external interface XPrvWrapper {
fun public(): ByteArray

fun derive(index: Any): XPrvWrapper

fun extended_secret_key(): ByteArray

fun chain_code(): ByteArray

var from_nonextended_noforce: (js_bytes: ByteArray, js_chain_code: ByteArray) -> XPrvWrapper

var from_extended_and_chaincode: (js_bytes: ByteArray, js_chain_code: ByteArray) -> XPrvWrapper
}

external interface ed25519_bip32_export {
var XPrvWrapper: XPrvWrapper
}

@JsModule("ed25519_bip32_export")
external val ed25519_bip32: ed25519_bip32_export

0 comments on commit de2a13b

Please sign in to comment.