A new `:obfs4` module, a plain JVM library like `:engine` so its tests run without an emulator -- which matters here because the only tests that mean anything are vector comparisons against lyrebird. Far smaller than the Swift port, for a reason worth recording: the Swift implementation hand-writes SipHash-2-4, XSalsa20, Poly1305 and its own field arithmetic because CryptoKit exposes none of them. The JVM does not have that hole. BouncyCastle -- already a dependency of :engine, for the same class of reason -- has X25519Field, XSalsa20Engine, Poly1305 and SipHash, vetted and constant-time where it matters. So the two clients do NOT share an implementation. They share the vectors and the live interop harness, which is what actually keeps them honest: two independent implementations agreeing with the same reference is a stronger statement than one agreeing with itself twice. Two things BouncyCastle would not do, both found by vectors rather than by reading. X25519Field.sqrtRatioVar is not a drop-in. Elligator needs the root even when the ratio is NOT square -- it is sqrt(i*u/v) then, and the algorithm uses it to pick a branch rather than to detect an error. BC only promises a usable root in the square case, and handing its output to the map produced zeros for 120 of 256 vectors. The exponent chain and branch selection are written out here; the field arithmetic underneath is still BouncyCastle's. X25519Field.cmov did nothing at all with a condition of 1. Both tweak parities produced the SAME representative -- a map that still round-trips, still looks uniform, and only ever emits one of the two valid answers. The failing assertion said "wrong bytes"; it took a diagnostic printing both candidates to see they were identical. Replaced with an explicit mask so the convention is stated rather than assumed. Behind no setting yet because nothing calls it: this is the crypto foundation only. The transport, the OkHttp socket factory and the user-facing switch come next, and the switch defaults to off. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
42 lines
1.3 KiB
Kotlin
42 lines
1.3 KiB
Kotlin
pluginManagement {
|
|
repositories {
|
|
google()
|
|
mavenCentral()
|
|
gradlePluginPortal()
|
|
}
|
|
}
|
|
|
|
dependencyResolutionManagement {
|
|
repositories {
|
|
google()
|
|
mavenCentral()
|
|
}
|
|
}
|
|
|
|
// Flamenet Messenger — Android.
|
|
//
|
|
// `engine` is deliberately a plain Kotlin/JVM library, not an Android library:
|
|
// the protocol has nothing to do with Android, and keeping it off the platform
|
|
// means its tests run on any machine and in CI on Linux, with no emulator and
|
|
// no SDK. The app module, when it exists, will depend on this.
|
|
rootProject.name = "flamenet-android"
|
|
|
|
include(":engine")
|
|
|
|
// The relay transport: HTTP, auth, and the §8 routes.
|
|
include(":client")
|
|
|
|
// The Compose app. Everything below it -- the protocol and the transport --
|
|
// lives in `:engine` and `:client`, which are plain JVM libraries so they can
|
|
// be tested without an emulator.
|
|
include(":app")
|
|
|
|
// The obfs4 pluggable transport, for reaching a relay on a network that blocks
|
|
// or fingerprints TLS to it. A plain JVM library like `:engine`, so its tests
|
|
// run without an emulator -- which matters here because the only tests that
|
|
// mean anything are vector comparisons against the reference implementation.
|
|
include(":obfs4")
|
|
|
|
// The cross-engine interop driver. Not shipped; see `engine/test/interop-kotlin.mjs`.
|
|
include(":interop")
|