Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate a linkingKey followed by LN concept #94

Open
jjhesk opened this issue Dec 16, 2023 · 1 comment
Open

Generate a linkingKey followed by LN concept #94

jjhesk opened this issue Dec 16, 2023 · 1 comment

Comments

@jjhesk
Copy link

jjhesk commented Dec 16, 2023

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
Copy link
Author

jjhesk commented Dec 16, 2023

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?

@jjhesk jjhesk changed the title how to generate a linkingKey followed by this rule Generate a linkingKey followed by LN concept Dec 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant