-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from radixdlt/feature/cap26
CAP-26 - Two default and one custom derivation path implemented.
- Loading branch information
Showing
12 changed files
with
362 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 33 additions & 0 deletions
33
src/main/kotlin/com/radixdlt/derivation/AccountHDDerivationPath.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
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'/<NETWORK_ID>'/525'/<ENTITY_INDEX>'/<KEY_TYPE>'` | ||
* | ||
* 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, +)` | ||
* | ||
*/ | ||
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}'" | ||
} |
27 changes: 27 additions & 0 deletions
27
src/main/kotlin/com/radixdlt/derivation/CustomHDDerivationPath.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
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]. | ||
*/ | ||
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() = 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") | ||
|
||
} |
34 changes: 34 additions & 0 deletions
34
src/main/kotlin/com/radixdlt/derivation/IdentityHDDerivationPath.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
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'/<NETWORK_ID>'/618'/<ENTITY_INDEX>'/<KEY_TYPE>'` | ||
* | ||
* 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, +)` | ||
* | ||
*/ | ||
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}'" | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
*/ | ||
enum class CoinType(val value: Int) { | ||
RadixDlt(1022) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.radixdlt.derivation.model | ||
|
||
enum class EntityType(val value: Int) { | ||
Account(525), | ||
Identity(618) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.radixdlt.derivation.model | ||
|
||
enum class KeyType(val value: Int) { | ||
// Key to be used for signing transactions. | ||
SignTransaction(1238), | ||
// Key to be used for signing authentication. | ||
SignAuth(706) | ||
} |
11 changes: 11 additions & 0 deletions
11
src/main/kotlin/com/radixdlt/derivation/model/NetworkId.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.radixdlt.derivation.model | ||
|
||
/** | ||
* 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), | ||
Adapanet(10), | ||
Enkinet(33) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
src/test/kotlin/com/radixdlt/derivation/AccountHDDerivationPathTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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.Adapanet, | ||
accountIndex = 0, | ||
keyType = KeyType.SignAuth | ||
) | ||
|
||
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.Adapanet, | ||
accountIndex = 1, | ||
keyType = KeyType.SignAuth | ||
) | ||
|
||
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.Adapanet, | ||
accountIndex = 1, | ||
keyType = KeyType.SignTransaction | ||
) | ||
|
||
assertEquals(accountHDDerivationPath.path, "m/44'/1022'/10'/525'/1'/1238'") | ||
} | ||
} |
85 changes: 85 additions & 0 deletions
85
src/test/kotlin/com/radixdlt/derivation/CustomHDDerivationPathTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
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 | ||
|
||
class CustomHDDerivationPathTest { | ||
|
||
@Test | ||
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 | ||
), | ||
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 invalid custom derivation path without radix coin`() { | ||
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 | ||
) | ||
assertThrows(IllegalArgumentException::class.java) { | ||
customHDDerivationPath.path | ||
} | ||
} | ||
|
||
@Test | ||
fun `verify empty custom derivation path for no bip44 elements`() { | ||
val bip44 = BIP44( | ||
path = emptyList() | ||
) | ||
val customHDDerivationPath = CustomHDDerivationPath( | ||
bip44 = bip44 | ||
) | ||
|
||
assertThrows(IllegalArgumentException::class.java) { | ||
customHDDerivationPath.path | ||
} | ||
} | ||
} |
53 changes: 53 additions & 0 deletions
53
src/test/kotlin/com/radixdlt/derivation/IdentityHDDerivationPathTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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.Adapanet, | ||
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'") | ||
} | ||
} |