[#1924] Add Android shielded-voting JNI foundation, round lifecycle, and delegation prep + signing#7
Closed
greg0x wants to merge 5 commits into
Closed
Conversation
2df5f27 to
42e5920
Compare
42e5920 to
4c72265
Compare
7171d4a to
f0106ae
Compare
greg0x
added a commit
that referenced
this pull request
May 11, 2026
Addresses PR zcash#1938 review comment #7.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of zodl-inc/zodl-android#2193.
Slice of zcash#1924.
Why
Land the Android-side JNI surface needed before delegation proof generation. Pulls the Rust backend onto the released
zcash_votingdependency, adds the voting DB handle and round lifecycle, and exposes the prep + signing surface: bundle setup, hotkey derivation, governance PCZT construction, sighash extraction, and spend-auth signature extraction.Vertical slice — every new JNI symbol gets a matching Rust handler, Kotlin
external fun, FFI model, and typesafe wrapper. Surface is entirelyinternal; no publicSynchronizerAPI yet.What's in
Dependencies —
orchardhard-pinned to=0.13.1withunstable-voting-circuits;zcash_voting 0.5.3withdefault-features = false(no PIR / tree-sync / networking pulled in).JNI (
backend-lib/src/main/rust/voting/)db.rsrounds.rsinitRound,getRoundState,listRounds,getBundleCount,getVotes,clearRound,deleteSkippedBundlesnotes.rscomputeBundleSetup,setupBundles,generateHotkeydelegation.rsbuildGovernancePcztJson,extractPcztSighash,extractSpendAuthSigshare_tracking.rscomputeShareNullifierutil.rswarmProvingCacheshelpers.rsjson.rsJsonNoteInfo, trimmedJsonGovernancePcztenvelope, hex enc/dec,json_from_jstringKotlin (
sdk-lib/.../internal/)jni/VotingRustBackend.kt—external fundeclarations; nestedVotingDbhandle guards every native call behind aMutexand dispatches onSdkDispatchers.DATABASE_IO.TypesafeVotingBackend.kt+Impl—suspendwrappers,native { … }helper that callsRustBackend.loadLibrary()before every dispatched block (idempotent; matchesRustDerivationTool/RustEip681Tool/TorClient), JSON →GovernancePcztResultparsing.model/voting/FfiVotingModels.kt—FfiRoundState,FfiRoundSummary,FfiBundleSetupResult,FfiVotingHotkey,HotkeySecretKey,HotkeyPublicKey(all with size-validated constructors).jni/JniConstants.kt— hotkey key size constants.ext/BlockExt.kt—String.fromHex()made strict (rejects odd length and non-hex characters) since it's now on the JNI parse path.Not in scope
Synchronizervoting APIReview focus
default-features = falseonzcash_votingare deliberate; see comment block inbackend-lib/Cargo.toml.pczt_bytes/rk/action_index/pczt_sighashcross JNI. The rest of the delegation-data fields (alpha,rseed_*,padded_note_secrets,gov_nullifiers, …) are persisted byzcash_voting'sstore_delegation_dataand read back in the proof-generation slice.java_bytes,java_bytes_at_least,java_bytes32, fixed-widthrequire_len/require_min_len, andu32_to_jint/u64_to_jlong/usize_to_jintcast helpers.setupBundlesparity check — chunker output is recomputed in Rust and compared againstdb.setup_bundles; on mismatch the JNI returnsErr. The DB write has already happened at that point, so callers should treat the mismatch as a bug rather than a recoverable error.hotkey_orchard_raw_address_from_wallet_seedderives the Orchard raw address from the wallet seed at the suppliedaccount_index, usingScope::Externalat index 0.VotingDbhandle —Mutex-guarded native calls,close()nulls the handle,withHandleerrors on use-after-close.Validation
cargo check --manifest-path backend-lib/Cargo.toml --lockedcargo fmt --manifest-path backend-lib/Cargo.toml --check./gradlew :backend-lib:compileReleaseKotlin :sdk-lib:compileReleaseKotlin./gradlew ktlint detektAll./gradlew checkPropertiesgit diff --check