@@ -17,11 +17,8 @@ import kotlinx.serialization.Serializable
1717import kotlinx.serialization.json.Json
1818import kotlinx.serialization.json.buildJsonObject
1919import kotlinx.serialization.json.put
20- import org.bouncycastle.crypto.digests.SHA512Digest
21- import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator
22- import org.bouncycastle.crypto.params.KeyParameter
23- import org.ldk.structs.KeysManager
2420import org.lightningdevkit.ldknode.Network
21+ import org.lightningdevkit.ldknode.deriveNodeSecretFromMnemonic
2522import to.bitkit.data.keychain.Keychain
2623import to.bitkit.di.IoDispatcher
2724import to.bitkit.di.json
@@ -275,44 +272,11 @@ class RNBackupClient @Inject constructor(
275272 return crypto.sign(fullMessage, privateKey)
276273 }
277274
278- private fun deriveSigningKey (mnemonic : String , passphrase : String? ): ByteArray {
279- val bip39Seed = deriveSeed(mnemonic, passphrase)
280- val bip32Seed = deriveMasterKey(bip39Seed)
281- val seconds = System .currentTimeMillis() / 1000L
282- val nanoSeconds = ((System .currentTimeMillis() % 1000 ) * 1_000_000 ).toInt()
283-
284- return runCatching {
285- val keysManager = KeysManager .of(bip32Seed, seconds, nanoSeconds)
286- val method = keysManager.javaClass.getMethod(" get_node_secret_key" )
287- when (val nodeSecretKey = method.invoke(keysManager)) {
288- is ByteArray -> nodeSecretKey
289- is List <* > -> nodeSecretKey.map { (it as UByte ).toByte() }.toByteArray()
290- else -> throw ClassCastException (" Unexpected type: ${nodeSecretKey?.javaClass?.name} " )
291- }
292- }.getOrElse { bip32Seed }
293- }
294-
295- private fun deriveEncryptionKey (mnemonic : String , passphrase : String? ): ByteArray {
296- // Match iOS: use the same node secret key as signing key for encryption
297- // iOS uses SymmetricKey(data: secretKey) where secretKey is the node secret key
298- return deriveSigningKey(mnemonic, passphrase)
299- }
275+ private fun deriveSigningKey (mnemonic : String , passphrase : String? ): ByteArray =
276+ deriveNodeSecretFromMnemonic(mnemonic, passphrase).map { it.toByte() }.toByteArray()
300277
301- private fun deriveSeed (mnemonic : String , passphrase : String? ): ByteArray {
302- val mnemonicBytes = mnemonic.toByteArray(Charsets .UTF_8 )
303- val salt = (" mnemonic" + (passphrase ? : " " )).toByteArray(Charsets .UTF_8 )
304- val generator = PKCS5S2ParametersGenerator (SHA512Digest ())
305- generator.init (mnemonicBytes, salt, 2048 )
306- return (generator.generateDerivedParameters(512 ) as KeyParameter ).key
307- }
308-
309- private fun deriveMasterKey (seed : ByteArray ): ByteArray {
310- val hmac = javax.crypto.Mac .getInstance(" HmacSHA512" )
311- val keySpec = javax.crypto.spec.SecretKeySpec (" Bitcoin seed" .toByteArray(), " HmacSHA512" )
312- hmac.init (keySpec)
313- val i = hmac.doFinal(seed)
314- return i.sliceArray(0 until 32 )
315- }
278+ private fun deriveEncryptionKey (mnemonic : String , passphrase : String? ): ByteArray =
279+ deriveSigningKey(mnemonic, passphrase)
316280
317281 private fun decrypt (blob : ByteArray , encryptionKey : ByteArray ): ByteArray {
318282 if (blob.size < GCM_IV_LENGTH + GCM_TAG_LENGTH ) {
0 commit comments