meherett / python-hdwallet

Python-based library for the implementation of a hierarchical deterministic wallet generator for more than 140+ multiple cryptocurrencies.
https://hdwallet.readthedocs.io
MIT License
445 stars 148 forks source link

Generate a linkingKey followed by LN concept #94

Open jjhesk opened 6 months ago

jjhesk commented 6 months ago

linkingKey derivation

linkingKey derivation for BIP-32 based wallets:

There exists a private hashingKey which is derived by user LN WALLET using m/138'/0 path. LN SERVICE full domain name is extracted from login LNURL and then hashed using hmacSha256(hashingKey, full service domain name). Full domain name here means FQDN with last full-stop (aka "point") omitted (Example: for https://x.y.z.com/... it would be x.y.z.com). First 16 bytes are taken from resulting hash and then turned into a sequence of 4 Long values which are in turn used to derive a service-specific linkingKey using m/138'/<long1>/<long2>/<long3>/<long4> path, a Scala example:

import fr.acinq.bitcoin.crypto
import fr.acinq.bitcoin.Protocol
import java.io.ByteArrayInputStream
import fr.acinq.bitcoin.DeterministicWallet._
val domainName = "site.com"
val hashingPrivKey = derivePrivateKey(walletMasterKey, hardened(138L) :: 0L :: Nil)
val derivationMaterial = hmac256(key = hashingPrivKey.toBin, message = domainName)
val stream = new ByteArrayInputStream(derivationMaterial.slice(0, 16).toArray)
val pathSuffix = Vector.fill(4)(Protocol.uint32(stream, ByteOrder.BIG_ENDIAN)) // each uint32 call consumes next 4 bytes
val linkingPrivKey = derivePrivateKey(walletMasterKey, hardened(138L) +: pathSuffix)
val linkingPubKey = linkingPrivKey.publicKey
jjhesk commented 6 months ago

found some cool coding block from js


import bech32 from 'bech32';
import bip21 from 'bip21';
import { fromSeed, fromBase58 } from 'bip32';
import bolt11 from 'bolt11';
import validate from 'bitcoin-address-validation';
import { crypto, payments, Psbt } from 'bitcoinjs-lib';
import {
  crypto as lqcrypto,
  ECPair,
  payments as lqpayments,
  Psbt as lqPsbt,
} from 'liquidjs-lib';

import { generateMnemonic, mnemonicToSeedSync } from 'bip39';
import cryptojs from 'crypto-js';
import sha256, { HMAC } from 'fast-sha256';
import secp256k1 from 'secp256k1';
import { validate as isUuid, v4 } from 'uuid';
import { fromSeed as slip77FromSeed } from 'slip77';

....

const linkingKey = (domain, seed) => {
  const root = fromSeed(mnemonicToSeedSync(seed));
  const hashingKey = root.derivePath("m/138'/0");
  const hmac = new HMAC(hashingKey.privateKey);
  const derivationMaterial = hmac.update(stringToUint8Array(domain)).digest();
  const first4 = derivationMaterial.slice(0, 4);
  return root.derivePath(
    `m/138'/${first4[0]}/${first4[1]}/${first4[2]}/${first4[3]}`
  );
};
...

 const key = linkingKey(params.domain, seed);
                const signedMessage = secp256k1.ecdsaSign(
                  hexToUint8Array(params.k1),
                  key.privateKey
                );
                const signedMessageDER = secp256k1.signatureExport(
                  signedMessage.signature
                );
                const linkingKeyPub = secp256k1.publicKeyCreate(
                  key.privateKey,
                  true
                );
                const sig = bytesToHexString(signedMessageDER);

anyone can make that into python with this library?