From defc917dbcd2cf0f2879da642b537a09a19a6df4 Mon Sep 17 00:00:00 2001 From: dpad85 <5765435+dpad85@users.noreply.github.com> Date: Thu, 24 Mar 2022 17:29:19 +0100 Subject: [PATCH] Add support for kmp node key generation This is needed for the migration to kmp --- .../main/scala/fr/acinq/eclair/crypto/KeyManager.scala | 2 ++ .../scala/fr/acinq/eclair/crypto/LocalKeyManager.scala | 9 +++++++++ .../fr/acinq/eclair/crypto/LocalKeyManagerSpec.scala | 10 +++++++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/crypto/KeyManager.scala b/eclair-core/src/main/scala/fr/acinq/eclair/crypto/KeyManager.scala index d25c5c1e9..443508444 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/crypto/KeyManager.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/crypto/KeyManager.scala @@ -31,6 +31,8 @@ trait KeyManager { def nodeId: PublicKey + def kmpNodeKey: DeterministicWallet.ExtendedPrivateKey + def fundingPublicKey(keyPath: DeterministicWallet.KeyPath): ExtendedPublicKey def revocationPoint(channelKeyPath: DeterministicWallet.KeyPath): ExtendedPublicKey diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/crypto/LocalKeyManager.scala b/eclair-core/src/main/scala/fr/acinq/eclair/crypto/LocalKeyManager.scala index 0de36c9dc..ae2b27a05 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/crypto/LocalKeyManager.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/crypto/LocalKeyManager.scala @@ -40,6 +40,14 @@ object LocalKeyManager { case Block.RegtestGenesisBlock.hash | Block.TestnetGenesisBlock.hash => DeterministicWallet.hardened(46) :: DeterministicWallet.hardened(0) :: Nil case Block.LivenetGenesisBlock.hash => DeterministicWallet.hardened(47) :: DeterministicWallet.hardened(0) :: Nil } + + // WARNING: if you change this path, you will change your node id even if the seed remains the same!!! + // Note that the node path and the above channel path are on different branches so even if the + // node key is compromised there is no way to retrieve the wallet keys + def kmpNodeKeyBasePath(chainHash: ByteVector32) = (chainHash: @unchecked) match { + case Block.RegtestGenesisBlock.hash | Block.TestnetGenesisBlock.hash => DeterministicWallet.hardened(48) :: DeterministicWallet.hardened(0) :: Nil + case Block.LivenetGenesisBlock.hash => DeterministicWallet.hardened(50) :: DeterministicWallet.hardened(0) :: Nil + } } /** @@ -53,6 +61,7 @@ class LocalKeyManager(seed: ByteVector, chainHash: ByteVector32) extends KeyMana override val nodeKey = DeterministicWallet.derivePrivateKey(master, LocalKeyManager.nodeKeyBasePath(chainHash)) override val nodeId = nodeKey.publicKey + override val kmpNodeKey = DeterministicWallet.derivePrivateKey(master, LocalKeyManager.kmpNodeKeyBasePath(chainHash)) private val privateKeys: LoadingCache[KeyPath, ExtendedPrivateKey] = CacheBuilder.newBuilder() .maximumSize(6 * 200) // 6 keys per channel * 200 channels diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/crypto/LocalKeyManagerSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/crypto/LocalKeyManagerSpec.scala index 5f477273d..eb39704c9 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/crypto/LocalKeyManagerSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/crypto/LocalKeyManagerSpec.scala @@ -18,7 +18,7 @@ package fr.acinq.eclair.crypto import fr.acinq.bitcoin.scala.Crypto.{PrivateKey, PublicKey} import fr.acinq.bitcoin.scala.DeterministicWallet.KeyPath -import fr.acinq.bitcoin.scala.{Block, ByteVector32, DeterministicWallet} +import fr.acinq.bitcoin.scala.{Block, ByteVector32, DeterministicWallet, MnemonicCode} import fr.acinq.eclair.TestConstants import fr.acinq.eclair.channel.ChannelVersion import org.scalatest.funsuite.AnyFunSuite @@ -34,6 +34,14 @@ class LocalKeyManagerSpec extends AnyFunSuite { assert(keyManager.nodeId == PublicKey(hex"02a051267759c3a149e3e72372f4e0c4054ba597ebfd0eda78a2273023667205ee")) } + test("generate the same KMP node id from the same seed") { + // if this test breaks it means that we will generate a different KMP node id from + // the same seed, which could be a problem during migration from eclair-core to kmp + val seed = MnemonicCode.toSeed("sock able evoke work output half bamboo energy simple fiber unhappy afford", passphrase = "") + val keyManager = new LocalKeyManager(seed, Block.TestnetGenesisBlock.hash) + assert(keyManager.kmpNodeKey.publicKey == PublicKey(hex"022b49d4ab3342ada31d79d2a57ceaa2e8f573277552a44433bc8a4ee5b945085d")) + } + test("generate the same secrets from the same seed") { // data was generated with eclair 0.3 val seed = hex"17b086b228025fa8f4416324b6ba2ec36e68570ae2fc3d392520969f2a9d0c1501"