From b695a869ed7abfc08f9e61a6fbd0506f678b0a23 Mon Sep 17 00:00:00 2001 From: Rafal Wesolowski Date: Thu, 3 Nov 2022 17:36:24 +0100 Subject: [PATCH 1/5] CAP-26 - Two default and one custom derivation path implemented. --- src/main/kotlin/com/radixdlt/bip44/BIP44.kt | 11 +++ .../derivation/AccountHDDerivationPath.kt | 35 +++++++++ .../derivation/CustomHDDerivationPath.kt | 24 +++++++ .../derivation/IdentityHDDerivationPath.kt | 36 ++++++++++ .../com/radixdlt/derivation/model/CoinType.kt | 8 +++ .../radixdlt/derivation/model/EntityType.kt | 6 ++ .../com/radixdlt/derivation/model/KeyType.kt | 9 +++ .../radixdlt/derivation/model/NetworkId.kt | 12 ++++ .../kotlin/com/radixdlt/bip44/BIP44Test.kt | 43 +++++++++++ .../derivation/AccountHDDerivationPathTest.kt | 53 ++++++++++++++ .../derivation/CustomHDDerivationPathTest.kt | 71 +++++++++++++++++++ .../IdentityHDDerivationPathTest.kt | 53 ++++++++++++++ 12 files changed, 361 insertions(+) create mode 100644 src/main/kotlin/com/radixdlt/derivation/AccountHDDerivationPath.kt create mode 100644 src/main/kotlin/com/radixdlt/derivation/CustomHDDerivationPath.kt create mode 100644 src/main/kotlin/com/radixdlt/derivation/IdentityHDDerivationPath.kt create mode 100644 src/main/kotlin/com/radixdlt/derivation/model/CoinType.kt create mode 100644 src/main/kotlin/com/radixdlt/derivation/model/EntityType.kt create mode 100644 src/main/kotlin/com/radixdlt/derivation/model/KeyType.kt create mode 100644 src/main/kotlin/com/radixdlt/derivation/model/NetworkId.kt create mode 100644 src/test/kotlin/com/radixdlt/derivation/AccountHDDerivationPathTest.kt create mode 100644 src/test/kotlin/com/radixdlt/derivation/CustomHDDerivationPathTest.kt create mode 100644 src/test/kotlin/com/radixdlt/derivation/IdentityHDDerivationPathTest.kt diff --git a/src/main/kotlin/com/radixdlt/bip44/BIP44.kt b/src/main/kotlin/com/radixdlt/bip44/BIP44.kt index 39cbc65..74a3c2c 100644 --- a/src/main/kotlin/com/radixdlt/bip44/BIP44.kt +++ b/src/main/kotlin/com/radixdlt/bip44/BIP44.kt @@ -16,6 +16,7 @@ private fun getEnsuredCleanPath(path: String): String { data class BIP44Element(val hardened: Boolean, val number: Int) { val numberWithHardeningFlag = if (hardened) number or BIP44_HARDENING_FLAG else number + val numberFormatted: String = if (hardened) "$number'" else number.toString() } data class BIP44(val path: List) { @@ -44,4 +45,14 @@ data class BIP44(val path: List) { fun increment() = BIP44(path.subList(0, path.size - 1) + path.last().let { BIP44Element(it.hardened, it.number + 1) }) + + fun customDerivationPath(): String { + if (path.isEmpty()) return "" + return path.joinToString( + prefix = "/", + separator = "/" + ) { bip44Element -> + bip44Element.numberFormatted + } + } } diff --git a/src/main/kotlin/com/radixdlt/derivation/AccountHDDerivationPath.kt b/src/main/kotlin/com/radixdlt/derivation/AccountHDDerivationPath.kt new file mode 100644 index 0000000..eab2b5a --- /dev/null +++ b/src/main/kotlin/com/radixdlt/derivation/AccountHDDerivationPath.kt @@ -0,0 +1,35 @@ +package com.radixdlt.derivation + +import com.radixdlt.bip44.BIP44_PREFIX +import com.radixdlt.derivation.model.CoinType +import com.radixdlt.derivation.model.EntityType +import com.radixdlt.derivation.model.KeyType +import com.radixdlt.derivation.model.NetworkId + +/** + * The **default** derivation path used to derive `Account` keys for signing off transactions or for signing authentication, at a certain account index (`ENTITY_INDEX`) + * and **unique per network** (`NETWORK_ID`) as per [CAP-26][cap26]. + * + * Note that users can choose to use custom derivation path instead of this default + * one when deriving keys for accounts. + * + * The format is: + * `m/44'/1022'/'/525'/'/'` + * + * Where `'` denotes hardened path, which is **required** as per [SLIP-10][slip10]. + * where `525` is ASCII sum of `"ACCOUNT"`, i.e. `"ACCOUNT".map{ $0.asciiValue! }.reduce(0, +)` + * + * [cap26]: https://radixdlt.atlassian.net/l/cp/UNaBAGUC + * [slip10]: https://github.com/satoshilabs/slips/blob/master/slip-0010.md + */ +data class AccountHDDerivationPath( + private val networkId: NetworkId, + private val accountIndex: Int, + private val keyType: KeyType +) { + private val coinType: CoinType = CoinType.RadixDlt + private val entityType: EntityType = EntityType.Account + + val path: String + get() = "$BIP44_PREFIX/44'/${coinType.value}'/${networkId.value}'/${entityType.value}'/${accountIndex}'/${keyType.value}'" +} \ No newline at end of file diff --git a/src/main/kotlin/com/radixdlt/derivation/CustomHDDerivationPath.kt b/src/main/kotlin/com/radixdlt/derivation/CustomHDDerivationPath.kt new file mode 100644 index 0000000..1ebb311 --- /dev/null +++ b/src/main/kotlin/com/radixdlt/derivation/CustomHDDerivationPath.kt @@ -0,0 +1,24 @@ +package com.radixdlt.derivation + +import com.radixdlt.bip44.BIP44 +import com.radixdlt.bip44.BIP44_PREFIX +import com.radixdlt.derivation.model.CoinType + +/** + * A custom derivation path used to derive keys for whatever purpose. [CAP-26][cap26] states + * The format is: + * `m/44'/1022'` + * Where `'` denotes hardened path, which is **required** as per [SLIP-10][slip10]. + * [cap26]: https://radixdlt.atlassian.net/l/cp/UNaBAGUC + * [slip10]: https://github.com/satoshilabs/slips/blob/master/slip-0010.md + */ +data class CustomHDDerivationPath( + val bip44: BIP44 +) { + + private val coinType: CoinType = CoinType.RadixDlt + + val path: String + get() = "$BIP44_PREFIX/44'/${coinType.value}'${bip44.customDerivationPath()}" + +} diff --git a/src/main/kotlin/com/radixdlt/derivation/IdentityHDDerivationPath.kt b/src/main/kotlin/com/radixdlt/derivation/IdentityHDDerivationPath.kt new file mode 100644 index 0000000..e567dbb --- /dev/null +++ b/src/main/kotlin/com/radixdlt/derivation/IdentityHDDerivationPath.kt @@ -0,0 +1,36 @@ +package com.radixdlt.derivation + +import com.radixdlt.bip44.BIP44_PREFIX +import com.radixdlt.derivation.model.CoinType +import com.radixdlt.derivation.model.EntityType +import com.radixdlt.derivation.model.KeyType +import com.radixdlt.derivation.model.NetworkId + +/** + * The **default** derivation path used to derive `Identity` (Persona) keys for signing authentication, + * at a certain (Persona) index (`ENTITY_INDEX`) and **unique per network** (`NETWORK_ID`) as per [CAP-26][cap26]. + * + * Note that users can choose to use custom derivation path instead of this default one + * when deriving keys for identities (personas). + * + * The format is: + * `m/44'/1022'/'/618'/'/'` + * + * Where `'` denotes hardened path, which is **required** as per [SLIP-10][slip10]. + * where `618` is ASCII sum of `"IDENTITY"`, i.e. `"IDENTITY".map{ $0.asciiValue! }.reduce(0, +)` + * + * [cap26]: https://radixdlt.atlassian.net/l/cp/UNaBAGUC + * [slip10]: https://github.com/satoshilabs/slips/blob/master/slip-0010.md + */ +data class IdentityHDDerivationPath( + private val networkId: NetworkId, + private val identityIndex: Int, + private val keyType: KeyType +) { + private val coinType: CoinType = CoinType.RadixDlt + private val entityType: EntityType = EntityType.Identity + + val path: String + get() = "$BIP44_PREFIX/44'/${coinType.value}'/${networkId.value}'/${entityType.value}'/${identityIndex}'/${keyType.value}'" + +} \ No newline at end of file diff --git a/src/main/kotlin/com/radixdlt/derivation/model/CoinType.kt b/src/main/kotlin/com/radixdlt/derivation/model/CoinType.kt new file mode 100644 index 0000000..19f4d35 --- /dev/null +++ b/src/main/kotlin/com/radixdlt/derivation/model/CoinType.kt @@ -0,0 +1,8 @@ +package com.radixdlt.derivation.model + +/** + * Currently we only support Radix coin which is documented here -> https://github.com/satoshilabs/slips/pull/1137 + */ +sealed class CoinType(val value: Int) { + object RadixDlt : CoinType(1022) +} diff --git a/src/main/kotlin/com/radixdlt/derivation/model/EntityType.kt b/src/main/kotlin/com/radixdlt/derivation/model/EntityType.kt new file mode 100644 index 0000000..084ee5c --- /dev/null +++ b/src/main/kotlin/com/radixdlt/derivation/model/EntityType.kt @@ -0,0 +1,6 @@ +package com.radixdlt.derivation.model + +sealed class EntityType(val value: Int) { + object Account : EntityType(525) + object Identity : EntityType(618) +} diff --git a/src/main/kotlin/com/radixdlt/derivation/model/KeyType.kt b/src/main/kotlin/com/radixdlt/derivation/model/KeyType.kt new file mode 100644 index 0000000..57e0002 --- /dev/null +++ b/src/main/kotlin/com/radixdlt/derivation/model/KeyType.kt @@ -0,0 +1,9 @@ +package com.radixdlt.derivation.model + +sealed class KeyType(val value: Int) { + // Key to be used for signing transactions. + object SignTransaction : KeyType(1238) + + // Key to be used for signing authentication. + object SignAuth : KeyType(706) +} \ No newline at end of file diff --git a/src/main/kotlin/com/radixdlt/derivation/model/NetworkId.kt b/src/main/kotlin/com/radixdlt/derivation/model/NetworkId.kt new file mode 100644 index 0000000..d9dd1d2 --- /dev/null +++ b/src/main/kotlin/com/radixdlt/derivation/model/NetworkId.kt @@ -0,0 +1,12 @@ +package com.radixdlt.derivation.model + +/** + * Full list of networks is documented here -> https://github.com/radixdlt/babylon-node/blob/ + * f3e3b262f7b7610dcd3bf42f6e98009c0444c8c4/common/src/main/java/com/radixdlt/networks/Network.java + */ +sealed class NetworkId(val value: Int) { + object Mainnet : NetworkId(1) + object Stokenet : NetworkId(2) + object Aplhanet : NetworkId(10) + object Betanet : NetworkId(11) +} \ No newline at end of file diff --git a/src/test/kotlin/com/radixdlt/bip44/BIP44Test.kt b/src/test/kotlin/com/radixdlt/bip44/BIP44Test.kt index f0f625b..d005029 100644 --- a/src/test/kotlin/com/radixdlt/bip44/BIP44Test.kt +++ b/src/test/kotlin/com/radixdlt/bip44/BIP44Test.kt @@ -3,6 +3,7 @@ package com.radixdlt.bip44 import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Assertions.assertThrows import org.junit.jupiter.api.Test +import kotlin.test.assertEquals class BIP44Test { @@ -79,4 +80,46 @@ class BIP44Test { assertThat(BIP44("m/0/1/2").increment()) .isEqualTo(BIP44("m/0/1/3")) } + + @Test + fun verifyHardenedDerivationPath() { + val bip44 = BIP44( + path = listOf( + BIP44Element( + hardened = true, + number = 10 + ), + BIP44Element( + hardened = true, + number = 20 + ), + BIP44Element( + hardened = true, + number = 30 + ) + ) + ) + assertEquals(bip44.customDerivationPath(), "/10'/20'/30'") + } + + @Test + fun verifyUnhardenedDerivationPath() { + val bip44 = BIP44( + path = listOf( + BIP44Element( + hardened = false, + number = 10 + ), + BIP44Element( + hardened = false, + number = 20 + ), + BIP44Element( + hardened = false, + number = 30 + ) + ) + ) + assertEquals(bip44.customDerivationPath(), "/10/20/30") + } } \ No newline at end of file diff --git a/src/test/kotlin/com/radixdlt/derivation/AccountHDDerivationPathTest.kt b/src/test/kotlin/com/radixdlt/derivation/AccountHDDerivationPathTest.kt new file mode 100644 index 0000000..9942cfa --- /dev/null +++ b/src/test/kotlin/com/radixdlt/derivation/AccountHDDerivationPathTest.kt @@ -0,0 +1,53 @@ +package com.radixdlt.derivation + +import com.radixdlt.derivation.model.KeyType +import com.radixdlt.derivation.model.NetworkId +import org.junit.jupiter.api.Test +import kotlin.test.assertEquals + +class AccountHDDerivationPathTest { + + @Test + fun `verify account derivation path for mainnet at index 0 for signing authentication`() { + val accountHDDerivationPath = AccountHDDerivationPath( + networkId = NetworkId.Mainnet, + accountIndex = 0, + keyType = KeyType.SignAuth + ) + + assertEquals(accountHDDerivationPath.path, "m/44'/1022'/1'/525'/0'/706'") + } + + @Test + fun `verify account derivation path for betanet at index 0 for signing authentication`() { + val accountHDDerivationPath = AccountHDDerivationPath( + networkId = NetworkId.Betanet, + accountIndex = 0, + keyType = KeyType.SignAuth + ) + + assertEquals(accountHDDerivationPath.path, "m/44'/1022'/11'/525'/0'/706'") + } + + @Test + fun `verify account derivation path for betanet at index 1 for signing authentication`() { + val accountHDDerivationPath = AccountHDDerivationPath( + networkId = NetworkId.Betanet, + accountIndex = 1, + keyType = KeyType.SignAuth + ) + + assertEquals(accountHDDerivationPath.path, "m/44'/1022'/11'/525'/1'/706'") + } + + @Test + fun `verify account derivation path for betanet at index 1 for signing transaction`() { + val accountHDDerivationPath = AccountHDDerivationPath( + networkId = NetworkId.Betanet, + accountIndex = 1, + keyType = KeyType.SignTransaction + ) + + assertEquals(accountHDDerivationPath.path, "m/44'/1022'/11'/525'/1'/1238'") + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/radixdlt/derivation/CustomHDDerivationPathTest.kt b/src/test/kotlin/com/radixdlt/derivation/CustomHDDerivationPathTest.kt new file mode 100644 index 0000000..3526557 --- /dev/null +++ b/src/test/kotlin/com/radixdlt/derivation/CustomHDDerivationPathTest.kt @@ -0,0 +1,71 @@ +package com.radixdlt.derivation + +import com.radixdlt.bip44.BIP44 +import com.radixdlt.bip44.BIP44Element +import org.junit.jupiter.api.Test +import kotlin.test.assertEquals + +class CustomHDDerivationPathTest { + + @Test + fun `verify custom derivation path for 3 hardened bip44 elements`() { + val bip44 = BIP44( + path = listOf( + BIP44Element( + hardened = true, + number = 10 + ), + BIP44Element( + hardened = true, + number = 20 + ), + BIP44Element( + hardened = true, + number = 30 + ) + ) + ) + val customHDDerivationPath = CustomHDDerivationPath( + bip44 = bip44 + ) + + assertEquals(customHDDerivationPath.path, "m/44'/1022'/10'/20'/30'") + } + + @Test + fun `verify custom derivation path for 1 hardened bip44 elements out of 3`() { + val bip44 = BIP44( + path = listOf( + BIP44Element( + hardened = true, + number = 10 + ), + BIP44Element( + hardened = false, + number = 20 + ), + BIP44Element( + hardened = false, + number = 30 + ) + ) + ) + val customHDDerivationPath = CustomHDDerivationPath( + bip44 = bip44 + ) + + assertEquals(customHDDerivationPath.path, "m/44'/1022'/10'/20/30") + } + + @Test + fun `verify custom derivation path for no bip44 elements`() { + val bip44 = BIP44( + path = emptyList() + ) + val customHDDerivationPath = CustomHDDerivationPath( + bip44 = bip44 + ) + + assertEquals(customHDDerivationPath.path, "m/44'/1022'") + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/radixdlt/derivation/IdentityHDDerivationPathTest.kt b/src/test/kotlin/com/radixdlt/derivation/IdentityHDDerivationPathTest.kt new file mode 100644 index 0000000..4e152a4 --- /dev/null +++ b/src/test/kotlin/com/radixdlt/derivation/IdentityHDDerivationPathTest.kt @@ -0,0 +1,53 @@ +package com.radixdlt.derivation + +import com.radixdlt.derivation.model.KeyType +import com.radixdlt.derivation.model.NetworkId +import org.junit.jupiter.api.Test +import kotlin.test.assertEquals + +class IdentityHDDerivationPathTest { + + @Test + fun `verify identity derivation path for mainnet at index 0 for signing authentication`() { + val identityHDDerivationPath = IdentityHDDerivationPath( + networkId = NetworkId.Mainnet, + identityIndex = 0, + keyType = KeyType.SignAuth + ) + + assertEquals(identityHDDerivationPath.path, "m/44'/1022'/1'/618'/0'/706'") + } + + @Test + fun `verify identity derivation path for alphanet at index 0 for signing authentication`() { + val identityHDDerivationPath = IdentityHDDerivationPath( + networkId = NetworkId.Aplhanet, + identityIndex = 0, + keyType = KeyType.SignAuth + ) + + assertEquals(identityHDDerivationPath.path, "m/44'/1022'/10'/618'/0'/706'") + } + + @Test + fun `verify identity derivation path for mainnet at index 1 for signing authentication`() { + val identityHDDerivationPath = IdentityHDDerivationPath( + networkId = NetworkId.Mainnet, + identityIndex = 1, + keyType = KeyType.SignAuth + ) + + assertEquals(identityHDDerivationPath.path, "m/44'/1022'/1'/618'/1'/706'") + } + + @Test + fun `verify identity derivation path for mainnet at index 0 for signing transaction`() { + val identityHDDerivationPath = IdentityHDDerivationPath( + networkId = NetworkId.Mainnet, + identityIndex = 0, + keyType = KeyType.SignTransaction + ) + + assertEquals(identityHDDerivationPath.path, "m/44'/1022'/1'/618'/0'/1238'") + } +} \ No newline at end of file From 93e20338c02c658af8d5cd5d0383869a26604ffd Mon Sep 17 00:00:00 2001 From: Rafal Wesolowski Date: Thu, 3 Nov 2022 17:55:42 +0100 Subject: [PATCH 2/5] CAP-26 - Sealed classes replaced with enums. --- .../kotlin/com/radixdlt/derivation/model/CoinType.kt | 4 ++-- .../kotlin/com/radixdlt/derivation/model/EntityType.kt | 6 +++--- .../kotlin/com/radixdlt/derivation/model/KeyType.kt | 7 +++---- .../kotlin/com/radixdlt/derivation/model/NetworkId.kt | 10 +++++----- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/main/kotlin/com/radixdlt/derivation/model/CoinType.kt b/src/main/kotlin/com/radixdlt/derivation/model/CoinType.kt index 19f4d35..d50d078 100644 --- a/src/main/kotlin/com/radixdlt/derivation/model/CoinType.kt +++ b/src/main/kotlin/com/radixdlt/derivation/model/CoinType.kt @@ -3,6 +3,6 @@ package com.radixdlt.derivation.model /** * Currently we only support Radix coin which is documented here -> https://github.com/satoshilabs/slips/pull/1137 */ -sealed class CoinType(val value: Int) { - object RadixDlt : CoinType(1022) +enum class CoinType(val value: Int) { + RadixDlt(1022) } diff --git a/src/main/kotlin/com/radixdlt/derivation/model/EntityType.kt b/src/main/kotlin/com/radixdlt/derivation/model/EntityType.kt index 084ee5c..62d4210 100644 --- a/src/main/kotlin/com/radixdlt/derivation/model/EntityType.kt +++ b/src/main/kotlin/com/radixdlt/derivation/model/EntityType.kt @@ -1,6 +1,6 @@ package com.radixdlt.derivation.model -sealed class EntityType(val value: Int) { - object Account : EntityType(525) - object Identity : EntityType(618) +enum class EntityType(val value: Int) { + Account(525), + Identity(618) } diff --git a/src/main/kotlin/com/radixdlt/derivation/model/KeyType.kt b/src/main/kotlin/com/radixdlt/derivation/model/KeyType.kt index 57e0002..ab2eb2c 100644 --- a/src/main/kotlin/com/radixdlt/derivation/model/KeyType.kt +++ b/src/main/kotlin/com/radixdlt/derivation/model/KeyType.kt @@ -1,9 +1,8 @@ package com.radixdlt.derivation.model -sealed class KeyType(val value: Int) { +enum class KeyType(val value: Int) { // Key to be used for signing transactions. - object SignTransaction : KeyType(1238) - + SignTransaction(1238), // Key to be used for signing authentication. - object SignAuth : KeyType(706) + SignAuth(706) } \ No newline at end of file diff --git a/src/main/kotlin/com/radixdlt/derivation/model/NetworkId.kt b/src/main/kotlin/com/radixdlt/derivation/model/NetworkId.kt index d9dd1d2..381886f 100644 --- a/src/main/kotlin/com/radixdlt/derivation/model/NetworkId.kt +++ b/src/main/kotlin/com/radixdlt/derivation/model/NetworkId.kt @@ -4,9 +4,9 @@ package com.radixdlt.derivation.model * Full list of networks is documented here -> https://github.com/radixdlt/babylon-node/blob/ * f3e3b262f7b7610dcd3bf42f6e98009c0444c8c4/common/src/main/java/com/radixdlt/networks/Network.java */ -sealed class NetworkId(val value: Int) { - object Mainnet : NetworkId(1) - object Stokenet : NetworkId(2) - object Aplhanet : NetworkId(10) - object Betanet : NetworkId(11) +enum class NetworkId(val value: Int) { + Mainnet(1), + Stokenet(2), + Aplhanet(10), + Betanet(11), } \ No newline at end of file From 27de3a985cf920e04239d673123073d0e9479fde Mon Sep 17 00:00:00 2001 From: Rafal Wesolowski Date: Wed, 9 Nov 2022 10:11:31 +0100 Subject: [PATCH 3/5] CAP-26 - Links removed from the comments. --- .../kotlin/com/radixdlt/derivation/AccountHDDerivationPath.kt | 2 -- .../kotlin/com/radixdlt/derivation/CustomHDDerivationPath.kt | 2 -- .../kotlin/com/radixdlt/derivation/IdentityHDDerivationPath.kt | 2 -- 3 files changed, 6 deletions(-) diff --git a/src/main/kotlin/com/radixdlt/derivation/AccountHDDerivationPath.kt b/src/main/kotlin/com/radixdlt/derivation/AccountHDDerivationPath.kt index eab2b5a..be8a488 100644 --- a/src/main/kotlin/com/radixdlt/derivation/AccountHDDerivationPath.kt +++ b/src/main/kotlin/com/radixdlt/derivation/AccountHDDerivationPath.kt @@ -19,8 +19,6 @@ import com.radixdlt.derivation.model.NetworkId * Where `'` denotes hardened path, which is **required** as per [SLIP-10][slip10]. * where `525` is ASCII sum of `"ACCOUNT"`, i.e. `"ACCOUNT".map{ $0.asciiValue! }.reduce(0, +)` * - * [cap26]: https://radixdlt.atlassian.net/l/cp/UNaBAGUC - * [slip10]: https://github.com/satoshilabs/slips/blob/master/slip-0010.md */ data class AccountHDDerivationPath( private val networkId: NetworkId, diff --git a/src/main/kotlin/com/radixdlt/derivation/CustomHDDerivationPath.kt b/src/main/kotlin/com/radixdlt/derivation/CustomHDDerivationPath.kt index 1ebb311..d7c13f5 100644 --- a/src/main/kotlin/com/radixdlt/derivation/CustomHDDerivationPath.kt +++ b/src/main/kotlin/com/radixdlt/derivation/CustomHDDerivationPath.kt @@ -9,8 +9,6 @@ import com.radixdlt.derivation.model.CoinType * The format is: * `m/44'/1022'` * Where `'` denotes hardened path, which is **required** as per [SLIP-10][slip10]. - * [cap26]: https://radixdlt.atlassian.net/l/cp/UNaBAGUC - * [slip10]: https://github.com/satoshilabs/slips/blob/master/slip-0010.md */ data class CustomHDDerivationPath( val bip44: BIP44 diff --git a/src/main/kotlin/com/radixdlt/derivation/IdentityHDDerivationPath.kt b/src/main/kotlin/com/radixdlt/derivation/IdentityHDDerivationPath.kt index e567dbb..ee97450 100644 --- a/src/main/kotlin/com/radixdlt/derivation/IdentityHDDerivationPath.kt +++ b/src/main/kotlin/com/radixdlt/derivation/IdentityHDDerivationPath.kt @@ -19,8 +19,6 @@ import com.radixdlt.derivation.model.NetworkId * Where `'` denotes hardened path, which is **required** as per [SLIP-10][slip10]. * where `618` is ASCII sum of `"IDENTITY"`, i.e. `"IDENTITY".map{ $0.asciiValue! }.reduce(0, +)` * - * [cap26]: https://radixdlt.atlassian.net/l/cp/UNaBAGUC - * [slip10]: https://github.com/satoshilabs/slips/blob/master/slip-0010.md */ data class IdentityHDDerivationPath( private val networkId: NetworkId, From c01499b78ff4709df5adac04b32495dfe17353d3 Mon Sep 17 00:00:00 2001 From: Rafal Wesolowski Date: Tue, 15 Nov 2022 17:20:44 +0100 Subject: [PATCH 4/5] CAP-26 - Unneeded method removed. Renamings. --- src/main/kotlin/com/radixdlt/bip44/BIP44.kt | 10 ---------- .../com/radixdlt/derivation/CustomHDDerivationPath.kt | 2 +- .../kotlin/com/radixdlt/derivation/model/NetworkId.kt | 6 +++--- src/test/kotlin/com/radixdlt/bip44/BIP44Test.kt | 4 ++-- .../derivation/IdentityHDDerivationPathTest.kt | 2 +- 5 files changed, 7 insertions(+), 17 deletions(-) diff --git a/src/main/kotlin/com/radixdlt/bip44/BIP44.kt b/src/main/kotlin/com/radixdlt/bip44/BIP44.kt index 74a3c2c..406c5f4 100644 --- a/src/main/kotlin/com/radixdlt/bip44/BIP44.kt +++ b/src/main/kotlin/com/radixdlt/bip44/BIP44.kt @@ -16,7 +16,6 @@ private fun getEnsuredCleanPath(path: String): String { data class BIP44Element(val hardened: Boolean, val number: Int) { val numberWithHardeningFlag = if (hardened) number or BIP44_HARDENING_FLAG else number - val numberFormatted: String = if (hardened) "$number'" else number.toString() } data class BIP44(val path: List) { @@ -46,13 +45,4 @@ data class BIP44(val path: List) { fun increment() = BIP44(path.subList(0, path.size - 1) + path.last().let { BIP44Element(it.hardened, it.number + 1) }) - fun customDerivationPath(): String { - if (path.isEmpty()) return "" - return path.joinToString( - prefix = "/", - separator = "/" - ) { bip44Element -> - bip44Element.numberFormatted - } - } } diff --git a/src/main/kotlin/com/radixdlt/derivation/CustomHDDerivationPath.kt b/src/main/kotlin/com/radixdlt/derivation/CustomHDDerivationPath.kt index d7c13f5..93182c0 100644 --- a/src/main/kotlin/com/radixdlt/derivation/CustomHDDerivationPath.kt +++ b/src/main/kotlin/com/radixdlt/derivation/CustomHDDerivationPath.kt @@ -17,6 +17,6 @@ data class CustomHDDerivationPath( private val coinType: CoinType = CoinType.RadixDlt val path: String - get() = "$BIP44_PREFIX/44'/${coinType.value}'${bip44.customDerivationPath()}" + get() = "$BIP44_PREFIX/44'/${coinType.value}'${bip44}" } diff --git a/src/main/kotlin/com/radixdlt/derivation/model/NetworkId.kt b/src/main/kotlin/com/radixdlt/derivation/model/NetworkId.kt index 381886f..07ca8f6 100644 --- a/src/main/kotlin/com/radixdlt/derivation/model/NetworkId.kt +++ b/src/main/kotlin/com/radixdlt/derivation/model/NetworkId.kt @@ -1,12 +1,12 @@ package com.radixdlt.derivation.model /** - * Full list of networks is documented here -> https://github.com/radixdlt/babylon-node/blob/ - * f3e3b262f7b7610dcd3bf42f6e98009c0444c8c4/common/src/main/java/com/radixdlt/networks/Network.java + * Full list of networks is documented here -> https://github.com/radixdlt/babylon-node/blob/main/common/src/main/java + * /com/radixdlt/networks/Network.java */ enum class NetworkId(val value: Int) { Mainnet(1), Stokenet(2), - Aplhanet(10), + Alphanet(10), Betanet(11), } \ No newline at end of file diff --git a/src/test/kotlin/com/radixdlt/bip44/BIP44Test.kt b/src/test/kotlin/com/radixdlt/bip44/BIP44Test.kt index d005029..1299c68 100644 --- a/src/test/kotlin/com/radixdlt/bip44/BIP44Test.kt +++ b/src/test/kotlin/com/radixdlt/bip44/BIP44Test.kt @@ -99,7 +99,7 @@ class BIP44Test { ) ) ) - assertEquals(bip44.customDerivationPath(), "/10'/20'/30'") + assertEquals(bip44.toString(), "m/10'/20'/30'") } @Test @@ -120,6 +120,6 @@ class BIP44Test { ) ) ) - assertEquals(bip44.customDerivationPath(), "/10/20/30") + assertEquals(bip44.toString(), "m/10/20/30") } } \ No newline at end of file diff --git a/src/test/kotlin/com/radixdlt/derivation/IdentityHDDerivationPathTest.kt b/src/test/kotlin/com/radixdlt/derivation/IdentityHDDerivationPathTest.kt index 4e152a4..adabf84 100644 --- a/src/test/kotlin/com/radixdlt/derivation/IdentityHDDerivationPathTest.kt +++ b/src/test/kotlin/com/radixdlt/derivation/IdentityHDDerivationPathTest.kt @@ -21,7 +21,7 @@ class IdentityHDDerivationPathTest { @Test fun `verify identity derivation path for alphanet at index 0 for signing authentication`() { val identityHDDerivationPath = IdentityHDDerivationPath( - networkId = NetworkId.Aplhanet, + networkId = NetworkId.Alphanet, identityIndex = 0, keyType = KeyType.SignAuth ) From 9f1f1cd83f0144a3489ee51875e3ec937bb8c993 Mon Sep 17 00:00:00 2001 From: Rafal Wesolowski Date: Wed, 16 Nov 2022 12:48:07 +0100 Subject: [PATCH 5/5] CAP-26 - Network names changed. Added sanity check on custom derivation path. Unit tests fixed. --- .../derivation/CustomHDDerivationPath.kt | 9 +++++-- .../radixdlt/derivation/model/NetworkId.kt | 5 ++-- .../derivation/AccountHDDerivationPathTest.kt | 12 +++++----- .../derivation/CustomHDDerivationPathTest.kt | 24 +++++++++++++++---- .../IdentityHDDerivationPathTest.kt | 2 +- 5 files changed, 35 insertions(+), 17 deletions(-) diff --git a/src/main/kotlin/com/radixdlt/derivation/CustomHDDerivationPath.kt b/src/main/kotlin/com/radixdlt/derivation/CustomHDDerivationPath.kt index 93182c0..c526edd 100644 --- a/src/main/kotlin/com/radixdlt/derivation/CustomHDDerivationPath.kt +++ b/src/main/kotlin/com/radixdlt/derivation/CustomHDDerivationPath.kt @@ -13,10 +13,15 @@ import com.radixdlt.derivation.model.CoinType data class CustomHDDerivationPath( val bip44: BIP44 ) { - private val coinType: CoinType = CoinType.RadixDlt + /** + * Check if path starts with m/44'/1022' (hardened or not). Otherwise throw exception + */ val path: String - get() = "$BIP44_PREFIX/44'/${coinType.value}'${bip44}" + get() = if ( + bip44.toString().startsWith("$BIP44_PREFIX/44'/${coinType.value}") || + bip44.toString().startsWith("$BIP44_PREFIX/44/${coinType.value}") + ) bip44.toString() else throw IllegalArgumentException("Invalid derivation path") } diff --git a/src/main/kotlin/com/radixdlt/derivation/model/NetworkId.kt b/src/main/kotlin/com/radixdlt/derivation/model/NetworkId.kt index 07ca8f6..516609b 100644 --- a/src/main/kotlin/com/radixdlt/derivation/model/NetworkId.kt +++ b/src/main/kotlin/com/radixdlt/derivation/model/NetworkId.kt @@ -6,7 +6,6 @@ package com.radixdlt.derivation.model */ enum class NetworkId(val value: Int) { Mainnet(1), - Stokenet(2), - Alphanet(10), - Betanet(11), + Adapanet(10), + Enkinet(33) } \ No newline at end of file diff --git a/src/test/kotlin/com/radixdlt/derivation/AccountHDDerivationPathTest.kt b/src/test/kotlin/com/radixdlt/derivation/AccountHDDerivationPathTest.kt index 9942cfa..4bfe8f6 100644 --- a/src/test/kotlin/com/radixdlt/derivation/AccountHDDerivationPathTest.kt +++ b/src/test/kotlin/com/radixdlt/derivation/AccountHDDerivationPathTest.kt @@ -21,33 +21,33 @@ class AccountHDDerivationPathTest { @Test fun `verify account derivation path for betanet at index 0 for signing authentication`() { val accountHDDerivationPath = AccountHDDerivationPath( - networkId = NetworkId.Betanet, + networkId = NetworkId.Adapanet, accountIndex = 0, keyType = KeyType.SignAuth ) - assertEquals(accountHDDerivationPath.path, "m/44'/1022'/11'/525'/0'/706'") + assertEquals(accountHDDerivationPath.path, "m/44'/1022'/10'/525'/0'/706'") } @Test fun `verify account derivation path for betanet at index 1 for signing authentication`() { val accountHDDerivationPath = AccountHDDerivationPath( - networkId = NetworkId.Betanet, + networkId = NetworkId.Adapanet, accountIndex = 1, keyType = KeyType.SignAuth ) - assertEquals(accountHDDerivationPath.path, "m/44'/1022'/11'/525'/1'/706'") + assertEquals(accountHDDerivationPath.path, "m/44'/1022'/10'/525'/1'/706'") } @Test fun `verify account derivation path for betanet at index 1 for signing transaction`() { val accountHDDerivationPath = AccountHDDerivationPath( - networkId = NetworkId.Betanet, + networkId = NetworkId.Adapanet, accountIndex = 1, keyType = KeyType.SignTransaction ) - assertEquals(accountHDDerivationPath.path, "m/44'/1022'/11'/525'/1'/1238'") + assertEquals(accountHDDerivationPath.path, "m/44'/1022'/10'/525'/1'/1238'") } } \ No newline at end of file diff --git a/src/test/kotlin/com/radixdlt/derivation/CustomHDDerivationPathTest.kt b/src/test/kotlin/com/radixdlt/derivation/CustomHDDerivationPathTest.kt index 3526557..41c874a 100644 --- a/src/test/kotlin/com/radixdlt/derivation/CustomHDDerivationPathTest.kt +++ b/src/test/kotlin/com/radixdlt/derivation/CustomHDDerivationPathTest.kt @@ -2,6 +2,9 @@ package com.radixdlt.derivation import com.radixdlt.bip44.BIP44 import com.radixdlt.bip44.BIP44Element +import com.radixdlt.derivation.model.CoinType +import org.assertj.core.api.Assertions +import org.junit.jupiter.api.Assertions.assertThrows import org.junit.jupiter.api.Test import kotlin.test.assertEquals @@ -11,6 +14,14 @@ class CustomHDDerivationPathTest { fun `verify custom derivation path for 3 hardened bip44 elements`() { val bip44 = BIP44( path = listOf( + BIP44Element( + hardened = true, + number = 44 + ), + BIP44Element( + hardened = true, + number = CoinType.RadixDlt.value + ), BIP44Element( hardened = true, number = 10 @@ -33,7 +44,7 @@ class CustomHDDerivationPathTest { } @Test - fun `verify custom derivation path for 1 hardened bip44 elements out of 3`() { + fun `verify invalid custom derivation path without radix coin`() { val bip44 = BIP44( path = listOf( BIP44Element( @@ -53,12 +64,13 @@ class CustomHDDerivationPathTest { val customHDDerivationPath = CustomHDDerivationPath( bip44 = bip44 ) - - assertEquals(customHDDerivationPath.path, "m/44'/1022'/10'/20/30") + assertThrows(IllegalArgumentException::class.java) { + customHDDerivationPath.path + } } @Test - fun `verify custom derivation path for no bip44 elements`() { + fun `verify empty custom derivation path for no bip44 elements`() { val bip44 = BIP44( path = emptyList() ) @@ -66,6 +78,8 @@ class CustomHDDerivationPathTest { bip44 = bip44 ) - assertEquals(customHDDerivationPath.path, "m/44'/1022'") + assertThrows(IllegalArgumentException::class.java) { + customHDDerivationPath.path + } } } \ No newline at end of file diff --git a/src/test/kotlin/com/radixdlt/derivation/IdentityHDDerivationPathTest.kt b/src/test/kotlin/com/radixdlt/derivation/IdentityHDDerivationPathTest.kt index adabf84..d75b97e 100644 --- a/src/test/kotlin/com/radixdlt/derivation/IdentityHDDerivationPathTest.kt +++ b/src/test/kotlin/com/radixdlt/derivation/IdentityHDDerivationPathTest.kt @@ -21,7 +21,7 @@ class IdentityHDDerivationPathTest { @Test fun `verify identity derivation path for alphanet at index 0 for signing authentication`() { val identityHDDerivationPath = IdentityHDDerivationPath( - networkId = NetworkId.Alphanet, + networkId = NetworkId.Adapanet, identityIndex = 0, keyType = KeyType.SignAuth )