¿Cómo recuperar fondos de un canal de rayos Lnd cerrado a la fuerza?

Perdí la copia de seguridad de mi canal Lnd en un accidente de navegación, pero todavía tengo el mnemotécnico. Tenía un canal recién abierto a mi propio nodo c-lightning que nunca se ha utilizado. Forcé el cierre del canal desde el lado c-relámpago.

Los fondos ahora están en una dirección P2WPKH que he importado a Bitcoin Core. Ahora necesito averiguar la clave privada para barrerla. Esto requiere saber cómo derivarlo y luego cómo volcarlo.

Hay una solicitud de extracción de la utilidad de billetera que podría modificar para descargar la clave que necesito una vez que sepa cómo obtenerla.

También sé la identificación de la transacción de financiación, la identificación del canal y todos los demás detalles del canal que c-lightning escupe listfunds.

La derivación de claves se explica en derivation.go :

m/1017'/coinType'/keyFamily'/0/index

El tipo de moneda para Bitcoin es 0, y creo que la familia de claves es 3: "usado en scripts que nos pagan directamente sin demora"

Supongo que el índice es 0 ya que fue el primer canal.

BOLT 3 luego explica cómo modificar esta clave para una transacción de compromiso. Debido a que el otro lado cerró este canal, necesito la to_remotesalida, que requiere el archivo remotepubkey.

pubkey = basepoint + SHA256(per_commitment_point || basepoint) * G 
privkey = basepoint_secret + SHA256(per_commitment_point || basepoint)

La especificación dice "remotepubkey usa el punto base de pago del nodo remoto". ¿Es esa la clave que acabamos de derivar?

Entonces eso deja el per_commitment_pointpor resolver, derivado de per_commitment_secret. Estoy confundido de dónde viene eso.

¿Qué conjuro Go debo usar para volcar la clave privada que estoy buscando?

No puedo darte la respuesta inmediata, pero quería seguir esa lógica desde hace mucho tiempo. si nadie encuentra la respuesta, me ofrecería como voluntario para tener un lugar de reunión (o el servicio que prefiera) para perseguir la derivación de los secretos per_commit de la semilla mnemotécnica.

Respuestas (2)

En c-lightning, el punto por compromiso se deriva del hsm_secretuso de per_commit_point de:

  1. La identificación del nodo / clave pública (se puede encontrar con listfunds, hasta que el canal se elimine algún tiempo después del cierre)
  2. El ID de la base de datos del canal (se puede encontrar con cat ~/.lightning/debug.log | grep $node_id), que se muestra comochan #$node_id
  3. El número de compromiso (0 al abrir el canal, aumenta durante las negociaciones de tarifas y otras actualizaciones del canal | grep commit)

Nos importa el punto de compromiso, no el secreto, porque la clave privada que necesitamos se deriva de la siguiente manera:

privkey = basepoint_secret + SHA256(per_commitment_point || basepoint)

Creé una herramienta para c-lightning para volcar este punto (con la ayuda de @cdecker): https://github.com/ElementsProject/lightning/pull/3115

Volviendo a Lnd... Un lugar fácil para volcar una clave privada es en el lnwallet walletinfocomando. Agregue algo como esto a commands.go:

basePointSecret, err := keyRing.DerivePrivKey(keychain.KeyDescriptor{
  KeyLocator: keychain.KeyLocator{
    Family: keychain.KeyFamilyPaymentBase,
    Index:  0, // Same commitment index as used in c-lightning 
  },
})

// Parse per_commitment_point dumped by c-lightning:
bytes, err := hex.DecodeString(".........")
commitPoint, err := btcec.ParsePubKey(bytes, btcec.S256())

// Obtain SHA256(per_commitment_point || basepoint)
h := sha256.New()
h.Write(commitPoint.SerializeCompressed())
h.Write(basePointSecret.PubKey().SerializeCompressed())
commitTweak := h.Sum(nil)

// Obtain and dump private key
tweakedPrivkey := TweakPrivKey(basePointSecret, commitTweak)
commitmentWif, err := btcutil.NewWIF(tweakedPrivkey, &chaincfg.MainNetParams, true)

fmt.Printf("Dump commitment priv key: %s\n", commitmentWif)

Donde TweakPrivKey() se levanta de script_utils .

Importe la clave privada resultante en Bitcoin Core y ¡listo!

Eso deja el per_commitment_point por descubrir, derivado de per_commitment_secret. Estoy confundido de dónde viene eso.

Esto viene de los open_channel/accept_channelmensajes en BOLT2. se llama first_per_commitment_point.

Desafortunadamente, no puedo encontrar dónde puede acceder a esto en la documentación de lnd.

Una idea: consulte la documentación de copia de seguridad de lnd e intente descubrir cómo funciona. per_commitment_secretdebe tener una copia de seguridad para canjear fondos sin confianza. Dado que parece que no ofrecen un fácil acceso a eso, es posible que pueda encontrarlo en la información de la copia de seguridad.