author: akumaigorodski
- There exists a private
hashingKey
which is derived by userLN WALLET
usingm/138'/0
path. LN SERVICE
full domain name is extracted from loginLNURL
and then hashed usinghmacSha256(hashingKey, full service domain name)
. Full domain name here means FQDN with last comma omitted (Example: forhttps://x.y.z.com/...
it would bex.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-specificlinkingKey
usingm/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
domain name: site.com
hashingPrivKey: 0x7d417a6a5e9a6a4a879aeaba11a11838764c8fa2b959c242d43dea682b3e409b01
pathSuffix: Vector(3751473387, 2829804099, 4228872783, 4134047485)