From eee8fa0fd8ff8fd205863b2db6239efc0b5faaf6 Mon Sep 17 00:00:00 2001 From: Kgothatso Ngako Date: Fri, 4 Sep 2026 23:25:23 +0200 Subject: [PATCH] build: package the android secp256k1 natives, with ChillDKG in them The android app had no android secp256k1 natives at all, and had not had any for as long as lightning-kmp-core has been a dependency. `dependencyInsight` on debugRuntimeClasspath resolved every secp256k1 coordinate to `:secp256k1-kmp:jni:jvm:{darwin,linux,mingw}` -- desktop .so/.dylib/.dll files, loaded by extracting them from a jar, which cannot work on a device. The cause is a chain of individually reasonable decisions. lightning-kmp-core publishes no android variant, so an android consumer resolves it to the jvm one; the jvm variant asks for `secp256k1-kmp-jni-jvm`; and nothing anywhere asks for `secp256k1-kmp-jni-android`. lightning-kmp-app names it only in androidDeviceTest, so consumers of the published library do not get it. It has to be named here. Naming it alone would not have been enough. bitcoin-kmp's settings.gradle.kts substituted five of secp256k1-kmp's coordinates to the fork's projects but not -jni-android, so it would have resolved from Maven Central to stock 0.24.0 -- built from upstream libsecp256k1, with no ChillDKG module. Because the kotlin API comes from the substituted root project, that combination type-checks and links and then fails with UnsatisfiedLinkError at the first native call. The rule is added in the submodule commits this carries. Submodule commits carried here: lightning-kmp-app ce1ed01 -> 6434282 build: carry the jni-android substitution down from bitcoin-kmp experimental/lightning-kmp 77be7b78 -> 5103b79e experimental/bitcoin-kmp 196a479 -> 65c4aab build: substitute secp256k1-kmp-jni-android to the included build too Verified through the artifact rather than the graph: composeApp-debug.apk now carries lib/{arm64-v8a,armeabi-v7a,x86,x86_64}/libsecp256k1-jni.so, and `nm -D` on the arm64 one exports all twelve Java_..._chilldkg_... JNI entry points -- hostpubkey_gen, params_hash, participant_step1/step2/finalize, coordinator_step1/finalize, and the recover and investigate calls. The three builds in the chain sit on `build/substitute-jni-android` branches (lightning-kmp-app on `build/agp-9.4.0`, which now carries two commits) and none are pushed, so a fresh clone cannot resolve these pointers yet. Co-Authored-By: Claude Opus 5 --- composeApp/build.gradle.kts | 12 ++++++++++++ lightning-kmp-app | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index bb8eed65..4bb5f8f2 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -47,6 +47,18 @@ kotlin { sourceSets { androidMain.dependencies { + // The android secp256k1 natives. Nothing pulls these in transitively: lightning-kmp-core + // publishes no android variant, so the android target resolves it to the jvm one, which + // asks for secp256k1-kmp-jni-jvm and gets desktop .so/.dylib/.dll files that cannot load + // on a device. The app has to name the android artifact itself. + // + // Resolved from source via the composite build, not from Maven Central -- bitcoin-kmp's + // settings.gradle.kts substitutes this coordinate for secp256k1-kmp's :jni:android. That + // matters: the stock artifact has no ChillDKG module, so ChillDKG would compile and then + // fail with UnsatisfiedLinkError. The version is never resolved; substitution matches on + // group:name. + implementation("fr.acinq.secp256k1:secp256k1-kmp-jni-android:0.24.0") + implementation(libs.androidx.activity.compose) implementation(libs.androidx.work.runtime.ktx) // implementation(libs.androidx.room.sqlite.wrapper) diff --git a/lightning-kmp-app b/lightning-kmp-app index ce1ed010..64342823 160000 --- a/lightning-kmp-app +++ b/lightning-kmp-app @@ -1 +1 @@ -Subproject commit ce1ed010339bfe9b3073b0b0c84b7ccd6954fe79 +Subproject commit 6434282380a14a997a2ac91227bb4d787a6f2c76