mirror of
https://github.com/ACINQ/eclair.git
synced 2025-03-12 19:01:39 +01:00
Derive per-user swap-in keys
We derive keys based on the server xpub and our node ID.
This commit is contained in:
parent
98d588ab03
commit
72f0993a31
2 changed files with 27 additions and 10 deletions
|
@ -25,6 +25,7 @@ import fr.acinq.eclair.transactions.Transactions
|
|||
import fr.acinq.eclair.transactions.Transactions.TransactionWithInputInfo
|
||||
import fr.acinq.eclair.{Features, ShortChannelId, secureRandom}
|
||||
import scodec.bits.ByteVector
|
||||
import scodec.codecs.uint16
|
||||
|
||||
object LocalKeyManager {
|
||||
def channelKeyBasePath(chainHash: ByteVector32) = (chainHash: @unchecked) match {
|
||||
|
@ -158,7 +159,8 @@ class LocalKeyManager(seed: ByteVector, chainHash: ByteVector32) extends KeyMana
|
|||
Announcements.signChannelAnnouncement(chainHash, shortChannelId, localNodeSecret, remoteNodeId, localFundingPrivKey, remoteFundingKey, features)
|
||||
}
|
||||
|
||||
def multisigSwapInAddress(serverPublicKey: Crypto.PublicKey, refundDelay: Int): String = {
|
||||
def multisigSwapInAddress(localNodeId: PublicKey, serverExtendedPublicKey: String, refundDelay: Int): String = {
|
||||
val serverPublicKey = deriveSwapInServerPublicKey(localNodeId, serverExtendedPublicKey)
|
||||
val userKeyPath = chainHash match {
|
||||
case Block.RegtestGenesisBlock.hash | Block.TestnetGenesisBlock.hash =>
|
||||
DeterministicWallet.hardened(51) :: DeterministicWallet.hardened(0) :: DeterministicWallet.hardened(0) :: Nil
|
||||
|
@ -179,4 +181,11 @@ class LocalKeyManager(seed: ByteVector, chainHash: ByteVector32) extends KeyMana
|
|||
val address = Bech32.encodeWitnessAddress(hrp, 0, witnessScript)
|
||||
address
|
||||
}
|
||||
|
||||
private def deriveSwapInServerPublicKey(localNodeId: PublicKey, serverExtendedPublicKey: String): PublicKey = {
|
||||
val (_, xpub) = DeterministicWallet.ExtendedPublicKey.decode(serverExtendedPublicKey)
|
||||
val h = Crypto.sha256(localNodeId.value)
|
||||
val path = h.bits.grouped(16).toSeq.map(uint16.decode(_).require.value.toLong)
|
||||
DeterministicWallet.derivePublicKey(xpub, path).publicKey
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ class LocalKeyManagerSpec extends AnyFunSuite {
|
|||
}
|
||||
|
||||
def makefundingKeyPath(entropy: ByteVector, isFunder: Boolean) = {
|
||||
val items = for(i <- 0 to 7) yield entropy.drop(i * 4).take(4).toInt(signed = false) & 0xFFFFFFFFL
|
||||
val items = for (i <- 0 to 7) yield entropy.drop(i * 4).take(4).toInt(signed = false) & 0xFFFFFFFFL
|
||||
val last = DeterministicWallet.hardened(if (isFunder) 1L else 0L)
|
||||
KeyPath(items :+ last)
|
||||
}
|
||||
|
@ -151,14 +151,22 @@ class LocalKeyManagerSpec extends AnyFunSuite {
|
|||
}
|
||||
|
||||
test("generate multisig swap-in address") {
|
||||
val entropy = ByteVector32.fromValidHex("0101010101010101010101010101010101010101010101010101010101010101")
|
||||
val seed = MnemonicCode.toSeed(MnemonicCode.toMnemonics(entropy), "").take(32)
|
||||
val keyManager = new LocalKeyManager(seed, Block.RegtestGenesisBlock.hash)
|
||||
|
||||
val serverPublicKey = PublicKey(ByteVector.fromValidHex("02cd0e2ed9c42af42e0b30e2a0b339c8335bbdc1f895fe552d8e224aedc82d6c88"))
|
||||
val aliceKeyManager = {
|
||||
val entropy = ByteVector32.fromValidHex("0101010101010101010101010101010101010101010101010101010101010101")
|
||||
val seed = MnemonicCode.toSeed(MnemonicCode.toMnemonics(entropy), "").take(32)
|
||||
new LocalKeyManager(seed, Block.RegtestGenesisBlock.hash)
|
||||
}
|
||||
val bobKeyManager = {
|
||||
val entropy = ByteVector32.fromValidHex("0202020202020202020202020202020202020202020202020202020202020202")
|
||||
val seed = MnemonicCode.toSeed(MnemonicCode.toMnemonics(entropy), "").take(32)
|
||||
new LocalKeyManager(seed, Block.RegtestGenesisBlock.hash)
|
||||
}
|
||||
val swapInRefundDelay = 144 * 30 * 6
|
||||
val swapInAddress = keyManager.multisigSwapInAddress(serverPublicKey, swapInRefundDelay)
|
||||
|
||||
assert(swapInAddress == "bcrt1qvwc4zcelvlj3pcy97pj09dz2hgq0ptav25nrjm54dt3ch09plxnq6pmjje")
|
||||
val bobSwapInServerXpub = "tpubDDt5vQap1awkyDXx1z1cP7QFKSZHDCCpbU8nSq9jy7X2grTjUVZDePexf6gc6AHtRRzkgfPW87K6EKUVV6t3Hu2hg7YkHkmMeLSfrP85x41"
|
||||
val swapInAddressAlice = aliceKeyManager.multisigSwapInAddress(aliceKeyManager.kmpNodeKey.publicKey, bobSwapInServerXpub, swapInRefundDelay)
|
||||
assert(swapInAddressAlice == "bcrt1qw78cdcsn55vwsvmwe9qgwnx0fwffzqej7keuqfjnwj5xm0f5u6js2hp66f")
|
||||
val aliceSwapInServerXpub = "tpubDCvYeHUZisCMVTSfWDa1yevTf89NeF6TWxXUQwqkcmFrNvNdNvZQh1j4m4uTA4QcmPEwcrKVF8bJih1v16zDZacRr4j9MCAFQoSydKKy66q"
|
||||
val swapInAddressBob = bobKeyManager.multisigSwapInAddress(bobKeyManager.kmpNodeKey.publicKey, aliceSwapInServerXpub, swapInRefundDelay)
|
||||
assert(swapInAddressBob == "bcrt1qjs2l2ey9rk742hvv25kjghqvqdyhvf7vshwesgflzch9kcq2c8lqh60h44")
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue