All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fr.acinq.eclair.crypto.KeyManager.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2019 ACINQ SAS
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package fr.acinq.eclair.crypto

import java.io.ByteArrayInputStream
import java.nio.ByteOrder

import fr.acinq.bitcoin.Crypto.{PrivateKey, PublicKey}
import fr.acinq.bitcoin.DeterministicWallet.ExtendedPublicKey
import fr.acinq.bitcoin.{ByteVector32, ByteVector64, Crypto, DeterministicWallet, Protocol}
import fr.acinq.eclair.ShortChannelId
import fr.acinq.eclair.channel.{ChannelVersion, LocalParams}
import fr.acinq.eclair.transactions.Transactions.TransactionWithInputInfo
import scodec.bits.ByteVector

trait KeyManager {
  def nodeKey: DeterministicWallet.ExtendedPrivateKey

  def nodeId: PublicKey

  def fundingPublicKey(keyPath: DeterministicWallet.KeyPath): ExtendedPublicKey

  def revocationPoint(channelKeyPath: DeterministicWallet.KeyPath): ExtendedPublicKey

  def paymentPoint(channelKeyPath: DeterministicWallet.KeyPath): ExtendedPublicKey

  def delayedPaymentPoint(channelKeyPath: DeterministicWallet.KeyPath): ExtendedPublicKey

  def htlcPoint(channelKeyPath: DeterministicWallet.KeyPath): ExtendedPublicKey

  def commitmentSecret(channelKeyPath: DeterministicWallet.KeyPath, index: Long): Crypto.PrivateKey

  def commitmentPoint(channelKeyPath: DeterministicWallet.KeyPath, index: Long): Crypto.PublicKey

  def channelKeyPath(localParams: LocalParams, channelVersion: ChannelVersion): DeterministicWallet.KeyPath = if (channelVersion.isSet(ChannelVersion.USE_PUBKEY_KEYPATH_BIT)) {
    // deterministic mode: use the funding pubkey to compute the channel key path
    KeyManager.channelKeyPath(fundingPublicKey(localParams.fundingKeyPath))
  } else {
    // legacy mode:  we reuse the funding key path as our channel key path
    localParams.fundingKeyPath
  }

  /**
   *
   * @param isFunder true if we're funding this channel
   * @return a partial key path for a new funding public key. This key path will be extended:
   *         - with a specific "chain" prefix
   *         - with a specific "funding pubkey" suffix
   */
  def newFundingKeyPath(isFunder: Boolean) : DeterministicWallet.KeyPath

  /**
    *
    * @param tx        input transaction
    * @param publicKey extended public key
    * @return a signature generated with the private key that matches the input
    *         extended public key
    */
  def sign(tx: TransactionWithInputInfo, publicKey: ExtendedPublicKey): ByteVector64

  /**
    * This method is used to spend funds send to htlc keys/delayed keys
    *
    * @param tx          input transaction
    * @param publicKey   extended public key
    * @param remotePoint remote point
    * @return a signature generated with a private key generated from the input keys's matching
    *         private key and the remote point.
    */
  def sign(tx: TransactionWithInputInfo, publicKey: ExtendedPublicKey, remotePoint: PublicKey): ByteVector64

  /**
    * Ths method is used to spend revoked transactions, with the corresponding revocation key
    *
    * @param tx           input transaction
    * @param publicKey    extended public key
    * @param remoteSecret remote secret
    * @return a signature generated with a private key generated from the input keys's matching
    *         private key and the remote secret.
    */
  def sign(tx: TransactionWithInputInfo, publicKey: ExtendedPublicKey, remoteSecret: PrivateKey): ByteVector64

  /**
    * Sign a channel announcement message
    *
    * @param fundingKeyPath BIP32 path of the funding public key
    * @param chainHash chain hash
    * @param shortChannelId short channel id
    * @param remoteNodeId remote node id
    * @param remoteFundingKey remote funding pubkey
    * @param features channel features
    * @return a (nodeSig, bitcoinSig) pair. nodeSig is the signature of the channel announcement with our node's
    *         private key, bitcoinSig is the signature of the channel announcement with our funding private key
    */
  def signChannelAnnouncement(fundingKeyPath: DeterministicWallet.KeyPath, chainHash: ByteVector32, shortChannelId: ShortChannelId, remoteNodeId: PublicKey, remoteFundingKey: PublicKey, features: ByteVector): (ByteVector64, ByteVector64)
}

object KeyManager {
  /**
    * Create a BIP32 path from a public key. This path will be used to derive channel keys. 
    * Having channel keys derived from the funding public keys makes it very easy to retrieve your funds when've you've lost your data:
    * - connect to your peer and use DLP to get them to publish their remote commit tx
    * - retrieve the commit tx from the bitcoin network, extract your funding pubkey from its witness data
    * - recompute your channel keys and spend your output  
    *
    * @param fundingPubKey funding public key
    * @return a BIP32 path
    */
  def channelKeyPath(fundingPubKey: PublicKey) : DeterministicWallet.KeyPath = {
    val buffer = Crypto.sha256(fundingPubKey.value)
    val bis = new ByteArrayInputStream(buffer.toArray)
    def next() = Protocol.uint32(bis, ByteOrder.BIG_ENDIAN)
    DeterministicWallet.KeyPath(Seq(next(), next(), next(), next(), next(), next(), next(), next()))
  }

  def channelKeyPath(fundingPubKey: DeterministicWallet.ExtendedPublicKey) : DeterministicWallet.KeyPath = channelKeyPath(fundingPubKey.publicKey)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy